我正在使用XNA在C#中进行游戏,我一直在学习C#中的程序,感谢Nick Gravelyn的教程,但我遇到了麻烦。当我使用尼克的碰撞系统时,我没有使用他的播放器代码。我正在使用一个基于Fatso784的教程,我已经修改过了。因此,我无法使我的碰撞系统的修改版本正常工作。我已经明白了它将玩家推出某些瓷砖,但我需要它更加坚固,因为玩家偶尔也能穿过墙壁。我很确定我正在处理碰撞错误,但可能是碰撞有点糊涂。所以这是我的播放器类的相关代码,移动代码:
public void Move()
{
pos.X = bounds.X;
pos.Y = bounds.Y;
offsetPos.X = bounds.Width;
offsetPos.Y = bounds.Height;
if (frameCount % delay == 0)
{
switch (direction)
{
case "stand":
if (sideCollide == "none")
{
Equalize(2);
}
else if (sideCollide == "left")
{
speed += 1f;
}
else if (sideCollide == "right")
{
speed -= 1f;
}
bounds.X += (int)speed;
if (frameCount / delay >= 8)
frameCount = 0;
srcBounds = new Rectangle(frameCount / delay * 64, 0, 64, 64);
break;
case "left":
if (sideCollide != "left")
{
if (speed > -maxspeed)
{
speed -= acceleration;
}
else if (speed < -maxspeed)
{
speed -= acceleration;
speed += drag;
Equalize(2);
}
speed += friction;
}
bounds.X += (int)speed;
if (frameCount / delay >= 4)
frameCount = 0;
srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
break;
case "right":
if (sideCollide != "right")
{
if (speed < maxspeed)
{
speed += acceleration;
}
else if (speed > maxspeed)
{
speed += acceleration;
speed -= drag;
Equalize(2);
}
speed -= friction;
}
bounds.X += (int)speed;
if (frameCount / delay >= 4)
frameCount = 0;
srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
break;
case "up":
if (speed > -4 && speed < 4)
srcBounds.Y = 128;
else
srcBounds.Y = 64;
if (srcBounds.Y == 0 || srcBounds.Y == 128)
{
if (jumpCount < 2)
{
if (frameCount / delay >= 9)
frameCount = 0;
}
else if (jumpCount > 2 && jumpCount <= 10)
{
if (frameCount / delay > 3)
frameCount = 2 * delay;
}
else if (jumpCount > 10 && jumpCount <= 18)
{
if (frameCount / delay > 5)
frameCount = 4 * delay;
}
else if (jumpCount > 18)
{
if (frameCount / delay >= 9)
frameCount = 0;
}
srcBounds = new Rectangle(frameCount / delay * 64, 128, 64, 64);
}
else if (srcBounds.Y == 64)
{
if (frameCount / delay >= 4)
frameCount = 0;
if (jumpCount <= 10)
srcBounds = new Rectangle((frameCount / delay) / 2 * 64, 64, 64, 64);
else
srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
}
if (jumpCount == 0)
startY = bounds.Y;
bounds = new Rectangle(bounds.X + (int)speed,
(jumpCount - 10) * (jumpCount - 10) - 100 + startY, 64, 64);
jumpCount++;
if (bounds.Y > startY)
{
bounds.Y = startY;
direction = "stand";
jumpCount = 0;
}
break;
}
}
frameCount++;
}
碰撞代码:
public void CollideOutside(TileMap tilemap)
{
Point cell = Engine.PointCell(PlayerCenter);
Point? upLeft = null, Up = null, upRight = null, Right = null, downRight = null, Down = null, downLeft = null, Left = null;
if (cell.Y > 0)
{
Up = new Point(cell.X, cell.Y - 1);
}
if (cell.Y < tilemap.collisionMap.HeightinPixels)
{
Down = new Point(cell.X, cell.Y + 1);
}
if (cell.X > 0)
{
Left = new Point(cell.X - 1, cell.Y);
}
if (cell.X < tilemap.collisionMap.WidthinPixels)
{
Right = new Point(cell.X + 1, cell.Y);
}
if (cell.X > 0 && cell.Y > 0)
{
upLeft = new Point(cell.X - 1, cell.Y - 1);
}
if (cell.X < tilemap.collisionMap.WidthinPixels - 1 && cell.Y > 0)
{
upRight = new Point(cell.X + 1, cell.Y - 1);
}
if (cell.X > 0 && cell.Y < tilemap.collisionMap.HeightinPixels - 1)
{
downLeft = new Point(cell.X - 1, cell.Y + 1);
}
if (cell.X < tilemap.collisionMap.WidthinPixels - 1 && cell.Y < tilemap.collisionMap.Height - 1)
{
downRight = new Point(cell.X + 1, cell.Y + 1);
}
if (Up != null && tilemap.collisionMap.GetCellIndex(Up.Value) == 1)
{
Rectangle rect = Engine.CreateCell(Up.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
}
}
if (Down != null && tilemap.collisionMap.GetCellIndex(Down.Value) == 1)
{
Rectangle rect = Engine.CreateCell(Down.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
}
}
if (Right != null && tilemap.collisionMap.GetCellIndex(Right.Value) == 1)
{
Rectangle rect = Engine.CreateCell(Right.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
speed = -1f;
sideCollide = "right";
}
else
{
sideCollide = "none";
}
}
if (Left != null && tilemap.collisionMap.GetCellIndex(Left.Value) == 1)
{
Rectangle rect = Engine.CreateCell(Left.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
speed = 1f;
sideCollide = "left";
}
else
{
sideCollide = "none";
}
}
if (upLeft != null && tilemap.collisionMap.GetCellIndex(upLeft.Value) == 1)
{
Rectangle rect = Engine.CreateCell(upLeft.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
}
}
if (upRight != null && tilemap.collisionMap.GetCellIndex(upRight.Value) == 1)
{
Rectangle rect = Engine.CreateCell(upRight.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
}
}
if (downLeft != null && Left != null && tilemap.collisionMap.GetCellIndex(downLeft.Value) == 1)
{
Rectangle rect = Engine.CreateCell(downLeft.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
speed = 1f;
sideCollide = "left";
}
}
if (downRight != null && Right != null && tilemap.collisionMap.GetCellIndex(downRight.Value) == 1)
{
Rectangle rect = Engine.CreateCell(downRight.Value);
Rectangle playerCell = Boundary;
if (rect.Intersects(playerCell))
{
speed = -1f;
sideCollide = "right";
}
}
if (Right == null && Left == null)
{
sideCollide = "none";
}
}
public Rectangle Boundary
{
get
{
Rectangle rect = bounds;
rect.X = (int)pos.X;
rect.Y = (int)pos.Y;
return rect;
}
}
那我怎样才能改善碰撞?
答案 0 :(得分:1)
这个答案主要是为了回应蒂姆的答案 - 因为他给出了非常错误的方法。 (你的问题是一个非常大的代码转储,我无法真正发挥这么多代码的错误。)
碰撞检测的技巧 - “真正的”物理引擎的做法 - 是始终将对象视为实体。你总是 - 每一帧 - 检查对象的互穿性,然后分开,如果它们相互渗透。
如果您只测试移动跨对象的边界,那么 会错过碰撞。这包括您尝试通过捕捉到表面来预测和避免碰撞的任何方法。如果你这样做,你只需要浮点精度错误就可以让你在对象中滑动。
编辑:当然,您的代码似乎都是基于整数的(Point
和Rectangle
)。所以至少浮点精度应该不是问题。但也许你有一个<
你应该有一个<=
或者其他什么呢?
(你也在很多地方使用字符串,你应该使用枚举。)