You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

游戏开发中Dog实例生成性能优化与订阅设计模式应用咨询

优化方案

1. 核心性能问题解决

你遇到的instanceof判断开销本质是「全量遍历+冗余类型判断」导致的,直接从存储结构上拆分即可彻底消除该开销:

  • 狗实例注册类不再仅维护单一全量集合,拆分为两个独立的存储集合:
    • 普通全服可见Dog实例集合
    • 按玩家生成的PerPlayerDog实例集合
  • 注册狗实例时自动根据类型存入对应集合,定时任务不再需要遍历全量狗实例,也不需要做任何类型判断,直接遍历按玩家生成的实例集合即可,性能可以提升数倍。

补充:100次instanceof判断本身的CPU开销极低,你感知到的性能瓶颈大概率还伴随每次循环重复获取狗/玩家位置、反复遍历玩家列表的冗余开销,后续优化可以顺便处理这些问题。

2. 重命名+订阅逻辑的合理性

完全合理。PerPlayerDog仅描述了实现层面的特性,重命名为SubscribedDog后直接匹配业务语义,后续不管是做距离触发的自动订阅,还是玩家主动领养的手动订阅,都不需要再调整接口的定位,扩展性更强。


具体代码优化建议

调整后接口定义

interface Dog {
    String getDogName();
    UUID getUUID();
    DogModel getDogModel();
}

interface SubscribedDog extends Dog {
    // 玩家订阅该狗,重复订阅返回false
    boolean subscribe(Player player);
    // 玩家取消订阅
    boolean unsubscribe(Player player);
    // 替代原getReceipts,语义更清晰
    Iterable<Player> getSubscribers();
    // 原生成逻辑保留
    void spawn(Player player);
    // 内置订阅判断,减少外部重复逻辑
    default boolean isSubscribed(Player player) {
        return getSubscribers().contains(player);
    }
}

注册类优化示例

public class DogRegistry {
    // 全服可见普通狗存储
    private final Set<Dog> globalDogs = ConcurrentHashMap.newKeySet();
    // 订阅制狗存储
    private final Set<SubscribedDog> subscribedDogs = ConcurrentHashMap.newKeySet();
    // 可观测半径平方,避免开根号计算
    private static final double SPAWN_RADIUS_SQUARED = X * X;

    // 注册时自动分类,仅做一次类型判断
    public void register(Dog dog) {
        if (dog instanceof SubscribedDog subscribedDog) {
            subscribedDogs.add(subscribedDog);
        } else {
            globalDogs.add(dog);
            // 全服狗注册时直接触发全服生成,不需要等定时任务
            triggerGlobalSpawn(dog);
        }
    }

    // 每秒定时任务,无任何类型判断开销
    public void runScheduledTask() {
        List<Player> onlinePlayers = getOnlinePlayers();
        for (SubscribedDog dog : subscribedDogs) {
            Location dogLoc = getDogCurrentLocation(dog.getUUID());
            // 处理半径范围内未订阅的玩家
            for (Player player : onlinePlayers) {
                if (player.getLocation().distanceSquared(dogLoc) > SPAWN_RADIUS_SQUARED) {
                    continue;
                }
                if (!dog.isSubscribed(player)) {
                    dog.subscribe(player);
                    dog.spawn(player);
                }
            }
            // 可选:超出半径的玩家自动取消订阅,减少后续遍历开销
            for (Player subscriber : dog.getSubscribers()) {
                if (subscriber.getLocation().distanceSquared(dogLoc) > SPAWN_RADIUS_SQUARED) {
                    dog.unsubscribe(subscriber);
                    despawnForPlayer(dog.getUUID(), subscriber);
                }
            }
        }
    }
}

额外性能优化建议

  • 用distanceSquared替代distance做半径判断,避免开根号计算,数学上判断结果完全一致,性能提升明显。
  • 如果狗的规模后续上涨到数千只,可以增加地图网格分区,每次定时任务仅遍历玩家所在网格及相邻网格内的狗,无需遍历全量订阅狗。
  • 定时任务开始前统一拉取一次所有在线玩家的位置缓存,避免遍历过程中重复获取玩家位置产生额外开销。

内容的提问来源于stack exchange,提问作者Profeta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 08:15:03