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; } } } } } }
同理,你可以创建ExitCollisionStrategy、ObstacleCollisionStrategy、CustomerCollisionStrategy,分别处理对应的碰撞逻辑。
最后,原来的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




