Ping pong game: ball bounces like crazy - c#

I am very new to C# and XNA and well.. just new to programming in general as well.
So, as an assignment, I need to make a ping pong game using xna.
I was doing alright until I realized that the ball bounces like crazy on the bottom of the screen for a reason that I cannot identify.
Below is my code
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace PongGame
{
public class Game1 : Microsoft.Xna.Framework.Game
{
SpriteFont score;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D leftPaddle;
Texture2D rightPaddle;
Texture2D centerLine;
private Texture2D ball;
private Vector2 leftPaddlePosition = new Vector2();
private Vector2 rightPaddlePosition = new Vector2();
private Vector2 centerLinePosition = new Vector2();
private Vector2 ballPosition = new Vector2();
private Vector2 ballVelocity = new Vector2();
private int WIDTH, HEIGHT;
private int scoreOne=0;
private int scoreTwo=0;
private int round = 1;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
WIDTH = GraphicsDevice.Viewport.Width;
HEIGHT = GraphicsDevice.Viewport.Height;
leftPaddlePosition = new Vector2(0, (HEIGHT / 2)-40);
rightPaddlePosition = new Vector2(WIDTH-30, (HEIGHT / 2)-40);
centerLinePosition = new Vector2(WIDTH / 2, 0);
ballPosition = new Vector2((WIDTH / 2)-15, (HEIGHT / 2)-15);
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
leftPaddle = new Texture2D(GraphicsDevice, 1, 1);
leftPaddle.SetData(new[] { Color.White });
rightPaddle = new Texture2D(GraphicsDevice, 1, 1);
rightPaddle.SetData(new[] { Color.White });
centerLine = new Texture2D(GraphicsDevice, 1, 1);
centerLine.SetData(new[] { Color.White });
score = Content.Load<SpriteFont>("score1");
ball = Content.Load<Texture2D>("ball2");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (round % 2 != 0)
//when the round is an odd numbered round,
{
ballVelocity = new Vector2(4f, 4f);
}
else if (round % 2 == 0)
{
ballVelocity = new Vector2(-4f, 4f);
}
KeyboardState key;
key = Keyboard.GetState();
if (key.IsKeyDown(Keys.W))
{
leftPaddlePosition.Y -= 5f;
}
if (key.IsKeyDown(Keys.S))
{
leftPaddlePosition.Y += 5f;
}
if (key.IsKeyDown(Keys.Up))
{
rightPaddlePosition.Y -= 5f;
}
if (key.IsKeyDown(Keys.Down))
{
rightPaddlePosition.Y += 5f;
}
//Left paddle manipulation
if (leftPaddlePosition.Y < 0)
{
leftPaddlePosition.Y = 0;
}
if (leftPaddlePosition.Y > HEIGHT-80)
{
leftPaddlePosition.Y = HEIGHT-80;
}
//Right paddle manipulation
if (rightPaddlePosition.Y < 0)
{
rightPaddlePosition.Y = 0;
}
if (rightPaddlePosition.Y > HEIGHT - 80)
{
rightPaddlePosition.Y = HEIGHT - 80;
}
//Making sure that the ball stays within the window
if (ballPosition.Y >= HEIGHT - 30)
{
ballVelocity.Y *= -1;
}
if (ballPosition.Y <= 0)
{
ballVelocity.Y *= -1;
}
//Checking if the ball goes over the left gutter
if (ballPosition.X < 29.9f)
{
ballPosition.X = 29.9f;
ballVelocity = new Vector2(0, 0);
scoreTwo++;
round++;
Initialize();
}
//Checking if the ball goes over the right gutter
if (ballPosition.X > WIDTH - 29.9f-29.9f)
{
ballPosition.X = WIDTH - 29.9f-29.9f;
ballVelocity = new Vector2(0, 0);
scoreOne++;
round++;
Initialize();
}
ballPosition.X += ballVelocity.X;
ballPosition.Y += ballVelocity.Y;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
spriteBatch.Draw(ball, ballPosition, Color.White);
spriteBatch.Draw(leftPaddle, leftPaddlePosition, null, Color.White, 0f, Vector2.Zero, new Vector2(30f, 80f), SpriteEffects.None, 0f);
spriteBatch.Draw(rightPaddle, rightPaddlePosition, null, Color.White, 0f, Vector2.Zero, new Vector2(30f, 80f), SpriteEffects.None, 0f);
spriteBatch.Draw(centerLine, centerLinePosition, null, Color.White, 0f, Vector2.Zero, new Vector2(1f, HEIGHT), SpriteEffects.None, 0f);
spriteBatch.DrawString(score, System.Convert.ToString(scoreOne), new Vector2(WIDTH/4-10, 10f), Color.White);
spriteBatch.DrawString(score, System.Convert.ToString(scoreTwo), new Vector2((WIDTH/4)*3-10, 10f), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
I understand that it is quite a long code to post here but since I don't know where the problem lies, I thought it would be best asking you guys.
I also uploaded the game to a dropbox account.
download link on dropbox

Without actually running the code I couldn't tell but SO is not here to write your code for you.
If it were me I would look at this bit here (seems like the most obvious suspect at a glance) ...
//Making sure that the ball stays within the window
if (ballPosition.Y >= HEIGHT - 30)
{
ballVelocity.Y *= -1;
}
if (ballPosition.Y <= 0)
{
ballVelocity.Y *= -1;
}

You should multiply the speed vectors by the amount of milliseconds sience the last frame divide by some speed constant (around 200).
This time is contained by the updatemethond's argument gameTime.

Related

2D Continous Collision Detection in Monogame/Xna Framework

I'm working on a custom physics engine for a potential game - based in Monogame/the XNA framework. While the physics itself works pretty well, I'm running into an issue with collision. When the player comes out of a jump, they can often end up inside the floor.
See image below. I did a couple hours of research on my own and found out that what I probably need is continous collision detection (CCD) similar to how something like Unity might implement it, but all the questions I've found here or other places haven't really worked, and neither has any of my solutions, so I'm asking the strangers on the internet who are smarter than me.
Here's game 1:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using MonoGame.Extended;
using AmethystDawn.Utilities;
namespace AmethystDawn
{
internal class Game1 : Game
{
Texture2D spritesheet;
Texture2D spritesheetFlipped;
Texture2D activeSpritesheet;
Texture2D platform;
float timer; // millisecond timer
int threshold;
Rectangle[] sourceRectangles;
byte previousAnimationIndex;
byte currentAnimationIndex;
RectangleF playerCollider;
RectangleF groundCollider;
PhysicsCalculator physics = new();
Vector2 PlayerPos = new Vector2(0, 0);
private GraphicsDeviceManager graphics;
private SpriteBatch sprites;
private SpriteFont font;
public Game1() : base()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsFixedTimeStep = true;
IsMouseVisible = true;
IsFixedTimeStep = false;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
graphics.PreferredBackBufferWidth = GraphicsDevice.DisplayMode.Width;
graphics.PreferredBackBufferHeight = GraphicsDevice.DisplayMode.Height;
graphics.IsFullScreen = true;
graphics.HardwareModeSwitch = false;
graphics.ApplyChanges();
sprites = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("Fonts/november");
spritesheet = Content.Load<Texture2D>("Sprites/Player/player spritesheet");
spritesheetFlipped = Content.Load<Texture2D>("Sprites/Player/player spritesheet flipped");
platform = Content.Load<Texture2D>("Sprites/platform");
activeSpritesheet = spritesheet;
timer = 0;
threshold = 100;
sourceRectangles = new Rectangle[4];
sourceRectangles[0] = new Rectangle(0, 0, 32, 40);
sourceRectangles[1] = new Rectangle(34, 0, 28, 40);
sourceRectangles[2] = new Rectangle(66, 0, 28, 40);
sourceRectangles[3] = new Rectangle(96, 0, 32, 40);
previousAnimationIndex = 2;
currentAnimationIndex = 1;
base.LoadContent();
}
protected override void UnloadContent()
{
base.UnloadContent();
}
protected override void Update(GameTime gameTime)
{
if (timer > threshold) // check if the timer has exceeded the threshold
{
if (currentAnimationIndex == 1) // if sprite is in the middle sprite of the animation
{
if (previousAnimationIndex == 0) // if the previous animation was the left-side sprite, then the next animation should be the right-side sprite
{
currentAnimationIndex = 2;
}
else
{
currentAnimationIndex = 0; // if not, then the next animation should be the left-side sprite
}
previousAnimationIndex = currentAnimationIndex;
}
else
{
currentAnimationIndex = 1; // if not in the middle sprite of the animation, return to the middle sprite
}
timer = 0;
}
else
{
// if the timer has not reached the threshold, then add the milliseconds that have past since the last Update() to the timer
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
sprites.Begin();
sprites.Draw(platform, new Vector2(0, GraphicsDevice.Viewport.Height - platform.Height - 50), Color.White);
groundCollider = new RectangleF(0, GraphicsDevice.Viewport.Height - platform.Height - 50, platform.Width, platform.Height);
var kstate = Keyboard.GetState();
playerCollider = new(PlayerPos.X, PlayerPos.Y, sourceRectangles[currentAnimationIndex].Width, sourceRectangles[currentAnimationIndex].Height);
if (IsColliding(groundCollider, playerCollider))
{
physics.UpdatePhysicValues(false);
/*if (PlayerPos.Y + playerCollider.Height + 100 > groundCollider.Y)
{
PlayerPos.Y = groundCollider.Y - groundCollider.Height;
}*/
if (kstate.IsKeyDown(Keys.Space))
{
physics.Jump(3f);
}
}
else
{
physics.UpdatePhysicValues(true);
if (kstate.IsKeyDown(Keys.Space))
{
physics.MidairJump(3f);
}
else
{
physics.LockJump();
}
}
if (kstate.IsKeyDown(Keys.A))
{
physics.ApplyWalkingForce(new Vector2(-1, 0), 0.5f);
activeSpritesheet = spritesheetFlipped;
sourceRectangles[0] = new Rectangle(0, 0, 32, 40);
sourceRectangles[1] = new Rectangle(34, 0, 28, 40);
sourceRectangles[2] = new Rectangle(66, 0, 28, 40);
sourceRectangles[3] = new Rectangle(96, 0, 32, 40);
}
else if (kstate.IsKeyDown(Keys.D))
{
physics.ApplyWalkingForce(new Vector2(1, 0), 0.5f);
activeSpritesheet = spritesheet;
sourceRectangles[0] = new Rectangle(96, 0, 32, 40);
sourceRectangles[1] = new Rectangle(66, 0, 28, 40);
sourceRectangles[2] = new Rectangle(34, 0, 28, 40);
sourceRectangles[3] = new Rectangle(0, 0, 32, 40);
}
else
{
}
if (kstate.IsKeyDown(Keys.S) && !IsColliding(groundCollider, playerCollider))
{
physics.ApplyExtraGravity(1f);
}
if (kstate.IsKeyDown(Keys.R))
{
PlayerPos = new Vector2(0, 0);
}
PlayerPos = physics.position(PlayerPos);
// is player on the bounds of the screen
if (PlayerPos.X < 0)
{
PlayerPos.X = 0;
physics.HitWall();
}
else if (PlayerPos.X > GraphicsDevice.Viewport.Width - 32)
{
PlayerPos.X = GraphicsDevice.Viewport.Width - 32;
physics.HitWall();
}
sprites.Draw(activeSpritesheet, PlayerPos, sourceRectangles[currentAnimationIndex], Color.White, 0f, new Vector2(0, 0), 1f, SpriteEffects.None, 0f);
sprites.End();
base.Draw(gameTime);
}
private bool IsColliding(RectangleF rect1, RectangleF rect2)
{
return rect1.Intersects(rect2);
}
}
}
And here's the physics calculator:
using System.Diagnostics;
using Microsoft.Xna.Framework;
namespace AmethystDawn.Utilities
{
internal class PhysicsCalculator
{
private float directionalForce;
private Vector2 direction;
private const float directionalForceMax = 10f;
private float walkingForce;
private const float walkingForceMax = 0.5f;
private float gravityForce;
private const float gravityForceMax = 25f;
private float jumpForce;
private const float jumpForceMax = 5f;
private int framesInAir;
private const int framesInAirMax = 90;
public void UpdatePhysicValues(bool falling)
{
if (directionalForce > 0)
{
directionalForce -= 0.5f;
}
if (walkingForce > 0)
{
walkingForce -= 0.02f;
}
else
{
walkingForce = 0;
}
if (gravityForce > jumpForce)
{
if (falling && !(gravityForce > gravityForceMax))
{
gravityForce += 0.2f;
}
else if (!falling)
{
gravityForce = 0;
direction.Y = 0;
framesInAir = 0;
}
}
else
{
jumpForce -= 0.3f;
}
FixDirection();
}
public void ApplyDirectionalForce(Vector2 directionHit, float forceToApply)
{
direction += directionHit;
directionalForce += forceToApply;
if (directionalForce > directionalForceMax) directionalForce = directionalForceMax;
}
public void ApplyWalkingForce(Vector2 directionWalked, float forceToApply)
{
direction += directionWalked;
walkingForce += forceToApply;
if (walkingForce > walkingForceMax) walkingForce = walkingForceMax;
}
public void Jump(float force)
{
direction += new Vector2(0, -1);
jumpForce += force;
if (jumpForce > jumpForceMax) jumpForce = jumpForceMax;
}
public void MidairJump(float force)
{
framesInAir++;
if (framesInAir > framesInAirMax) return;
jumpForce += force;
if (jumpForce > jumpForceMax) jumpForce = jumpForceMax;
}
public void LockJump()
{
framesInAir = framesInAirMax;
}
public void ApplyExtraGravity(float amount)
{
gravityForce += amount;
}
public Vector2 position(Vector2 currentPosition)
{
currentPosition += new Vector2(0, gravityForce);
currentPosition += new Vector2(direction.X * directionalForce, direction.Y * directionalForce);
currentPosition += new Vector2(direction.X * walkingForce, direction.Y * walkingForce);
currentPosition += new Vector2(0, direction.Y * jumpForce);
return currentPosition;
}
public void HitWall()
{
direction.X = 0;
}
private void CorrectGravity()
{
}
private void FixDirection()
{
if (direction.X > 20) direction.X = 20;
if (direction.Y > 20) direction.Y = 20;
if (direction.X < -20) direction.X = -20;
if (direction.Y < -15) direction.Y = -15;
if (walkingForce <= 0 && directionalForce <= 0) direction.X = 0;
}
}
}
And the image:
I remember watching a tutorial that explained the way of handling continious collision, but that was done in GameMaker Studio 2.
I'll try to translate it to XNA.
In short: You need to check for collision ahead of you with calculating the collision with the current speed beforehand, then let the player approach the solid object 1 pixel at a time through a while loop, and once it hits, then set the velocity in that direction to 0.
Original GMS2 code:
if place_meeting(x+hspeed_, y, o_solid) {
while !place_meeting(x+sign(hspeed_), y, o_solid) {
x += sign(hspeed_);
}
hspeed_ = 0;
}
x += hspeed_;
translated to XNA (dummy code as quick example):
private bool IsColliding(RectangleF rect1, RectangleF rect2, int vspeed)
{
if (rect1.Intersects(new Rectangle(rect2.x, rect2.y + vspeed, rect2.Width, rect2.Height))
{
while (!rect1.Intersects(new Rectangle(rect2.x, rect2.y+Sign(vspeed), rect2.Width, rect2.Height)
{
rect1 += Sign(vspeed) //moves towards the collision 1 pixel at a time
}
return true;
}
return false;
}
//Sign is a build-in function in GMS2 that only returns 1, 0 or -1, depending if the number is positive, 0 or negative
private int Sign(value)
{
return (value > 0) ? 1 : (value < 0) ? -1 : 0;
}
Source: https://youtu.be/zqtT_9eWIkM?list=PL9FzW-m48fn3Ya8QUTsqU-SU6-UGEqhx6

Camera is stuttering after random amount of time

I have a problem that my camera starts to stutter when moving it after a random amount of time. This is not the case for the movement itself. That runs really smoothly. It is just hte camera that starts to stutter. Small notice I am working in monogame
Here is the code of the main
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Cube_chaser
{
public class CubeChaserGame : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Camera camera;
Map map;
BasicEffect effect;
private Vector2 mouseRotationBuffer;
private MouseState currentMouseState, previousMouseState;
public Vector3 moveVector = Vector3.Zero;
public CubeChaserGame()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
camera = new Camera(this, new Vector3(0.5f, 0.5f, 0.5f), Vector3.Zero, 5f);
Components.Add(camera);
effect = new BasicEffect(GraphicsDevice);
map = new Map(GraphicsDevice);
IsMouseVisible = false;
graphics.IsFullScreen = true;
previousMouseState = Mouse.GetState();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
KeyboardState keyState = Keyboard.GetState();
currentMouseState = Mouse.GetState();
moveVector = Vector3.Zero;
//Handle the mouse movement for rotation
float deltaX, deltaY;
if (currentMouseState != previousMouseState)
{
//We need to save the mouse location for further use
deltaX = (currentMouseState.X - (GraphicsDevice.Viewport.Width / 2));
deltaY = (currentMouseState.Y - (GraphicsDevice.Viewport.Height / 2));
mouseRotationBuffer.X -= (0.09f * deltaX * dt);
mouseRotationBuffer.Y -= (0.09f * deltaY * dt);
if (mouseRotationBuffer.Y < MathHelper.ToRadians(-75.0f))
{
mouseRotationBuffer.Y = mouseRotationBuffer.Y - (mouseRotationBuffer.Y - MathHelper.ToRadians(-75.0f));
}
if (mouseRotationBuffer.Y > MathHelper.ToRadians(75.0f))
{
mouseRotationBuffer.Y = mouseRotationBuffer.Y - (mouseRotationBuffer.Y - MathHelper.ToRadians(75.0f));
}
camera.Rotation = new Vector3(-MathHelper.Clamp(mouseRotationBuffer.Y, MathHelper.ToRadians(-75.0f), MathHelper.ToRadians(75.0f)), MathHelper.WrapAngle(mouseRotationBuffer.X), 0);
deltaX = 0;
deltaY = 0;
}
try { Mouse.SetPosition(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2); }
catch { }
if (keyState.IsKeyDown(Keys.W)) moveVector.Z = 1;
if (keyState.IsKeyDown(Keys.S)) moveVector.Z = -1;
if (keyState.IsKeyDown(Keys.A)) moveVector.X = 1;
if (keyState.IsKeyDown(Keys.D)) moveVector.X = -1;
if (keyState.IsKeyDown(Keys.Space) && camera.Position.Y >= 0.5f && camera.Position.Y <= 0.8f) moveVector.Y = 0.05f;
// if (camera.Position.Y == 0.8f&&camera.Position.Y>=0.5f)camera.moveVector.Y=-0.01f;
if (moveVector != Vector3.Zero)
{
//We don't want to make the player move faster when it is going diagonally.
moveVector.Normalize();
//Now we add the smoothing factor and speed factor
moveVector *= (dt * camera.cameraSpeed);
Vector3 newPosition = camera.PreviewMove(moveVector);
bool moveTrue = true;
if (newPosition.X < 0 || newPosition.X > Map.mazeWidth) moveTrue = false;
if (newPosition.Z < 0 || newPosition.Z > Map.mazeHeight) moveTrue = false;
foreach (BoundingBox boxes in map.GetBoundsForCell((int)newPosition.X, (int)newPosition.Z))
{
if (boxes.Contains(newPosition) == ContainmentType.Contains)
{
moveTrue = false;
}
}
if (moveTrue) camera.Move(moveVector);
previousMouseState = currentMouseState;
camera.Update(gameTime);
base.Update(gameTime);
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
map.Draw(camera, effect);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}
}
This is the code for the camera:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
namespace Cube_chaser
{
public class Camera: GameComponent
{
#region Fields
public Vector3 cameraPosition;
public Vector3 cameraRotation;
public float cameraSpeed;
private Vector3 cameraLookAt;
#endregion
#region Properties
public Matrix Projection
{
get;
protected set;
}
public Matrix View
{
get
{
return Matrix.CreateLookAt(cameraPosition, cameraLookAt, Vector3.Up);
}
}
public Vector3 Position
{
get { return cameraPosition; }
set
{
cameraPosition = value;
UpdateLookAt();
}
}
public Vector3 Rotation
{
get { return cameraRotation; }
set
{
cameraRotation = value;
UpdateLookAt();
}
}
#endregion
#region Constructor
public Camera (Game game, Vector3 position, Vector3 rotation, float speed):base(game)
{
cameraSpeed = speed;
//Setup the projection Matrix
Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, game.GraphicsDevice.Viewport.AspectRatio, 0.05f, 100.0f);
MoveTo(position, rotation);
}
#endregion
#region Helper Methods
//Set the camera its position and rotation
public void MoveTo(Vector3 pos, Vector3 rot)
{
Position = pos;
Rotation = rot;
}
//Updating the look at vector
public void UpdateLookAt()
{
//Built a rotation matrix to rotate the direction we are looking
Matrix rotationMatrix = Matrix.CreateRotationX(cameraRotation.X) * Matrix.CreateRotationY(cameraRotation.Y);
// Build a look at offset vector
Vector3 lookAtOffset = Vector3.Transform(Vector3.UnitZ, rotationMatrix);
//Update our camera's look at the vector
cameraLookAt = (cameraPosition + lookAtOffset);
}
//Method to create movement and to check if it can move:)
public Vector3 PreviewMove(Vector3 amount)
{
//Create a rotation matrix to move the camera
Matrix rotate = Matrix.CreateRotationY(cameraRotation.Y);
//Create the vector for movement
Vector3 movement = new Vector3(amount.X, amount.Y, amount.Z);
movement = Vector3.Transform(movement, rotate);
// Give the value of the camera position +ze movement
return (cameraPosition+movement);
}
//Method that moves the camera when it hasnt'collided with anything
public void Move(Vector3 scale)
{
//Moveto the location
MoveTo(PreviewMove(scale), Rotation);
}
#endregion
/*public void Update(GameTime gameTime)
{
}*/
}
}
Any idea why the camera stutters after a while?
Thanks,
Jeromer
Forgot to post the answer to my problem for people having the same issue.
The following changes were made to make the problem go away:
in the constructor of the game1 class
IsFixedTimeStep = true;
TargetElapsedTime = TimeSpan.FromMilliseconds(16);
This results in fixed timesteps and thus a smooth calculation

(Xna) My players position won't update, I need it for my enemy to follow

enter code hereWhen im drawing it to a string it just stays at 300,300 . My mouse always updates its Vector2 position.X, position.Y. I need to be able to update my players position or my enemy wont follow my player. It just goes to that certain player position i set for it. PLEASE HELP AND THANK YOU!
class Enemy
{
Player p = new Player();
public Vector2 direction, velocity,position;
public float speed;
public Texture2D texture;
public Enemy()
{
speed = 1;
texture = null;
position = new Vector2(600, 500);
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("circle");
}
public void Update(GameTime gameTime)
{
MouseState mouse = Mouse.GetState();
direction = p.position - position;
direction.Normalize();
velocity = direction * speed;
position += velocity;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.Red);
}
/*
direction = p.position - position;
direction.Normalize();
velocity = direction * speed;
position += velocity;
*/
}
class Player
{
public float rotation, bulletDelay;
public Vector2 position,velocity,origin;
public string spriteName;
public Texture2D texture,bulletTexture;
List<Bullets> bullets = new List<Bullets>();
public float speed = 10;
public float health = 100;
public Player()
{
texture = null;
spriteName = "playerover";
position = new Vector2(300, 300);
bulletDelay = 20;
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>(spriteName);
bulletTexture = Content.Load<Texture2D>("playerbullet");
}
public void Draw(SpriteBatch spriteBatch)
{
origin = new Vector2(texture.Width / 2, texture.Height / 2);
spriteBatch.Draw(texture, new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height), null, Color.White, rotation,new Vector2(texture.Width / 2, texture.Height / 2), SpriteEffects.None, 0);
foreach (Bullets bullet in bullets)
{
bullet.Draw(spriteBatch);
}
}
public void Update(GameTime gameTime)
{
MouseState curMouse = Mouse.GetState();
KeyboardState keyState = Keyboard.GetState();
Vector2 mouseLoc = new Vector2(curMouse.X, curMouse.Y);
Vector2 direction = mouseLoc - position;
rotation = (float)(Math.Atan2(direction.Y, direction.X));
if (keyState.IsKeyDown(Keys.W))
{
position.Y -= speed;
}
if (keyState.IsKeyDown(Keys.S))
{
position.Y += speed;
}
if (keyState.IsKeyDown(Keys.A))
{
position.X -= speed;
}
if (keyState.IsKeyDown(Keys.D))
{
position.X += speed;
}
if (curMouse.LeftButton == ButtonState.Pressed)
{
Shoot();
}
UpdateBullets();
}
public void UpdateBullets()
{
foreach (Bullets bullet in bullets)
{
bullet.position += bullet.velocity;
if (bullet.position.Y <= 5)
{
bullet.isVisible = false;
}
if (bullet.position.X <= 5)
{
bullet.isVisible = false;
}
if (bullet.position.X >= 785)
{
bullet.isVisible = false;
}
if (bullet.position.Y >= 575)
{
bullet.isVisible = false;
}
}
for (int i = 0; i < bullets.Count; i++)
{
if (!bullets[i].isVisible)
{
bullets.RemoveAt(i);
i--;
}
}
}
public void Shoot()
{
if (bulletDelay >= 0)
bulletDelay--;
if (bulletDelay <= 0)
{
Bullets newBullet = new Bullets(bulletTexture);
newBullet.velocity = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * 5f + velocity;
newBullet.position = position + newBullet.velocity * 5;
newBullet.isVisible = true;
if (bullets.Count < 20)
{
bullets.Add(newBullet);
}
}
if (bulletDelay == 0)
{
bulletDelay = 20;
}
}
}
class Hud
{
public SpriteFont font;
public bool showHud;
Player p = new Player();
Enemy e = new Enemy();
public Hud()
{
showHud = true;
}
public void LoadContent(ContentManager Content)
{
font = Content.Load<SpriteFont>("font");
}
public void Draw(SpriteBatch spriteBatch)
{
MouseState mouse = Mouse.GetState();
if (showHud)
{
spriteBatch.DrawString(font, "Mouse.X = " + mouse.X, new Vector2(10, 0), Color.White);
spriteBatch.DrawString(font, "Mouse.Y = " + mouse.Y, new Vector2(10, 20), Color.White);
spriteBatch.DrawString(font, "Health = " + p.health, new Vector2(10, 40), Color.White);
spriteBatch.DrawString(font, "Pos.Y = " + p.position.Y, new Vector2(10, 60), Color.White);
spriteBatch.DrawString(font, "Pos.X = " + p.position.X, new Vector2(10, 80), Color.White);
}
}
}
I didn't read all the code you posted, but it seems that you created a new separate instance for the player in the Enemy class which is never updated.
class Enemy
{
Player p = new Player();
//...
}
You should either take a Vector2 for the players position into your enemies Update method or handle the enemy movement somewhere else. Perhaps you could have a method in your Enemy class named Follow taking a Player object as a parameter, then you could do something like the following in the place where you handle all entity movement. It would look roughly like this:
public void UpdateEntities(GameTime gameTime)
{
player.Update(gameTime);
enemy.Update(gameTime);
if(PlayerDistanceFromEnemy() < 50)
enemy.Follow(player);
}
That is a very rough guideline and probably something you'd want to rewrite later on, but it will work.
as for the Follow method in your enemy class:
public void Follow(Player player)
{
this.p = player;
}
public void Update(GameTime gameTime)
{
if(p != null)
{
//do stuff
}
}
This will work, but you have to work on the structure of your code if you want to expand. I might update this answer later with a better solution if someone doesn't do it before me.

Difficulties with Windows Phone Accelerometer

I want to use the accelerometer to move a ball in a Windows Phone game. But the ball moves not correct when I tilt the Windows Phone device.
For example, if I tilt the device to the left, the ball isn't moving to the left, instead the ball moves very strange. I don't know what I could change in my code so that the ball moves correctly.
What should I change so that the ball moves correctly if I tilt the Windows Phone device?
UPDATE:
I changed my code but the ball doesn't move in the right direction.
You can download my project here: http://www.file-upload.net/download-8439759/WindowsPhoneGame22.rar.html
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Motion motion;
Texture2D Ball;
Vector2 BallPos = new Vector2(400, 300);
Vector3 accelReading = new Vector3();
Vector3 speed = new Vector3();
void motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e)
{
UpdateUI(e.SensorReading);
}
private void UpdateUI(MotionReading e)
{
accelReading.X = e.DeviceAcceleration.X;
accelReading.Y = e.DeviceAcceleration.Y;
accelReading.Z = e.DeviceAcceleration.Z;
accelReading.Normalize();
Vector3 currentAccelerometerState = accelReading;
if (currentAccelerometerState.X != 0)
speed += new Vector3(currentAccelerometerState.X, 0, 0);
if (currentAccelerometerState.Z != 0)
speed += new Vector3(0, 0, -currentAccelerometerState.Z);
if (speed.Length() > 2)
{
speed.Normalize();
speed *= 2;
}
BallPos.X += speed.X;
BallPos.Y += speed.Y;
}
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
TargetElapsedTime = TimeSpan.FromTicks(333333);
InactiveSleepTime = TimeSpan.FromSeconds(1);
graphics.IsFullScreen = true;
}
protected override void Initialize()
{
if (Motion.IsSupported)
{
motion = new Motion();
motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(motion_CurrentValueChanged);
motion.Start();
}
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Ball = Content.Load<Texture2D>("ballbig");
}
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(Ball, BallPos, null, Color.White, rotation, new Vector2(Ball.Width/2,Ball.Height/2), 1f, SpriteEffects.None,1);
spriteBatch.End();
base.Draw(gameTime);
}
}
I did a pretty similar game on Windows8, and I use a method like this to handle the accelerometer. I hope you can find something that can help you.
private Accelerometer _accelerometer;
public void Initialize()
{
if (_accelerometer != null)
{
_accelerometer = Accelerometer.GetDefault();
_accelerometer.ReadingChanged += _accelerometer_ReadingChanged;
}
}
private void _accelerometer_ReadingChanged(Accelerometer sender, AccelerometerReadingChangedEventArgs args)
{
AccelerometerReading reading = _accelerometer.GetCurrentReading();
Vector3 stateValue = new Vector3();
stateValue.Y = -1;
stateValue.X = (float)reading.AccelerationX;
stateValue.Z = (float)reading.AccelerationY;
stateValue.Normalize();
Vector3 currentAccelerometerState = stateValue;
Vector3 Rotation = Vector3.Zero;
if (currentAccelerometerState.X != 0)
marble.speed += new Vector3(currentAccelerometerState.X, 0, 0);
if (currentAccelerometerState.Z != 0)
marble.speed += new Vector3(0, 0, -currentAccelerometerState.Z);
if (marble.speed.Length() > 10)
{
marble.speed.Normalize();
marble.speed *= 10;
}
}

Object reference is not set to an object

I am trying to create collision between my bullets and the enemy. I have created bounding boxes for each and placed them into their own class. However, I am getting a Null reference error in my HandleCollision function, specifically at the if statement with the bounding boxes. I will also post the rest of my code.
I discussed this with two lecturers and some peers and they asy it is because bullet and enemy are equal to null. This is because it takes a couple of seconds for the enemy to spawn and the bullet only spawns once it is fired. To counter this I added an if statement to check if the bullet or enemy is null yet it still throws up the same error.
HandleCollision Function
private void HandleCollision()//collision
{
Sprite toRemove = null;
if (bullet != null || enemyTexture != null)
{
foreach (EnemySprite e in enemyList) //checks each enemy sprite
{
if (bullet.BoundingBox.Intersects(enemy.BoundingBox))
{
enemyList.Remove(enemy); //removes enemy
//toRemove = enemy;
break;
}
}
}
}
Game1.cs
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Rectangle spriteRectangle;
Rectangle bulletBounds;
Rectangle enemyBounds;
Sprite player;
Bullets bullet;
EnemySprite enemy;
Texture2D enemyTexture;
List<EnemySprite> enemyList = new List<EnemySprite>();
List<Bullets> bulletsList = new List<Bullets>();
//Pause
bool paused = false;
Texture2D pauseTexture;
Rectangle pauseRectangle;
KeyboardState pastKey;
Vector2 enemyPos = new Vector2(100, 400);
Vector2 Position;
Vector2 Distance;
Vector2 spriteOrigin;
Vector2 spriteVelocity;
const float tangentialVelocity = 5f;
float friction = 0.1f;
float rotation;
float timer = 0f;
float dropInterval = 2f;
float speed = 4f;
float angle;
Random random;
enum GameState
{
MainMenu,
Options,
Help,
Playing,
Exit,
}
GameState CurrentGameState = GameState.MainMenu;
// Screen adjustments
int screenWidth = 800, screenHeight = 600;
cButton btnPlay;
cButtonExit btnExit;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
random = new Random();
Position = new Vector2(150, 150);
this.IsMouseVisible = true;
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
player = new Sprite();
player.Texture = Content.Load<Texture2D>("graphics/player");
// Screen stuff
graphics.PreferredBackBufferWidth = screenWidth;
graphics.PreferredBackBufferHeight = screenHeight;
//graphics.IsFullScreen = true;
graphics.ApplyChanges();
IsMouseVisible = true;
btnPlay = new cButton(Content.Load<Texture2D>("Graphics/play"), graphics.GraphicsDevice);
btnPlay.setPosition(new Vector2(350, 190));
btnExit = new cButtonExit(Content.Load <Texture2D>("Graphics/exit"), graphics.GraphicsDevice);
btnExit.setPosition(new Vector2(350, 220));
enemyTexture = Content.Load<Texture2D>("graphics/enemy");
player.Texture = Content.Load<Texture2D>("Graphics/player");
int screenCenterX = GraphicsDevice.Viewport.Width / 2;
player.Position = new Vector2(screenCenterX - (player.Texture.Width / 2), screenHeight - player.Texture.Height - 20);
pauseTexture = Content.Load<Texture2D>("graphics/paused");
pauseRectangle = new Rectangle(0, 0, pauseTexture.Width, pauseTexture.Height);
Bullets.BulletTexture = Content.Load<Texture2D>("graphics/bullet");
}
protected override void Update(GameTime gameTime)
{
MouseState mouse = Mouse.GetState();
IsMouseVisible = true;
switch (CurrentGameState)
{
case GameState.MainMenu:
if (btnPlay.isClicked == true) CurrentGameState = GameState.Playing;
btnPlay.Update(mouse);
if (btnExit.isClicked == true) CurrentGameState = GameState.Help;
btnExit.Update(mouse);
if (btnExit.isClicked == true) CurrentGameState = GameState.Options;
btnExit.Update(mouse);
if (btnExit.isClicked == true) CurrentGameState = GameState.Exit;
btnExit.Update(mouse);
break;
case GameState.Playing:
timer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (timer >= dropInterval)
{
int yPos = random.Next(GraphicsDevice.Viewport.Height - 50);
enemyList.Add(new EnemySprite(enemyTexture, new Vector2(GraphicsDevice.Viewport.Width + 100, yPos)));
timer = 0f;
}
HandleCollision();
HandleMovingEnemy();
MouseState curMouse = Mouse.GetState();
Vector2 mouseLoc = new Vector2(curMouse.X, curMouse.Y);
Vector2 direction = mouseLoc - Position;
spriteRectangle = new Rectangle((int)Position.X, (int)Position.Y,
player.Texture.Width, player.Texture.Height);
Position = spriteVelocity + Position;
spriteOrigin = new Vector2(spriteRectangle.Width / 2, spriteRectangle.Height / 2);
Distance.X = mouse.X - Position.X;
Distance.Y = mouse.Y - Position.Y;
rotation = (float)Math.Atan2(Distance.Y, Distance.X); //calculates the rotation(trigonometry)
//angle = (float)(Math.Atan2(direction.Y, direction.X));
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.A))
Position.X -= 2;
if (keyState.IsKeyDown(Keys.D))
Position.X += 2;
if (keyState.IsKeyDown(Keys.W))
Position.Y -= 2;
if (keyState.IsKeyDown(Keys.S))
Position.Y += 2;
//right and left edge detection
if (Position.X < 0)
Position = new Vector2(0, Position.Y);
int rightEdge = GraphicsDevice.Viewport.Width - player.Texture.Width;
if (Position.X > rightEdge)
Position = new Vector2(rightEdge, Position.Y);
//bottom and top edge detection
if (Position.Y < 0)
Position = new Vector2(Position.X, 0);
int bottomEdge = GraphicsDevice.Viewport.Height - player.Texture.Height;
if (Position.Y > bottomEdge)
Position = new Vector2(Position.X, bottomEdge);
if (!paused)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
{
paused = true;
btnPlay.isClicked = false; //so that everytime its paused I can pause it again
}
enemy.Update();
}
else if(paused)
{
if (btnPlay.isClicked)
{
paused = false;
speed = 4;
}
if (btnExit.isClicked)
Exit();
btnPlay.Update(mouse);
btnExit.Update(mouse);
}
if (Keyboard.GetState().IsKeyDown(Keys.C))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
}
else if (spriteVelocity != Vector2.Zero)
{
float i = spriteVelocity.X;
float j = spriteVelocity.Y;
spriteVelocity.X = i -= friction * i;
spriteVelocity.Y = j -= friction * j;
}
if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastKey.IsKeyUp(Keys.Space))
Fire();
pastKey = Keyboard.GetState();
UpdateBullets();
break;
case GameState.Exit:
this.Exit();
break;
}
base.Update(gameTime);
}
public void UpdateBullets()
{
foreach (Bullets bullet in bulletsList)
{
bullet.position += bullet.velocity;
if(Vector2.Distance(bullet.position, Position) > 500) //finds position
bullet.isVisible = false;
}
for (int i = 0; i < bulletsList.Count; i++)
{
if (!bulletsList[i].isVisible)
{
bulletsList.RemoveAt(i);
i--;
}
}
}
//function to handle movement of enemies
private void HandleMovingEnemy()
{
List<EnemySprite> toRemove = new List<EnemySprite>();
foreach (EnemySprite e in enemyList)
{
if (e.Position.X < (-20))
{
toRemove.Add(e);
}
else
e.Position -= new Vector2(speed, 0);
}
if (toRemove.Count > 0)
{
foreach (EnemySprite e in toRemove)
{
enemyList.Remove(e);
}
}
}
private void HandleCollision()//collision
{
Sprite toRemove = null;
if (bullet != null || enemyTexture != null)
{
foreach (EnemySprite e in enemyList) //checks each enemy sprite
{
if (bullet.BoundingBox.Intersects(enemy.BoundingBox)) //checks if a sprite has intersected an enemy
{
enemyList.Remove(enemy); //removes enemy
//toRemove = enemy;
break;
}
}
}
}
public void Fire()
{
Bullets newBullet = new Bullets(Content.Load<Texture2D>("graphics/bullet"));
Bullets.BulletTexture = Content.Load<Texture2D>("graphics/bullet");
//newBullet.LoadContent(LoadContent);
newBullet.velocity = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * 5f + spriteVelocity;
newBullet.position = Position + newBullet.velocity * 5;
newBullet.isVisible = true;
if (bulletsList.Count() < 20)
bulletsList.Add(newBullet);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
switch (CurrentGameState)
{
case GameState.MainMenu:
spriteBatch.Draw(Content.Load<Texture2D>("Graphics/SeaSideDefenderMainMenu"), new Rectangle(0,0,screenWidth,screenHeight),Color.White);
btnPlay.Draw(spriteBatch);
btnExit.Draw(spriteBatch);
break;
case GameState.Playing:
spriteBatch.Draw(Content.Load<Texture2D>("Graphics/leveltest"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
enemy = new EnemySprite();
enemy.Texture = Content.Load<Texture2D>("graphics/enemy");
enemy.Draw(spriteBatch);
spriteBatch.Draw(player.Texture, Position, null, Color.White, rotation, spriteOrigin, 1f, SpriteEffects.None, 0);
//player.Draw(spriteBatch);
foreach (EnemySprite e in enemyList)
{
e.Draw(spriteBatch);
}
foreach (Bullets bullet in bulletsList)
bullet.draw(spriteBatch);
/*for (int i; i < enemyList.Count; i++)
{
enemyList[i].Draw(spriteBatch);
}*/
if (paused)
{
speed = 0;
spriteBatch.Draw(Content.Load<Texture2D>("graphics/paused"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
btnPlay.Draw(spriteBatch);
btnExit.Draw(spriteBatch);
}
break;
}
spriteBatch.End();
base.Draw(gameTime);
}
}
Bullets.cs
public class Bullets
{
public Texture2D texture;
public static Texture2D BulletTexture;
public Vector2 position;
public Vector2 velocity;
public Vector2 origin;
public bool isVisible;
public Rectangle BoundingBox
{
get { return new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height); }
}
public Bullets(Texture2D newTexture)
{
texture = newTexture;
isVisible = false;
}
public void draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture,position,null,Color.White,0f,origin,1f, SpriteEffects.None, 0);
}
public void LoadContent(ContentManager Content)
{
BulletTexture = Content.Load<Texture2D>(#"graphics/bullet");
}
}
enemy.cs
public class EnemySprite
{
public Texture2D Texture { get; set; }
public Vector2 Position {get; set; }
public Vector2 origin;
public Vector2 velocity;
public Rectangle rectangle;
float rotation = 0f;
bool right;
float distance;
float oldDistance;
public Rectangle BoundingBox
{
get { return new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height); } //uses enemy position and wiwdth to create bounding box
}
public EnemySprite() { }
public EnemySprite(Texture2D texture, Vector2 position)
{
Texture = texture;
Position = position;
oldDistance = distance;
}
float mouseDistance;
public void Update()
{
Position += velocity;
origin = new Vector2(Texture.Width / 2, Texture.Height / 2);
if (distance <= 0)
{
right = true;
velocity.X = 1f;
}
else if(distance <= oldDistance)
{
right = false;
velocity.X = -1f;
}
if (right) distance += 1; else distance -= 1;
MouseState mouse = Mouse.GetState();
mouseDistance = mouse.X - Position.X;
if (mouseDistance >= -200 && mouseDistance <= 200)
{
if (mouseDistance < -1)
velocity.X = -1f;
else if (mouseDistance > 1)
velocity.X = 1f;
else if (mouseDistance == 0)
velocity.X = 0f;
}
}
public void Draw(SpriteBatch spriteBatch)
{
if (Texture != null)
spriteBatch.Draw(Texture, Position, Color.White);
if (velocity.X > 0)
{
spriteBatch.Draw(Texture, Position, null, Color.White, rotation, origin, 1f, SpriteEffects.FlipHorizontally, 0f);
}
else
{
spriteBatch.Draw(Texture, Position, null, Color.White, rotation, origin, 1f, SpriteEffects.None, 0f);
}
}
}
You've not initialized the global variable Bullet anywhere in your game1.cs, therefore you would never get bullet != null as true. Whereas, you'll always get enemyTexture != null as true since you've already initialized enemyTexture in the LoadContent().
Which means you'll always enter the if block while having the Bullet variable not initialized.
Hope this will lead you to the solution.
PS: Do mark the answer as 'Accepted' if this was the most helpful one.

Categories