这是我在编写代码时考虑到封装和成分的代码示例:
class Bullet {
private:
Vector2 position;
Vector2 speed;
public:
void move(float time_delta) {
position += speed * time_delta;
}
};
[基本上,只有一个弹丸无处移动。但是,子弹实际上可以G。 speed
发生了很大变化,使弹跳离开了墙壁。有没有考虑这种相互作用的好方法?我既不想让Bullet
知道“高级”类(应该自己使用),也不想编写这样的一次性解决方案:
template<typename F> void move(float time_delta, F collision_checker);
如果您想缩小此问题,UPDATE:值得一读。这是移动Bullet
的理想逻辑的简化示例(我并不完全是Bullet::move()
成员函数!)及其与其他实体的交互:
Vector2 destination = bullet.position + bullet.speed * time_delta;
if (std::optional<Creature> target = get_first_creature(bullet.position, destination)) {
// decrease Bullet::speed depending on the target (and calculate the damage)
} else if (std::optional<Wall> obstacle = get_first_wall(bullet.position, destination)) {
// calculate the ricochet changing Bullet::position and Bullet::speed
}
用注释表示的所有代码段都应该使用Creature
和Wall
class
es的某些属性。
从设计的角度来看,最好是子弹头不知道如何检测它何时……穿过障碍物(scnr)。因此,最好将您的Bullet
类转换为struct
,即让它的行为像是作用在某物上而不是某物在作用。
您仍然可以添加便利功能,但它是不变的:
struct Bullet {
Vector2 position;
Vector2 speed;
Vector2 move(float time_delta) const {
return position + speed * time_delta;
}
};
这样您可以从调用范围计算冲突:
auto dest = bullet.move(dt);
while (std::optional<Collision> const col = detectCollision(bullet.position,dest)) {
bullet.position = col->intersectPoint;
bullet.speed = col->reflectedSpeed;
dest = col->reflectDest;
}
bullet.position = dest;
这里detectCollision
检查从子弹当前位置到新位置dest
的线是否与任何障碍物相交,并计算反射参数。实际上,将子弹的所有连续乒乓球与潜在的障碍物连在一起会导致您曲折地到达目的地。