我正在使用XNA开发游戏。我已经在YouTube上找到了Oyyou的一系列教程,并且到目前为止已经进入了碰撞教程。我已经成功处理了重力,运动和动画。但我遇到碰撞问题。我角色的产生点在空中。
第一个值是我的bool hasJumped。第二个是y速度。它正在加速0.25。 角色正在慢慢地加速下降。所有四个平台都采用相同的方式。所有四个都在列表中,我不会做任何与他们中的任何一个有关的事情。
当我降落在最低点(地面)时,我得到了我需要的参数。 hasJumped是false和velocity.Y是0.
但是当我在三个非地面平台中的一个上时,结果并不像我想要的那样。即使我将它设为0,速度也是0.25。而且由于我的速度是一个非零变量,因此跳跃不会变为真。不幸的是,我无法发布图片,因此无法显示。但我会发布我的代码: 这是我添加玩家和平台的maingame类。
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
player = new Animation(Content.Load<Texture2D>("player"), Content.Load<Texture2D>("rect"), new Vector2(300 + 28, graphics.PreferredBackBufferHeight - 500), 47, 44, graphics.PreferredBackBufferHeight, graphics.PreferredBackBufferWidth);
platformList.Add(new Platform(Content.Load<Texture2D>("Crate"), new Vector2(300,graphics.PreferredBackBufferHeight-100), 80,50));
platformList.Add(new Platform(Content.Load<Texture2D>("Crate"), new Vector2(500, graphics.PreferredBackBufferHeight - 50), 80, 50));
platformList.Add(new Platform(Content.Load<Texture2D>("Crate"), new Vector2(700, graphics.PreferredBackBufferHeight - 60),80,50));
platformList.Add(new Platform(Content.Load<Texture2D>("Crate"), new Vector2(0, graphics.PreferredBackBufferHeight - 10), graphics.PreferredBackBufferWidth, 10));
// TODO: use this.Content to load your game content here
}
这是我的动画类:
class Animation
{
Texture2D texture;
Texture2D rectText;
public Rectangle rectangle;
public Rectangle collisionRect;
public Vector2 position;
Vector2 origin;
public Vector2 velocity;
int currentFrame;
int frameHeight;
int frameWidth;
int screenHeight;
int screenWidth;
float timer;
float interval = 60;
bool movingRight;
public bool hasJumped;
public Animation(Texture2D newTexture, Texture2D newRectText, Vector2 newPosition, int newHeight, int newWidth, int screenH, int screenW)
{
rectText = newRectText;
texture = newTexture;
position = newPosition;
frameHeight = newHeight;
frameWidth = newWidth;
screenHeight = screenH;
screenWidth = screenW;
hasJumped = true;
}
public void Update(GameTime gameTime)
{
rectangle = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
collisionRect = new Rectangle((int)position.X-frameWidth/2, (int)position.Y - frameHeight/2, frameWidth, frameHeight);
origin = new Vector2(rectangle.Width / 2, rectangle.Height / 2);
position = position + velocity;
if (Keyboard.GetState().IsKeyDown(Keys.Right))
{
AnimateRight(gameTime);
velocity.X = 5;
movingRight = true;
}
else if (Keyboard.GetState().IsKeyDown(Keys.Left))
{
AnimateLeft(gameTime);
velocity.X = -5;
movingRight = false;
}
else
{
velocity.X = 0f;
if (movingRight)
currentFrame = 0;
else currentFrame = 4;
}
if(Keyboard.GetState().IsKeyDown(Keys.Space) && !hasJumped)
{
position.Y -= 5f;
velocity.Y = -10;
hasJumped = true;
}
if(hasJumped)
{
velocity.Y += 0.25f;
}
if(position.X<0+frameWidth/2)
{
position.X = 0 + frameWidth / 2;
}
else if (position.X>screenWidth-frameWidth/2)
{
position.X = screenWidth - frameWidth / 2;
}
}
public void AnimateRight(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds/2;
if(timer>interval)
{
currentFrame++;
timer = 0;
if (currentFrame > 3)
{
currentFrame = 0;
}
}
}
public void AnimateLeft(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds / 2;
if (timer > interval)
{
currentFrame++;
timer = 0;
if (currentFrame > 7 || currentFrame < 4)
{
currentFrame = 4;
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture,position,rectangle,Color.White, 0f, origin, 1.0f, SpriteEffects.None, 0);
// spriteBatch.Draw(rectText,collisionRect,Color.White);
}
}}
平台类非常简单:
class Platform
{
Texture2D texture;
Vector2 position;
public Rectangle rectangle;
public Platform(Texture2D newTexture, Vector2 newPosition, int platformWidth, int platformHeight)
{
texture = newTexture;
position = newPosition;
rectangle = new Rectangle((int)position.X, (int)position.Y, platformWidth, platformHeight);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, rectangle, Color.White);
}
}
和碰撞方法:
public static bool isOnTopOf(this Rectangle r1, Rectangle r2)
{
return (r1.Bottom >= r2.Top - 10 &&
r1.Bottom <= r2.Top + 10 &&
r1.Right >= r2.Left + 10 &&
r1.Left <= r2.Right - 10);
}
问题应该在这里:
foreach (Platform a in platformList)
{
if (player.collisionRect.isOnTopOf(a.rectangle) && player.velocity.Y>=0)
{
player.hasJumped = false;
player.velocity.Y = 0f;
if(player.collisionRect.Bottom > a.rectangle.Top || player.collisionRect.Bottom - a.rectangle.Top <=10)
{
player.position.Y = a.rectangle.Y - 48 / 2;
player.hasJumped = false;
}
}
else
{
player.hasJumped = true;
}
}
但是,如果我排除了最后一个它不会失败的平台。
感谢您提出问题。我添加了图片。
答案 0 :(得分:1)
您的问题是当用户位于不是最低平台的平台之上时,在检查用户是否在平台上的else期间,您明确将hasJumped设置为true。
你必须做的是在你的foreach中检查你的平台,通过增加Y坐标(非常取决于你的相机设置)来命令它们,并在你将hasJumped设置为false后中断。这样您就可以避免出现问题:
foreach (Platform a in platformList.OrderByY())
{
if (player.collisionRect.isOnTopOf(a.rectangle) && player.velocity.Y>=0)
{
player.hasJumped = false;
player.velocity.Y = 0f;
if(player.collisionRect.Bottom > a.rectangle.Top || player.collisionRect.Bottom - a.rectangle.Top <=10)
{
player.position.Y = a.rectangle.Y - 48 / 2;
player.hasJumped = false;
}
break;
}
else
{
player.hasJumped = true;
}
}
不幸的是,3D开发经常出现这种情况,我们必须做一些黑客攻击才能使应用程序正确呈现。在使用高级透明度渲染复杂项目时尤其如此。但是,在你的情况下,我会建议你重新想象你处理碰撞的方式。
游戏开发并非易事。从表面上看,您工作的约束强制执行不太理想的架构。 XNA游戏中的所有内容都围绕着更新循环,并且控制哪个项目首先更新的能力是如此简单和诱人,人们倾向于使用它。然而,通常这是一种更好的方法来尝试和推断功能,使您的模型以事件驱动的方式运行。实现此目的的一种方法是在以下阶段中分割游戏的更新周期:
以上不一定是最好的方法,但它确实有效。如果您只依赖于更新周期,您很快就会达到这样的程度,即模型之间的相互依赖性和按顺序触发某些事件的要求将成为支持的噩梦。实施事件驱动机制将使您免于大量的报废工作,并且初始开销非常小。
对于XNA游戏,我建议使用Rx可能听起来有点奇怪,但相信我,这是一个很棒的方式来处理事件。最后,我想提一下MonoGame,这是一个开发Windows,Mac,Linux,Android,iPhone,Windows Phone,WinRT(甚至更多)游戏的优秀框架,如果您还不知道的话。