C#/ XNA

编程入门 行业动态 更新时间:2024-10-22 18:29:49
C#/ XNA - 2D碰撞引擎故障?(C# / XNA - 2D collision engine glitch?)

我在这里有很多代码,但它相对简单。

这是来自不同类的所有片段,所有引用都是正确的,但我认为我已经在某处做了基于数学的错误而我找不到它。 它始终在y轴上找到一个像素之前的碰撞。 我没有用不同的X轴位置尝试它,但它似乎落在它旁边的块很好。

struct“mapSection”只包含两个Vector2s-左上角块和左下角块坐标。

tileManager.def_ts是默认的tile宽度和高度(32)。 玩家的大小是32x64。

除了返回之外,toWorldSpace函数现在什么都不做,所以这不是问题。

当我说块坐标时我指的是块在块阵列中的哪个索引(Ex 0,0是第一个块,0,1是Y轴上的第二个块,1,3是X轴上的1个块并且在Y轴上3,我不是指实际像素。)

从tile引擎类:

public mapSection toMapMinMax(Vector2 position, Vector2 size) { position = toWorldSpace(position); position.X = (float)Math.Floor(position.X / tileManager.def_ts); position.Y = (float)Math.Floor(position.Y / tileManager.def_ts); size.X = (float)Math.Floor(size.X / tileManager.def_ts); size.Y = (float)Math.Floor(size.Y / tileManager.def_ts); return new mapSection(position, position + size); } public bool collision(Vector2 screenPosition, Vector2 size) { mapSection mapCollisionPossibilities = toMapMinMax(screenPosition, size); for (int y = (int)mapCollisionPossibilities.topLeft.Y; y <= mapCollisionPossibilities.bottomRight.Y; y++) { for (int x = (int)mapCollisionPossibilities.topLeft.X; x <= mapCollisionPossibilities.bottomRight.X; x++) { if (x >= 0 && y >= 0 && y < tiles.Count && x < tiles[y].Count) { if (tileManager.tileTypes[tiles[y][x]].collideable == true) { return true; } } } } return false; }

这是播放器类的代码:

if (!tEngine.collision(position + new Vector2(0, 1), new Vector2(32, 64))) { position.Y += 1; }

我添加“Vector2(0,1)”,因为我想看看是否有一个像素进一步向下发生碰撞; 所以他一直摔倒,直到他击中一些东西。 它现在非常基础,但它只是测试碰撞引擎,它不起作用。

有一张错误的图片。 你可以看到播放器的像素太高了。

在图中,“X:”是X轴上的左上方块坐标,“X2:”是X轴上的右下方块坐标,与“Y:”和“Y2:Y轴除外”相同。它们直接从mapSection中读取。

如果有人能注意到为什么会发生这种情况,那将会受到大力赞赏。

谢谢。

如果您无法理解代码的任何部分,只需在评论中发布,我将很乐意解释,或者如果您认为我在本文的某些方面有点太不明确。

I've got quite a lot of code here, but it's relatively straightforward.

This is all snippets from different classes, all references are right, but I think I've done a math-based error somewhere and I can't find it. It always finds a collision on the y axis a pixel before it should. I haven't tried it with different X axis positions but it seems to fall past blocks next to it fine.

The struct "mapSection" just contains two Vector2s- A top-left block and bottom-left block coordinate.

tileManager.def_ts is the default tile width and height (32). The player's size is 32x64.

The toWorldSpace function does nothing right now other than return so that's not the problem.

When I say block coordinate I mean which index the block is in the tile array (Ex 0, 0 is the first block, 0, 1 is the second block on the Y axis, 1, 3 is 1 block in on the X axis and 3 on the Y axis, I do not mean actual pixels.)

From tile engine class:

public mapSection toMapMinMax(Vector2 position, Vector2 size) { position = toWorldSpace(position); position.X = (float)Math.Floor(position.X / tileManager.def_ts); position.Y = (float)Math.Floor(position.Y / tileManager.def_ts); size.X = (float)Math.Floor(size.X / tileManager.def_ts); size.Y = (float)Math.Floor(size.Y / tileManager.def_ts); return new mapSection(position, position + size); } public bool collision(Vector2 screenPosition, Vector2 size) { mapSection mapCollisionPossibilities = toMapMinMax(screenPosition, size); for (int y = (int)mapCollisionPossibilities.topLeft.Y; y <= mapCollisionPossibilities.bottomRight.Y; y++) { for (int x = (int)mapCollisionPossibilities.topLeft.X; x <= mapCollisionPossibilities.bottomRight.X; x++) { if (x >= 0 && y >= 0 && y < tiles.Count && x < tiles[y].Count) { if (tileManager.tileTypes[tiles[y][x]].collideable == true) { return true; } } } } return false; }

And this is the code from the player class:

if (!tEngine.collision(position + new Vector2(0, 1), new Vector2(32, 64))) { position.Y += 1; }

I add "Vector2(0, 1)" because I want to see if there's a collision a pixel further down; so that he falls until he hits something. It's very basic right now but it's only to test the collision engine, which isn't working.

There's a picture of the error. You can see the player is a pixel too high.

In the picture, "X:" is the top-left block coordinate on X axis, "X2:" is the bottom-right block coordinate on the X axis, and same with "Y:" and "Y2: except Y axis. They're read from the mapSection directly.

If anyone can notice why this is happening, it would be massively appreciated.

Thanks.

If you cannot understand any section of the code just post in the comments and I'll be happy to explain, or if you think I've been a bit too unspecific in some area of this post.

最满意答案

编辑 :对于tile坐标问题,你的toMapMinMax代码应该更像这样:

EDIT2 :已从bottomRight中减去(1,1),因为它是我们要添加的大小。

public mapSection toMapMinMax(Vector2 position, Vector2 size) { Vector2 topLeft = position; Vector2 bottomRight = position + size - new Vector2(1, 1); topLeft.X = (float)Math.Floor(topLeft.X / tileManager.def_ts); topLeft.Y = (float)Math.Floor(topLeft.Y / tileManager.def_ts); bottomRight.X = (float)Math.Floor(bottomRight.X / tileManager.def_ts); bottomRight.Y = (float)Math.Floor(bottomRight.Y / tileManager.def_ts); return new mapSection(topLeft, bottomRight); }

另外,我在上面的评论中错了; 你确实希望在你的两个for循环中有<=符号,因为大多数时候你会检查6个tile。

对于逐像素问题:

为了让您通过一定量的像素查看字符,绘图代码和碰撞代码必须不同。 如果它们是相同的,例如,如果它们都偏离了15个像素(你过早地碰撞了15个像素,但是你还画了15个像素),你就不会看到任何变化。

1像素间隙表示绘制坐标计算和碰撞坐标计算之间的1像素差。 这个1像素差异很可能是由于舍入的差异造成的,可能是您在碰撞代码中调用Math.Floor,但是没有舍入绘制代码中的坐标。 (我猜你可能只是将Vector2的位置直接传递给SpriteBatch.Draw方法)。

EDIT: For the tile coordinates issue, your toMapMinMax code should be more like this:

EDIT2: have subtracted (1, 1) from bottomRight, since it is a size we are adding.

public mapSection toMapMinMax(Vector2 position, Vector2 size) { Vector2 topLeft = position; Vector2 bottomRight = position + size - new Vector2(1, 1); topLeft.X = (float)Math.Floor(topLeft.X / tileManager.def_ts); topLeft.Y = (float)Math.Floor(topLeft.Y / tileManager.def_ts); bottomRight.X = (float)Math.Floor(bottomRight.X / tileManager.def_ts); bottomRight.Y = (float)Math.Floor(bottomRight.Y / tileManager.def_ts); return new mapSection(topLeft, bottomRight); }

Also, I was wrong in my above comment; you do want <= signs in your two for loops, because most of the time you will be checking 6 tiles.

for the off-by-one-pixel issue:

In order for you to see the character off by some amount of pixels, the draw code and the collision code must be different. If they were identical, for example if they were both off by 15 pixels (you collide 15 pixels too early, but you are also drawing 15 pixels ahead), you wouldn't see any change.

The 1 pixel gap indicates a 1 pixel difference between the draw coordinate calculation and the collision coordinate calculation. This 1 pixel difference is most likely caused by differences in rounding, probably that you are calling Math.Floor in the collision code, but are not rounding the coordinates in the draw code. (I would guess you are probably just passing the position Vector2 straight to the SpriteBatch.Draw method).

更多推荐

本文发布于:2023-08-05 11:14:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1431160.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:XNA

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!