C# XNA Draw 方法和碰撞错误
在从一本创建 3 个游戏的书中学习 C# XNA 后,我一直在尝试制作 2D RPG 游戏,但这些错误让我发疯,我不得不放弃,因为我找不到任何修复。
首先是 Draw 方法,我在屏幕上有岩石,我将它们绘制在相同的深度,但按顺序绘制,因此它沿着 X 轴,然后它增加 Y 轴并重置 X 等等。因此,它们应该与上方或左侧的其他岩石重叠,但这是行不通的。当我四处移动或射箭时,它们随机地相互重叠,如果有帮助的话,这是我的代码:
Game1.cs 绘制方法
Protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(
SpriteSortMode.BackToFront,
BlendState.AlphaBlend);
TileMap.Draw(spriteBatch);
ObjectManager.Draw(spriteBatch);
player.Draw(spriteBatch);
WeaponManager.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
ObjectManager 绘制方法
static public void Draw(SpriteBatch spriteBatch)
{
// Get the tile locations of each corner tile on the screen
int startX = (((int)Camera.Position.X) / 32) - 2;
int endX = ((int)Camera.Position.X + Camera.ViewPortWidth) / 32;
int startY = (((int)Camera.Position.Y) / 32) - 2;
int endY = ((int)Camera.Position.Y + Camera.ViewPortHeight) / 32;
// Go through all possible objects and draw them to the screen if they exist
for (int y = startY; y <= endY; y++)
for (int x = startX; x <= endX; x++)
{
if ((x > 0) && (y > 0) && (x < MapWidth - 1) && (y < MapHeight - 1))
{
if (objects[x, y] != null)
{
spriteBatch.Draw(
texture,
Camera.Transform(objects[x, y].destinationRectangle),
objects[x, y].Frame,
new Color(256, 256, 256, objects[x, y].Transparency),
0,
new Vector2(0, 0),
SpriteEffects.None,
objects[x, y].Depth);
}
}
}
}
第二个问题是我的碰撞,我正在使用 矩形 类的边界框碰撞对于一切。当我的玩家角色移动时,我会为新位置创建一个新的矩形,如果他与任何对象的任何边界框发生碰撞,则移动会被取消,但有时他仍会移动到该位置并卡在对象中1 像素。即使对于同一个对象,有时会发生有时不会发生,这是没有任何意义的。如果有人知道为什么会发生这种情况,请发帖,这里有太多代码要粘贴,所以我将保留它,我更担心 Draw 方法问题。
I've been trying to make a 2D RPG game after learning C# XNA from a book creating 3 games but these bugs are driving me insane and I'm gonna have to give up as I can not find any fix.
First of all is the Draw method, i have rocks on the screen and i have them drawn at the same depth but drawn in order so it goes along to X axes, then it increments the Y axes and resets X and so on. So they should overlap other rocks above them or to the left but it doesn't work. They randomly go on top of each other when i move around or shoot arrows, here is my code if it helps:
Game1.cs Draw Method
Protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(
SpriteSortMode.BackToFront,
BlendState.AlphaBlend);
TileMap.Draw(spriteBatch);
ObjectManager.Draw(spriteBatch);
player.Draw(spriteBatch);
WeaponManager.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
ObjectManager Draw Method
static public void Draw(SpriteBatch spriteBatch)
{
// Get the tile locations of each corner tile on the screen
int startX = (((int)Camera.Position.X) / 32) - 2;
int endX = ((int)Camera.Position.X + Camera.ViewPortWidth) / 32;
int startY = (((int)Camera.Position.Y) / 32) - 2;
int endY = ((int)Camera.Position.Y + Camera.ViewPortHeight) / 32;
// Go through all possible objects and draw them to the screen if they exist
for (int y = startY; y <= endY; y++)
for (int x = startX; x <= endX; x++)
{
if ((x > 0) && (y > 0) && (x < MapWidth - 1) && (y < MapHeight - 1))
{
if (objects[x, y] != null)
{
spriteBatch.Draw(
texture,
Camera.Transform(objects[x, y].destinationRectangle),
objects[x, y].Frame,
new Color(256, 256, 256, objects[x, y].Transparency),
0,
new Vector2(0, 0),
SpriteEffects.None,
objects[x, y].Depth);
}
}
}
}
The second problem is with my collision, I am using bounding box collision with the Rectangle class for everything. When my player character moves, I create a new Rectangle for the new location, and if he is colliding with any of the bounding boxes of any object then movement is cancelled but sometimes he will still move to that location and get stuck in the object by 1 pixel. It just doesn't make any sense how it happens sometimes and other times it doesn't, even with the same object. If anyone has any idea why this could be happening please post, there is way too much code to paste on here so I'll leave it, I'm more bothered about the Draw method problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您正在这样做:
这将根据深度重新排序您的绘制调用。
因此,如果对象具有相同的深度,则会随机绘制。
最好修改岩石的深度,相应地你想要绘制。
第二个错误可能是由于浮动精度造成的。
You are doing this:
This will be reorder your draw calls based in depth.
So if the objects have the same depth will be ramdomly drawed.
Is better that you modify the depth of the rocks, accordinly you want to be drawn.
the second bug may be due to float precision.
问题 1:
正如 Blau 所说,您的岩石将从前往后排序,并且由于它们具有相同的深度,因此它们(有时)会被随机排序。这可能是由于浮动精度(或缺乏浮动精度)造成的。
您可以使用
SpriteSortMode.Deferred
来代替更改岩石的深度,它将按顺序绘制精灵,并延迟渲染直到您调用 End (或者直到 spriteBatch 无法再处理为止)精灵并需要刷新)。问题 2:
正如 Blau 所说,这也可能是由于浮点精度造成的。然而,这个问题是可以避免的。想象一下有一个移动的图块,并且您的玩家走在该图块附近。然后,图块会移动到玩家的顶部(因为我们忘记对图块进行编码)。您的玩家现在无法移动,因为玩家尝试移动的任何方向都是“无效”移动,因为他将触摸该图块。
问题是我们阻止角色移动。如果角色总是可以移动,我们就不会有这个问题。然而,如果角色总是可以移动,他就可以更正确地完成事情。为了防止这种情况发生,当角色在固体物体上移动时,我们需要一个相反的动作。
解决方案:
允许玩家移动到一个物体中,然后扫描他接触到的所有物体。如果他触摸了任何物体,请找出应该将他从每个物体上移开的方向,并将所有这些方向组合起来形成一个向量。将该矢量缩放某个合理的量(以防止角色被急剧推开)。根据该矢量移动玩家
此方法的问题:
如果您有重力等力,您可能会发现您的角色“下沉”到地面中。这是重力对抗将玩家从方块上推回的力的结果。这个问题可以通过先将角色从任何方块上移开来解决,然后再对玩家施力将其移开。
事实证明这是一个非常复杂的问题,并且它已经为您解决了。
Box 2D / Farseer 物理引擎:
您以前可能听说过这些,并想“哦,我就自己推出吧,因为这听起来超级有趣!”虽然编写自己的物理引擎非常有趣,但它也需要非常长的时间。如果您想让游戏通过物理原理快速启动并运行(即使它们是简单的类似索尼克的物理原理),Erin Catto 已经为您奠定了所有基础工作。 :)
看看这些:
Box2D XNA:http://box2dxna.codeplex.com/
Farseer 物理:http://farseerphysicals.codeplex.com/
Problem 1:
As Blau stated, your rocks will be sorted from front to back, and because they have the same depth, they will (some times) be sorted randomly. This is probably due to float precision (or lack thereof).
Instead of changing the depth of your rocks, you can use
SpriteSortMode.Deferred
, which will draw the sprites in order, and delay the render until you call End (or until the spriteBatch can't handle any more sprites and needs to flush).Problem 2:
As Blau stated, this is also probably due to float precision. However, the problem can be avoided. Imagine having a moving tile, and your player walks near that tile. The tile then moves on top of your player (because we forgot to code the tile not to). You're player now cannot move, because any direction the player tries to move is an "invalid" move, because he'll be touching that tile.
The problem is that we're preventing the character from moving. If the character could always move, we wouldn't have this problem. However, if the character could always move, he could just more right through things. To prevent this, we need an opposite action acting against the character when he moves against a solid object.
Solution:
Allow the player to move into an object, and then scan for all of the objects he's touching. If he's touching any, figure out what direction you should move him away from each object, and combine all of those directions to form a single vector. Scale that vector by some reasonable amount (to prevent the character from being pushed away dramatically). Move the player according to that vector
Problems with this method:
If you have a force from gravity, or the like, you may find your character "sinking" into the ground. This is a result of the gravity pushing against the force that pushed the player back from the tiles. The problem can be solved by displacing the character away from any tiles before applying a force on the player to move him away.
This turns out to be a very complex problem, and it is already solved for you.
Box 2D / Farseer Physics Engine:
You've probably heard of these before and thought "Oh, I'll just roll my own, because that sounds super fun!" And while programming your own physics engine can be super fun, it also takes an extremely long time. If you want to get your game up and running quickly with physics (even if they're simple Sonic-like physics), Erin Catto has laid all the ground work for you. :)
Check these out:
Box2D XNA: http://box2dxna.codeplex.com/
Farseer Physics: http://farseerphysics.codeplex.com/
您可以使用 Deferred 代替 SpriteSortMode.BackToFront:
这是文档: http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritesortmode.aspx
Instead of using SpriteSortMode.BackToFront, you can use Deferred:
Here's the doc: http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritesortmode.aspx