How do I fix my platformer collision detection? - c#

I'm working on a game that allows my 2D sprite to jump on a platform but when it lands on the platform, my 2D sprite is not exactly on top of the platform, sometimes its exceeding or the same as the position of the platform.
//here is my code:
Texture2D jumper;
Texture2D tile;
Vector2 position, velocity;
Rectangle top;
Rectangle tile_rectangle;
Rectangle jumper_rectangle;
KeyboardState ks;
bool jump;
//here is my Load Content:
protected override void LoadContent()
{
jump = true;
position.X = 10;
position.Y = 10;
jumper = Content.Load<Texture2D>("character");
tile = Content.Load<Texture2D>("tile");
tile_rectangle = new Rectangle(300, 350, tile.Width, tile.Height);
top = new Rectangle(tile_rectangle.X, tile_rectangle.Y - 16, tile_rectangle.Width, 10);
}
//Here is my update:
protected override void Update(GameTime gameTime)
{
ks = Keyboard.GetState();
position += velocity;
float i = 1;
if (ks.IsKeyDown(Keys.Up) && jump == false)
{
position.Y -= 10f;
velocity.Y = -25f;
jump = true;
}
if (jump == true)
{
velocity.Y += 2f * i;
}
if (position.Y > 400)
{
jump = false;
}
if (jump == false)
{
velocity.Y = 0f;
}
BoundingBox();
if (ks.IsKeyDown(Keys.Right))
{
position.X += 5f;
velocity.X = +0.05f;
if (jumper_rectangle.Left > tile_rectangle.Right)
{
jump = true;
}
}
if (ks.IsKeyDown(Keys.Left))
{
position.X -= 5f;
velocity.X = -0.05f;
if (jumper_rectangle.Right < tile_rectangle.Left)
{
jump = true;
}
}
jumper_rectangle = new Rectangle((int)position.X, (int)position.Y, jumper.Width, jumper.Height);
BoundingBox();
base.Update(gameTime);
}
//here is my draw:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(jumper, jumper_rectangle, Color.White);
spriteBatch.Draw(tile, tile_rectangle, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
//here is my method on landing:
public void BoundingBox()
{
if (jumper_rectangle.Intersects(top))
{
if (jumper_rectangle.Bottom > top.Top)
{
position.Y--;
jump = false;
}
}
}
Where did i go wrong or is there some other way?

Related

XNA programming a platformer

"Rem ad Triarios redisse" Scipio Africanus
I'm programming a platformer and I'm working on the collision, but when it collides a get a stack overflow error;I can't figure it out myself and I would be thankfull if someone knew how to fix it.
The code of the class(main concern):
public class Colliding
{
Rectangle testCollide;
Vector2 playerposition, objectPosition;
Texture2D objectPic;
bool jump;
public Rectangle TestCollide
{
get { return TestCollide; }
set { testCollide = value; }
}
public Vector2 ObjectPosition
{
get { return objectPosition; }
set { objectPosition = value; }
}
public Vector2 Return
{
get { return objectPosition; }
}
public Texture2D ObjectPic
{
set { objectPic = value; }
}
public bool Bool
{
get { return jump; }
}
public void Update()
{
/*if (testCollide.Contains(new Point((int)objectPosition.X, (int)objectPosition.Y + (int)objectPic.Height)) && !
testCollide.Contains(new Point((int)objectPosition.X, (int)objectPosition.Y + (int)objectPic.Height)))
{
objectPosition = new Vector2(objectPosition.X, testCollide.Top - objectPic.Height);
jump = false;
}*/
if (testCollide.Contains(new Point((int)objectPosition.X + (int)objectPic.Width, (int)objectPosition.Y))&&
testCollide.Contains(new Point((int)objectPosition.X + (int)objectPic.Width, (int)objectPosition.Y)))
{
objectPosition = new Vector2(TestCollide.Right - objectPic.Width, ObjectPosition.Y);
jump = false;
}
if (testCollide.Contains(new Point((int)objectPosition.X , (int)objectPosition.Y)) &&
testCollide.Contains(new Point((int)objectPosition.X , (int)objectPosition.Y)))
{
objectPosition = new Vector2(TestCollide.Left +1 , ObjectPosition.Y);
jump = false;
}
The Code of my main(a little messy at the moment)
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
KeyboardState keyState;
KeyboardState prevKeyState;
Texture2D flour,nonAnimPlayer;
Rectangle ground1,ground2,playerRect;
Vector2 playerPosition;
float jumpspeed;
int screenX = 800;
int screenY=480;
float standardMoveSpeed;
bool jumping;
Colliding colGround1=new Colliding ();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
this.graphics.PreferredBackBufferWidth = screenX;
this.graphics.PreferredBackBufferHeight = screenY;
}
protected override void Initialize()
{
keyState = Keyboard.GetState();
ground1 = new Rectangle(-100, (screenY / 5) * 4, 300,screenY);
ground2 = new Rectangle(400, (screenY / 5) * 4, 800, screenY);
playerRect = new Rectangle(0, 0, 10, 10);
standardMoveSpeed = 300;
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
flour = Content.Load<Texture2D>("background");
nonAnimPlayer = Content.Load<Texture2D>("blok");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
prevKeyState = keyState;
keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.D))
playerPosition.X += standardMoveSpeed *(float) gameTime.ElapsedGameTime.TotalSeconds;
if (keyState.IsKeyDown(Keys.A))
playerPosition.X -= standardMoveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
if (keyState.IsKeyDown(Keys.Space)&&prevKeyState.IsKeyUp(Keys.Space ))
{
if (jumpspeed == 0)
jumpspeed = 300;
else
jumpspeed += 35;
jumping = true;
}
playerPosition.Y += standardMoveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
if(jumping)
{
playerPosition.Y -= standardMoveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds+jumpspeed*(float)gameTime.ElapsedGameTime.TotalSeconds ;
jumpspeed-=9;
if (jumpspeed <= 0)
jumping = false;
}
if (ground2.Contains(new Point((int)playerPosition.X, (int)playerPosition.Y + (int)nonAnimPlayer.Height)))
{
playerPosition.Y = ground2.Top - nonAnimPlayer.Height;
jumpspeed = 0;
}
colGround1.ObjectPosition = playerPosition;
colGround1.TestCollide = ground1;
colGround1.ObjectPic = nonAnimPlayer;
colGround1.Update();
playerPosition = colGround1.Return;
if (colGround1.Bool)
jumpspeed = 0;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(flour, ground1, Color.White);
spriteBatch.Draw(flour, ground2, Color.White);
spriteBatch.Draw(nonAnimPlayer, playerPosition, Color.White);
spriteBatch.End();
base.Draw(gameTime);

C# XNA - Sprite moves out of window/screen

When I press left or up arrow keys the sprite gets out of the window/screen. My code:
Texture2D m_PlayerShipTex;
Rectangle m_PlayerShipHitBox;
Vector2 m_PlayerShipPos = new Vector2(400, 486);
Vector2 m_PlayerShipOrigin;
int m_PlayerShipCurrentFrame = 1;
int m_PlayerShipFrameWidth = 62;
int m_PlayerShipFrameHeight = 64;
float m_Timer = 0f;
float m_Interval = 100;
public void LoadContent(ContentManager Content)
{
m_PlayerShipTex = Content.Load<Texture2D>(".\\gameGraphics\\gameSprites\\playerShip\\playerShipSpriteSheet");
}
public void Update(GameTime gameTime)
{
m_PlayerShipHitBox = new Rectangle(m_PlayerShipCurrentFrame * m_PlayerShipFrameWidth, 0, m_PlayerShipFrameWidth, m_PlayerShipFrameHeight);
m_PlayerShipOrigin = new Vector2(m_PlayerShipHitBox.X / 2, m_PlayerShipHitBox.Y / 2);
MouseState m_MouseState = Mouse.GetState();
KeyboardState m_KeyboardState = Keyboard.GetState();
m_Timer += (float)gameTime.ElapsedGameTime.Milliseconds;
if (m_Timer > m_Interval)
{
m_PlayerShipCurrentFrame++;
m_Timer = 0f;
}
if (m_PlayerShipCurrentFrame == 2)
{
m_PlayerShipCurrentFrame = 0;
}
m_PlayerShipHitBox = new Rectangle(m_PlayerShipCurrentFrame * m_PlayerShipFrameWidth, 0, m_PlayerShipFrameWidth, m_PlayerShipFrameHeight);
m_PlayerShipOrigin = new Vector2(m_PlayerShipHitBox.Width / 2, m_PlayerShipHitBox.Height / 2);
if (m_KeyboardState.IsKeyDown(Keys.Right))
{
m_PlayerShipPos.X += 3;
}
if (m_KeyboardState.IsKeyDown(Keys.Left))
{
m_PlayerShipPos.X -= 3;
}
if (m_KeyboardState.IsKeyDown(Keys.Down))
{
m_PlayerShipPos.Y += 3;
}
if (m_KeyboardState.IsKeyDown(Keys.Up))
{
m_PlayerShipPos.Y -= 3;
}
if (m_PlayerShipPos.X <= 0)
{
m_PlayerShipPos.X = 0;
}
if (m_PlayerShipPos.X + m_PlayerShipTex.Width >= 1141)
{
m_PlayerShipPos.X = 1141 - m_PlayerShipTex.Width;
}
if (m_PlayerShipPos.Y <= 0)
{
m_PlayerShipPos.Y = 0;
}
if (m_PlayerShipPos.Y + m_PlayerShipTex.Height >= 620)
{
m_PlayerShipPos.Y = 620 - m_PlayerShipTex.Height;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(m_PlayerShipTex, m_PlayerShipPos, m_PlayerShipHitBox, Color.White, 0f, m_PlayerShipOrigin, 1.0f, SpriteEffects.None, 0);
}
I don't know what could be wrong, my window is 800x600 but if I set m_PlayerShipTex.Width >= 800 I can get only to half of the screen, that's why I'm using 1141. Same goes for window height... What am I doing wrong and why the ship's out of the "reacheable" area?
To fix the original problem, use this draw function:
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(m_PlayerShipTex, m_PlayerShipPos, m_PlayerShipHitBox, Color.White, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
}
This will use (0,0) as the origin for drawing; which means that your "edge" calculations will work as originally expected. If you want the centered origin, then you need to account for that adjustment when calculating the edges.
The only reason to change the origin is to make rotation easier; in general, you can just use Vector2.Zero.

Attempting to get asteroids to move down screen themselves

I'm attempting to create an asteroids game and what I am trying to do is to get the asteroids to move down the screen themselves. The code I have loads the asteroids onto the screen however the asteroids do not move.
The code I have for the movement of the asteroids is listed below.
public class Asteroids
{
public int speed;
public Asteroids(Texture2D newTexture, Vector2 newPosition)
{
speed = 2;
}
public LoadContent()
{
while (asteroidsList.Count() < 5)
{
randX = random.Next(0, 1000) + speed;
randY = random.Next(-200, 984) + speed;
asteroidsList.Add(new Asteroids(Content.Load<Texture2D>("asteroid big"), new Vector2(randX, randY)));
}
}
public void Update (GameTime gameTime)
{
// Update Origin
if (texture != null)
{
Asteroidorigin.X = texture.Width / 2;
Asteroidorigin.Y = texture.Height / 2;
}
foreach (Asteroids a in asteroidsList)
{
position.Y = position.Y + speed;
position.X = position.X + speed;
}
if (position.X >= 1280)
{
position.X = -105;
}
if (position.Y >= 1024)
{
position.Y = -105;
}
}
}
Game1.cs
namespace AsteroidsGame
{
// Main
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Random random = new Random();
// List Of Asteroids
// Making New Objects Of These Classes
Player p = new Player();
Background bg = new Background();
Asteroids a = new Asteroids();
EnemySpaceship es = new EnemySpaceship();
// Constructor
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.IsFullScreen = false; // Fullscreen mode
graphics.PreferredBackBufferWidth = 1280; // Screen Width
graphics.PreferredBackBufferHeight = 1024; // Screen Height
this.Window.Title = "12013951 Asteroids Game";
Content.RootDirectory = "Content";
}
// Init
protected override void Initialize()
{
base.Initialize();
}
// Load Content
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
bg.LoadContent(Content);
p.LoadContent(Content);
a.LoadContent(Content);
es.LoadContent(Content);
}
// Unload Content
protected override void UnloadContent()
{
}
// Update
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
bg.Update(gameTime);
p.Update(gameTime);
a.Update(gameTime);
es.Update(gameTime);
a.CheckCollisionAsteroid();
base.Update(gameTime);
}
// Draw
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
bg.Draw(spriteBatch); //Draws The Background
p.Draw(spriteBatch); // Draws The Player
a.Draw(spriteBatch); // Draws asteroids
es.Draw(spriteBatch); // Draws enemy spaceships
spriteBatch.End();
base.Draw(gameTime);
}
// Load Asteroids
}
}
Any help with this issue would be greatly appreciated.
You are modifying the position of something, but I don't see how modifying that position property is modifying the position of each asteroid. You need each asteroid to have its own position property. You could try something like this (assuming position is a Vector2 property of the asteroid class):
public void Update (GameTime gameTime)
{
foreach (Asteroids a in asteroidsList)
{
a.position = new Vector2(
MathHelper.Clamp(a.position.X + speed, -105, 1280),
MathHelper.Clamp(a.position.Y + speed, -200, 1024));
}
}
The MathHelper.Clamp() also removes the need for the if statements you have in the update method.

Getting Acces to Other Classes Variables

I'm working on a pong game, since i'm new at programming, i don't know how to get acess to another class variable. I have seperate classes, green and blue paddles, a ball, and game1.cs.
I control the ball movement with bool movingUp, movingLeft;
It bounces off the borders of the screen, but i don't know how to make it work with the paddles. Basically, how do i check the position of the paddle, and make so when the ball touches the paddle, it bounces off? I mean, how to detect the collision?
public class Ball
{
ParticleEngine particleEngine;
GraphicsDeviceManager graphics;
Texture2D texture;
Vector2 position;
Boolean movingUp, movingLeft;
Vector2 origin;
public Ball()
{
position = new Vector2(800 / 2, 330);
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("ball");
movingLeft = true;
//Particle Engine
List<Texture2D> textures = new List<Texture2D>();
textures.Add(Content.Load<Texture2D>("pixel"));
particleEngine = new ParticleEngine(textures, new Vector2(400, 240));
}
public void Update(GameTime gameTime)
{
float speed = 2.5f;
//Physics
if (movingUp)
{
position.Y -= 3;
}
if (movingLeft)
{
position.X -= 3;
}
if (!movingUp)
{
position.Y += 3;
}
if (!movingLeft)
{
position.X += 3;
}
if (position.X <= 0 && movingLeft) movingLeft = false;
if (position.Y <= 85 && movingUp) movingUp = false;
if (position.X >= 800 - texture.Width && !movingLeft) movingLeft = true;
if (position.Y >= 500 - texture.Height && !movingUp) movingUp = true;
origin = new Vector2(position.X + texture.Width / 2, position.Y + texture.Height / 2);
//Particles
particleEngine.EmitterLocation = new Vector2(origin.X, origin.Y);
particleEngine.Update();
}
public void Draw(SpriteBatch spriteBatch)
{
particleEngine.Draw(spriteBatch);
spriteBatch.Draw(texture, position, Color.White);
}
}
One of the paddle classes (they look the same exept the name and movement keys):
public class GreenPaddle
{
Texture2D texture;
Vector2 position;
float speed = 2f;
public GreenPaddle()
{
position = new Vector2(10, 230);
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("greenpaddle");
}
public void Update(GameTime gameTime)
{
KeyboardState keyState = Keyboard.GetState();
//Check If Keys Are Pressed // Movement
if (keyState.IsKeyDown(Keys.W))
position.Y -= speed;
if (keyState.IsKeyDown(Keys.S))
position.Y += speed;
//Check Border
if (position.Y < 87)
{
position.Y = 87;
}
if (position.Y > 396)
{
position.Y = 396;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Thanks in advance, i really wish to learn things like this :D
Declare the variables you want to access as public, or create get methods.
For public variables you would do:
public Vector2 Position;
And to access it, you would call:
Ball ball;
ball.Position
For get method implement:
public Vector2 getPosition()
{
return Position;
}
And you would call that method to get the position.

40f equal to 40 pixel?

I want that my character makes a 40 pixel height jump if I press the A button once. But I don't know if 40f is equal to 40 pixel?
What do you think about my code? What is wrong?
In addition, I want that my program runs with the same speed on every computer.
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D image, water;
float Gravity = 5.0F;
float Acceleration = 20.0F;
Vector2 Position = new Vector2(1200,720);
Vector2 Velocity;
float rotation = 0;
SpriteEffects flip;
Vector2 Speed = new Vector2(0, 0);
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
image = Content.Load<Texture2D>("cartoondolphin");
water = Content.Load<Texture2D>("background");
flip = SpriteEffects.None;
}
protected override void Update(GameTime gameTime)
{
float VelocityX = 0f;
float VelocityY = 0f;
float time = (float)gameTime.ElapsedGameTime.TotalSeconds;
KeyboardState kbState = Keyboard.GetState();
if(kbState.IsKeyDown(Keys.Left))
{
rotation = 0;
flip = SpriteEffects.None;
VelocityX += -5f;
}
if(kbState.IsKeyDown(Keys.Right))
{
rotation = 0;
flip = SpriteEffects.FlipHorizontally;
VelocityX += 5f;
}
// jump if the dolphin is under water
if(Position.Y >= 670)
{
if (kbState.IsKeyDown(Keys.A))
{
if (flip == SpriteEffects.None)
{
VelocityY += 40f;
}
else
{
VelocityY += 40f;
}
}
}
else
{
VelocityY += -10f;
}
float deltaY = 0;
float deltaX = 0;
deltaY = Gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;
deltaX += VelocityX * (float)gameTime.ElapsedGameTime.TotalSeconds * Acceleration;
deltaY += -VelocityY * (float)gameTime.ElapsedGameTime.TotalSeconds * Acceleration;
Speed = new Vector2(Speed.X + deltaX, Speed.Y + deltaY);
Position += Speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
Velocity.X = 0;
if (Position.Y + image.Height/2 > graphics.PreferredBackBufferHeight)
Position.Y = graphics.PreferredBackBufferHeight - image.Height/2;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(water, new Rectangle(0, graphics.PreferredBackBufferHeight -100, graphics.PreferredBackBufferWidth, 100), Color.White);
spriteBatch.Draw(image, Position, null, Color.White, MathHelper.ToRadians(rotation), new Vector2(image.Width / 2, image.Height / 2), 1, flip, 1);
spriteBatch.End();
base.Draw(gameTime);
}
}
The problem is that you're not taking the gameTime into account. If a computer with a fast CPU executes that code twice as fast as a slower PC, the value of velocity will increase twice as fast (relative to the slower PC).
When you have code like:
VelocityX += 5f;
You need to keep track of the last gameTime, and get the difference between the frames, and multiply that by your constant. (Some code grabbed from Xna adding gravity to a 2d sprite)
int updateTime = gt.ElapsedGameTime.TotalMilliseconds - oldgt.ElapsedGameTime.TotalMilliseconds;
float timeScalar = updateTime / AVG_FRAME_TIME;
VelocityX += 5f * timeScalar;

Categories

Resources