You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SpaceTaxi游戏碰撞检测代码重构:适用设计模式咨询

嘿,针对你SpaceTaxi游戏里这个臃肿的碰撞检测方法,我有几个非常合适的设计模式思路,能帮你把大方法拆分成清晰、易维护的小类,一起来看看吧~

推荐的重构方案

1. 策略模式(Strategy Pattern)

这个模式最适合你的场景——把不同类型的碰撞检测+处理逻辑,封装成独立的「策略类」,每个类只负责一种碰撞场景的逻辑,完全符合单一职责原则。

实现步骤:

首先定义一个统一的碰撞策略接口,所有碰撞处理类都实现这个接口:

public interface ICollisionStrategy
{
    void Execute(
        Player player, 
        Parser parser, 
        GameState gameState, 
        List<Customer> allCustomers, 
        List<Customer> pickedUpCustomers, 
        Score score
    );
}

然后为每种碰撞场景创建对应的策略类,比如平台碰撞:

public class PlatformCollisionStrategy : ICollisionStrategy
{
    public void Execute(Player player, Parser parser, GameState gameState, List<Customer> allCustomers, List<Customer> pickedUpCustomers, Score score)
    {
        var platformCollision = player.CollisionPlatform(parser.PlatformEntities, false);
        var obstacleCollision = player.CollisionObstacle(parser.ObstacleEntities, false);

        if (platformCollision.Item1 && obstacleCollision)
        {
            // 着陆逻辑
            if (Math.Abs(player.Entity.Shape.AsDynamicShape().Direction.Y) < Constants.COLLISION_DISTANCE)
            {
                player.Shape.Direction.Y = 0;
                player.Shape.Direction.X = 0;
                player.OnPlatform = true;
            }
            else
            {
                gameState.AddExplosion(player.Shape.Position.X, player.Shape.Position.Y, 0.1f, 0.1f);
            }

            // 乘客奖励逻辑
            if (player.HasCostumer)
            {
                foreach (var customer in pickedUpCustomers)
                {
                    if (gameState.CorrectDestination(platformCollision.Item2, customer.DestinationPlatform))
                    {
                        score.AddPoint(gameState.CurrentCustomer.RewardPoints);
                        customer.CanRemove = true;
                        player.HasCostumer = false;
                    }
                }
            }
        }
    }
}

同理,你可以创建ExitCollisionStrategyObstacleCollisionStrategyCustomerCollisionStrategy,分别处理对应的碰撞逻辑。

最后,原来的CollisionCheck方法就会变得非常简洁:

// 在类中初始化策略列表
private readonly List<ICollisionStrategy> _collisionStrategies;

public YourGameClass()
{
    _collisionStrategies = new List<ICollisionStrategy>
    {
        new PlatformCollisionStrategy(),
        new ExitCollisionStrategy(),
        new ObstacleCollisionStrategy(),
        new CustomerCollisionStrategy()
    };
}

private void CollisonCheck()
{
    foreach (var strategy in _collisionStrategies)
    {
        strategy.Execute(Player, Parser, GameRunning, allCustomersInMap, pickedUpCustomers, score);
    }
}

2. 责任链模式(Chain of Responsibility Pattern)

如果你的碰撞处理有顺序依赖,或者某些碰撞发生后需要中断后续检测(比如撞到障碍物后就不用再检测平台碰撞了),责任链模式会更合适。每个处理者负责一种碰撞,处理完后决定是否把请求传递给下一个处理者。

实现步骤:

先定义处理者接口:

public interface ICollisionHandler
{
    bool Handle(
        Player player, 
        Parser parser, 
        GameState gameState, 
        List<Customer> allCustomers, 
        List<Customer> pickedUpCustomers, 
        Score score
    );
    ICollisionHandler SetNext(ICollisionHandler next);
}

创建一个抽象基类简化实现:

public abstract class BaseCollisionHandler : ICollisionHandler
{
    protected ICollisionHandler _nextHandler;

    public ICollisionHandler SetNext(ICollisionHandler next)
    {
        _nextHandler = next;
        return next;
    }

    public virtual bool Handle(Player player, Parser parser, GameState gameState, List<Customer> allCustomers, List<Customer> pickedUpCustomers, Score score)
    {
        return _nextHandler?.Handle(player, parser, gameState, allCustomers, pickedUpCustomers, score) ?? true;
    }
}

然后实现具体的处理者,比如出口碰撞处理:

public class ExitCollisionHandler : BaseCollisionHandler
{
    public override bool Handle(Player player, Parser parser, GameState gameState, List<Customer> allCustomers, List<Customer> pickedUpCustomers, Score score)
    {
        var exitCollision = player.CollisionObstacle(parser.ExitEntities, false);
        
        if (exitCollision)
        {
            // 切换地图逻辑
            gameState.CurrentMap = gameState.CurrentMap == "the-beach.txt" 
                ? "short-n-sweet.txt" 
                : "the-beach.txt";
            
            player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X, Constants.PLAYER_ENTRYPOSITION_Y);
            player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
            player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;

            gameState.Timer.Restart();
            parser.Load(gameState.CurrentMap);
            allCustomers.Clear();
            foreach (var c in parser.Customer)
            {
                allCustomers.Add(new Customer(c.Key, c.Value.Item1, c.Value.Item2, c.Value.Item3, c.Value.Item4, c.Value.Item5));
            }
            
            // 发生出口碰撞后,中断后续处理
            return false;
        }
        
        // 未发生出口碰撞,传递给下一个处理者
        return base.Handle(player, parser, gameState, allCustomers, pickedUpCustomers, score);
    }
}

最后初始化责任链并调用:

private ICollisionHandler _collisionChain;

public YourGameClass()
{
    var platformHandler = new PlatformCollisionHandler();
    var exitHandler = new ExitCollisionHandler();
    var obstacleHandler = new ObstacleCollisionHandler();
    var customerHandler = new CustomerCollisionHandler();
    
    // 构建责任链顺序
    platformHandler.SetNext(exitHandler).SetNext(obstacleHandler).SetNext(customerHandler);
    _collisionChain = platformHandler;
}

private void CollisonCheck()
{
    _collisionChain.Handle(Player, Parser, GameRunning, allCustomersInMap, pickedUpCustomers, score);
}
额外优化建议
  • 把重复代码(比如重置Player位置和方向)提取成公共方法,比如player.ResetMovement(),减少冗余。
  • 把游戏状态操作(比如AddExplosion、切换地图)封装到GameState类中,让策略/处理者类更专注于碰撞逻辑。
  • 如果后续要新增碰撞类型(比如道具碰撞),只需要新增对应的策略/处理者类,完全不用修改原有代码,符合开闭原则。

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

火山引擎 最新活动