I am creating a PacMan clone just for fun and I am using the pixel perfect collision algorithm to detect when PacMan collides with the maze and the dots (which has not been implemented in the game yet). I know I am using the algorithm correctly but the PacMan is collided with the maze when both the maze and PacMan and are not near each other. I picture for proof showing the debugging screen and the game. Here is the image and code below:
Main 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 PacMan_Bytes
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
enum Direction
{
Left,
Right,
Up,
Down
};
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D maze;
Texture2D pacman;
Color[] mazeclr = new Color[484 * 483];
Color[] pacmanclr = new Color[20 * 27];
Rectangle dest;
Rectangle src;
int frame = 2;
float rotation = 0.0f;
Direction dir;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 484;
graphics.PreferredBackBufferHeight = 483;
dest = new Rectangle(50, 455, 20, 27);
src = new Rectangle(frame, 0, 20, 27);
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
maze = Content.Load<Texture2D>("maze");
pacman = Content.Load<Texture2D>("pacman");
maze.GetData<Color>(mazeclr);
// Get the colors that comprises the image for pixel perfect collision.
pacman.GetData<Color>(0, src, pacmanclr, 0, 20 * 27);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
this.TargetElapsedTime = TimeSpan.FromSeconds(1.0f / 13.0f);
// Each frame check if the PacMan has collided with the maze.
bool collision = PacmanAnimator.CollidedWithMaze(dest, pacmanclr, maze.Bounds, mazeclr);
// If PacMan doesn't collide with the maze allow the PacMan to move.
if (collision == false)
{
if (Keyboard.GetState().IsKeyDown(Keys.Left))
{
PacmanAnimator.AnimateAndMoveLeft(ref rotation, ref frame, ref src, ref dest);
dir = Direction.Left;
}
else if (Keyboard.GetState().IsKeyDown(Keys.Right))
{
PacmanAnimator.AnimateAndMoveRight(ref rotation, ref frame, ref src, ref dest);
dir = Direction.Right;
}
else if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
PacmanAnimator.AnimateAndMoveUp(ref rotation, ref frame, ref src, ref dest);
dir = Direction.Up;
}
else if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
PacmanAnimator.AnimateAndMoveDown(ref rotation, ref frame, ref src, ref dest);
dir = Direction.Down;
}
}
// If collision is true move the PacMan away from the maze's border.
else if (collision == true)
{
if (dir == Direction.Down)
{
dest.Y -= 1;
}
else if (dir == Direction.Up)
{
dest.Y += 1;
}
else if (dir == Direction.Left)
{
dest.X += 1;
}
else if (dir == Direction.Right)
{
dest.X -= 1;
}
}
if (dest.X < 0)
{
dest.X = graphics.PreferredBackBufferWidth - 20;
}
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Transparent);
spriteBatch.Begin();
spriteBatch.Draw(maze, Vector2.Zero, Color.White);
spriteBatch.Draw(pacman, dest, src, Color.White, rotation, new Vector2(20 / 2, 24 / 2), SpriteEffects.None, 1);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
PacmanAnimator Class:
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 PacMan_Bytes
{
static class PacmanAnimator
{
// Animates and moves the PacMan to the left.
public static void AnimateAndMoveLeft(ref float rotation, ref int frame, ref Rectangle src, ref Rectangle dest)
{
switch (frame)
{
case 2:
{
frame = 40;
break;
}
case 40:
{
frame = 2;
break;
}
}
src.X = frame;
dest.X -= 7;
rotation = MathHelper.ToRadians(180.0f);
}
// Animates and moves the sprite to the right.
public static void AnimateAndMoveRight(ref float rotation, ref int frame, ref Rectangle src, ref Rectangle dest)
{
switch (frame)
{
case 2:
{
frame = 40;
break;
}
case 40:
{
frame = 2;
break;
}
}
src.X = frame;
dest.X += 7;
rotation = 0.0f;
}
// Moves and animates the sprite upward.
public static void AnimateAndMoveUp(ref float rotation, ref int frame, ref Rectangle src, ref Rectangle dest)
{
switch (frame)
{
case 2:
{
frame = 40;
break;
}
case 40:
{
frame = 2;
break;
}
}
src.X = frame;
dest.Y -= 7;
rotation = MathHelper.ToRadians(270.0f);
}
// Moves the sprite downward and animates it.
public static void AnimateAndMoveDown(ref float rotation, ref int frame, ref Rectangle src, ref Rectangle dest)
{
switch (frame)
{
case 2:
{
frame = 40;
break;
}
case 40:
{
frame = 2;
break;
}
}
src.X = frame;
dest.Y += 7;
rotation = MathHelper.ToRadians(90.0f);
}
// Subroutine that deals with collision.
public static bool CollidedWithMaze(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB)
{
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) +
(y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return true;
}
}
}
// No intersection found
return false;
}
}
}
PS. The PacMan sprite has a transparent background and the black areas you see on the maze are transparent. So I know that is not the problem. By the way sorry for such a long post.
Edit: Added comments to make code more understandable.
Your problem is that you're trying to test "not completely transparent" with this line:
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
But that's the opposite: that is testing if they're NOT completely OPAQUE.
Completely transparent would be alpha 255, or 1.0f, depending on int/float.
After doing some research I found out it is better to do tile base collision rather than pixel perfect collision.
Related
Apparantly I have to show research efforts (and be clearer)?!?...
I have been trying to make a top-down space shooter from scratch using XNA. I have done this quite a few times in the past but havent been coding for a while and this is catching me out again. I am having a problem making the bullets fire how I want them too (I want a maximum specified number of bullets eg.5 on screen at any one time).
I have read many many articles on using arrays but for some reason I cannot see why they only appear as one bullet. I have debugged to the best of my ability and see that it seems they are all being created and 'fired' when space if pushed, however it seems they are all drawn in the same position and hence look like one bullet. Interestingly, the higher i set my 'maxBullets' variable the faster the bullets travel, as if the position -= speed is being applied to all of them each time I create a new Bullet1.
Can any one please help me find the solution. If you need any info if I have left something out, please just let me know. All help appreciated. Thanks :)
Code is below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 AlienAttacks
{
public class Player
{
Texture2D texture, bulletTexture1;
KeyboardState kbState;
public Vector2 position;
public int turnSpeed = 15, backSpeed = 2, forwardSpeed = 3;
Rectangle gameScreenBounds;
public int frameWidth, frameHeight, currentFrameX, currentFrameY;
Rectangle drawnRect;
Bullet[] bullets;
Bullet bullet1;
public int maxBullets = 3; // this will actually allow one extra bullet due to array starting at zero
public int bulletSpeed = 4;
public float FireTimer = 0.0f, FireRate = 0.8f;
public Player(Texture2D Texture, int FrameWidth, int FrameHeight, Rectangle GameScreenBounds, Texture2D BulletTexture1)
{
texture = Texture;
frameWidth = FrameWidth;
frameHeight = FrameHeight;
gameScreenBounds = GameScreenBounds;
bulletTexture1 = BulletTexture1;
bullet1 = new Bullet(bulletTexture1, bulletSpeed);
bullets = new Bullet[maxBullets];
for (int i = 0; i < maxBullets; i++)
{
bullets[i] = bullet1;
}
}
public void Update(GameTime gameTime)
{
drawnRect = new Rectangle(currentFrameX * frameWidth, currentFrameY * frameHeight, frameWidth, frameHeight);
kbState = Keyboard.GetState();
// Keyboard Controls
if (kbState.IsKeyDown(Keys.A) && position.X > gameScreenBounds.Left)
{
position.X -= turnSpeed;
}
if (kbState.IsKeyDown(Keys.D) && position.X + frameWidth < gameScreenBounds.Right)
{
position.X += turnSpeed;
}
if (kbState.IsKeyDown(Keys.W) && position.Y > gameScreenBounds.Top)
{
currentFrameX = 1;
position.Y -= forwardSpeed;
}
else
currentFrameX = 0;
if (kbState.IsKeyDown(Keys.S) && position.Y + frameHeight < gameScreenBounds.Bottom)
{
position.Y += backSpeed;
}
for (int i = 0; i < maxBullets; i++)
{
bullets[i] = bullet1;
bullets[i].Update(gameTime);
}
FireTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (kbState.IsKeyDown(Keys.Space))
{
for (int i = 0; i < maxBullets; i++)
{
if (FireTimer >= FireRate)
{
if (!bullets[i].IsAlive)
{
bullets[i].IsAlive = true;
bullets[i].position = position;
FireTimer = 0.0f;
}
}
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, drawnRect, Color.White);
for (int i = 0; i < maxBullets; i++)
{
bullets[i].Draw(spriteBatch);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 AlienAttacks
{
public class Bullet
{
public Texture2D texture;
public Vector2 position;
public int speed;
public bool IsAlive = false;
public Bullet(Texture2D Texture, int Speed)
{
texture = Texture;
speed = Speed;
}
public void Update(GameTime gameTime)
{
if (IsAlive)
{
position.Y -= speed;
// if bullet goes off top of screen...
if (position.Y - texture.Height < 0)
{
BulletDead();
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
if (IsAlive)
spriteBatch.Draw(texture, position, Color.White);
}
public void BulletDead()
{
IsAlive = false;
}
}
}
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 AlienAttacks
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Rectangle gameScreenBounds;
Texture2D hudBGTexture;
Rectangle hudRect;
int hudPositionY;
Texture2D p1Texture, p1bulletTexture1;
Player player1;
Vector2 player1StartPosition;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
graphics.PreferredBackBufferWidth = 1600;
graphics.PreferredBackBufferHeight = 900;
//graphics.IsFullScreen = true;
graphics.ApplyChanges();
hudRect = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, 100);
hudPositionY = graphics.PreferredBackBufferHeight - hudRect.Height;
gameScreenBounds = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight - hudRect.Height);
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
hudBGTexture = Content.Load<Texture2D>("hud");
p1bulletTexture1 = Content.Load<Texture2D>("shot");
p1Texture = Content.Load<Texture2D>("red");
player1 = new Player(p1Texture, 144, 104, gameScreenBounds, p1bulletTexture1);
player1StartPosition = new Vector2(graphics.PreferredBackBufferWidth / 2 - player1.frameWidth / 2, graphics.PreferredBackBufferHeight - hudRect.Height - player1.frameHeight);
player1.position = player1StartPosition;
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
player1.Update(gameTime);
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
SpriteBatch targetBatch = new SpriteBatch(GraphicsDevice);
RenderTarget2D target = new RenderTarget2D(GraphicsDevice, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
GraphicsDevice.SetRenderTarget(target);
spriteBatch.Begin();
player1.Draw(spriteBatch);
spriteBatch.Draw(hudBGTexture, new Vector2(0, hudPositionY), Color.WhiteSmoke);
spriteBatch.End();
GraphicsDevice.SetRenderTarget(null);
targetBatch.Begin();
targetBatch.Draw(target, new Rectangle(0, 0, GraphicsDevice.DisplayMode.Width, GraphicsDevice.DisplayMode.Height), Color.White);
targetBatch.End();
base.Draw(gameTime);
}
}
}
It looks like each item in your array points to the one instance.
bullet1 = new Bullet(bulletTexture1, bulletSpeed);
bullets = new Bullet[maxBullets];
for (int i = 0; i < maxBullets; i++)
{
bullets[i] = bullet1;
}
Should be like this:
bullets = new Bullet[maxBullets];
for (int i = 0; i < maxBullets; i++)
{
bullets[i] = new Bullet(bulletTexture1, bulletSpeed);
}
Okay so I'm making a space invader type game in visual studio 2010 c# with xna studio, currently stuck on the bullet class it spawns the bullet but doesn't fire it off in the direction that the sprite is pointing. The bullet class says the Public Vector2 origin; isn't being assigned to anything & is remaining at its default value however I don't know what could be causing it.
Code for bullet
class Bullets
{
public Texture2D texture;
public Vector2 position;
public Vector2 velocity;
public Vector2 origin;
public bool isVisible;
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, 1);
}
}
Code for the game is:
namespace Rotationgame
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Vector2 spriteVelocity;
const float tangentialVelocity = 0f;
float friction = 1f;
Texture2D spriteTexture;
Rectangle spriteRectangle;
Rectangle screenRectangle;
// The centre of the image
Vector2 spriteOrigin;
Vector2 spritePosition;
float rotation;
// Background
Texture2D backgroundTexture;
Rectangle backgroundRectangle;
// Shield
Texture2D shieldTexture;
Rectangle shieldRectangle;
// Bullets
List<Bullets> bullets = new List<Bullets>();
KeyboardState pastKey;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 1250;
graphics.PreferredBackBufferHeight = 930;
screenRectangle = new Rectangle(
0,
0,
graphics.PreferredBackBufferWidth,
graphics.PreferredBackBufferHeight);
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
shieldTexture = Content.Load<Texture2D>("Shield");
shieldRectangle = new Rectangle(517, 345, 250, 220);
spriteTexture = Content.Load<Texture2D>("PlayerShipup");
spritePosition = new Vector2(640, 450);
backgroundTexture = Content.Load<Texture2D>("Background");
backgroundRectangle = new Rectangle(0, 0, 1250, 930);
// TODO: use this.Content to load your game content here
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
// TODO: Add your update logic here
if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastKey.IsKeyUp(Keys.Space))
Shoot();
pastKey = Keyboard.GetState();
spritePosition = spriteVelocity + spritePosition;
spriteRectangle = new Rectangle((int)spritePosition.X, (int)spritePosition.Y,
spriteTexture.Width, spriteTexture.Height);
spriteOrigin = new Vector2(spriteRectangle.Width / 2, spriteRectangle.Height / 2);
if (Keyboard.GetState().IsKeyDown(Keys.Right)) rotation += 0.025f;
if (Keyboard.GetState().IsKeyDown(Keys.Left)) rotation -= 0.025f;
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
}
else if (Vector2.Zero != spriteVelocity)
{
float i = spriteVelocity.X;
float j = spriteVelocity.Y;
spriteVelocity.X = i -= friction * i;
spriteVelocity.Y = j -= friction * j;
base.Update(gameTime);
}
}
public void UpdateBullets()
{
foreach (Bullets bullet in bullets)
{
bullet.position += bullet.velocity;
if (Vector2.Distance(bullet.position, spritePosition) > 100)
bullet.isVisible = false;
}
for (int i = 0; i < bullets.Count; i++)
{
if(!bullets[i].isVisible)
{
bullets.RemoveAt(i);
i--;
}
}
}
public void Shoot()
{
Bullets newBullet = new Bullets(Content.Load<Texture2D>("ball"));
newBullet.velocity = new Vector2((float)Math.Cos(rotation),(float)Math.Sin(rotation)) * 5f + spriteVelocity;
newBullet.position = spritePosition + newBullet.velocity * 5;
newBullet.isVisible = true;
if(bullets.Count() < 20)
bullets.Add(newBullet);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(backgroundTexture, backgroundRectangle, Color.White);
spriteBatch.Draw(shieldTexture, shieldRectangle, Color.White);
foreach (Bullets bullet in bullets)
bullet.Draw(spriteBatch);
spriteBatch.Draw(spriteTexture, spritePosition, null, Color.White, rotation, spriteOrigin, 1f, SpriteEffects.None, 0);
spriteBatch.End();
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}
Where am I going wrong?
When you draw the bullet you pass origin as an argument but never set a value to it. You should find the point on the image which you want to be the origin (so if you place the bullet at 0,0 that part of the image will be on 0,0).
If you don't set a value for a variable and then try and pass it into a function if it's needed by the function then this will cause the program to crash.
Try 0,0 first so in the class
Vector2 origin=new Vector2(0,0);
That should make your code work, tweak the origin based on your preferences.
Also instead of making these variables public it is far better practise to make the private and create get and set functions in bullet to set them or get the values. This minimises the risk of unpredictable access and modification
EDIT: looked again realised that although a problem was not THE problem.
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
updateBullets();
...
}
You need to actually call updateBullets in your update function, it won't get called automatically
I modified your Game classes Update method to call your UpdateBullets method and now the bullet sprites will travel in a direction and then disappear.
I have also fixed the Shoot() method to properly direct the bullets according to the direction the ship is rotated to.
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
// TODO: Add your update logic here
if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastKey.IsKeyUp(Keys.Space))
Shoot();
pastKey = Keyboard.GetState();
spritePosition = spriteVelocity + spritePosition;
spriteRectangle = new Rectangle((int)spritePosition.X, (int)spritePosition.Y,
spriteTexture.Width, spriteTexture.Height);
spriteOrigin = new Vector2(spriteRectangle.Width / 2, spriteRectangle.Height / 2);
if (Keyboard.GetState().IsKeyDown(Keys.Right)) rotation += 0.025f;
if (Keyboard.GetState().IsKeyDown(Keys.Left)) rotation -= 0.025f;
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
}
else if (Vector2.Zero != spriteVelocity)
{
float i = spriteVelocity.X;
float j = spriteVelocity.Y;
spriteVelocity.X = i -= friction * i;
spriteVelocity.Y = j -= friction * j;
base.Update(gameTime);
}
UpdateBullets();
}
public void Shoot()
{
Bullets newBullet = new Bullets(Content.Load<Texture2D>("ball"));
newBullet.velocity = new Vector2((float)Math.Sin(rotation), (float)Math.Cos(rotation)) * new Vector2(5f,-5f) + spriteVelocity;
newBullet.position = spritePosition + newBullet.velocity * 5;
newBullet.isVisible = true;
if (bullets.Count < 20)
bullets.Add(newBullet);
}
I am following: http://xbox.create.msdn.com/en-US/education/tutorial/2dgame/animating_the_player and it was when during implementing the animation something went wrong. But I am not sure why:
Game1.cs (the only method I changed here was LoadContent()-method and UpdatePlayer()-method.
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;
using Microsoft.Xna.Framework.Input.Touch;
namespace Shooter
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//Represents the player
Player player;
KeyboardState currentKeyboardState;
KeyboardState previousKeyboardState;
GamePadState currentGamePadState;
GamePadState previousGamePadState;
float playerMoveSpeed;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
player = new Player();
playerMoveSpeed = 8.0f;
TouchPanel.EnabledGestures = GestureType.FreeDrag;
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
//Load the player resources
// Load the player resources
Animation playerAnimation = new Animation();
Texture2D playerTexture = Content.Load<Texture2D>("shipAnimation");
playerAnimation.Initialize(playerTexture, Vector2.Zero, 115, 69, 8, 30, Color.White, 1f, true);
Vector2 playerPosition = new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y
+ GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
player.Initialize(playerAnimation, playerPosition);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
previousGamePadState = currentGamePadState;
previousKeyboardState = currentKeyboardState;
currentKeyboardState = Keyboard.GetState();
currentGamePadState = GamePad.GetState(PlayerIndex.One);
UpdatePlayer(gameTime);
base.Update(gameTime);
}
private void UpdatePlayer(GameTime gameTime)
{
player.Update(gameTime);
player.Position.X += currentGamePadState.ThumbSticks.Left.X *playerMoveSpeed;
player.Position.Y -= currentGamePadState.ThumbSticks.Left.Y *playerMoveSpeed;
if (currentKeyboardState.IsKeyDown(Keys.Left) || currentGamePadState.DPad.Left == ButtonState.Pressed)
{
player.Position.X -= playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Right) || currentGamePadState.DPad.Right == ButtonState.Pressed)
{
player.Position.X += playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Up) || currentGamePadState.DPad.Up == ButtonState.Pressed)
{
player.Position.Y -= playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Down) || currentGamePadState.DPad.Down == ButtonState.Pressed)
{
player.Position.Y += playerMoveSpeed;
}
//Make sure the player does not go out of bounds
player.Position.X = MathHelper.Clamp(player.Position.X, 0, GraphicsDevice.Viewport.Width - player.Width);
player.Position.Y = MathHelper.Clamp(player.Position.Y, 0, GraphicsDevice.Viewport.Height - player.Height);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
player.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Player.cs
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Shooter
{
class Player
{
//Animation representing the player
public Animation PlayerAnimation;
//Position of the Player relative to the upper left side of the screen
public Vector2 Position;
//State of the player
public bool Active;
//Amount of hit points that player has
public int Health;
//Get the width of the player ship
public int Width
{
get { return PlayerAnimation.FrameWidth; }
}
//Get the height of the player ship
public int Height
{
get { return PlayerAnimation.FrameHeight; }
}
public void Initialize(Animation animation, Vector2 position)
{
PlayerAnimation = animation;
//Set the starting position of the player around the middle of the screen and to the back
Position = position;
//Set the player to be active
Active = true;
//Set the player health
Health = 100;
}
public void Update(GameTime gameTime)
{
PlayerAnimation.Position = Position;
PlayerAnimation.Update(gameTime);
}
public void Draw(SpriteBatch spriteBatch)
{
PlayerAnimation.Draw(spriteBatch);
}
}
}
Animation.cs
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace Shooter
{
class Animation
{
// The image representing the collection of images used for animation
Texture2D spriteStrip;
// The scale used to display the sprite strip
float scale;
// The time since we last updated the frame
int elapsedTime;
// The time we display a frame until the next one
int frameTime;
// The number of frames that the animation contains
int frameCount;
// The index of the current frame we are displaying
int currentFrame;
// The color of the frame we will be displaying
Color color;
// The area of the image strip we want to display
Rectangle sourceRect = new Rectangle();
// The area where we want to display the image strip in the game
Rectangle destinationRect = new Rectangle();
// Width of a given frame
public int FrameWidth;
// Height of a given frame
public int FrameHeight;
// The state of the Animation
public bool Active;
// Determines if the animation will keep playing or deactivate after one run
public bool Looping;
// Width of a given frame
public Vector2 Position;
public void Initialize(Texture2D texture, Vector2 position,
int frameWidth, int frameHeight, int frameCount,
int frametime, Color color, float scale, bool looping)
{
// Keep a local copy of the values passed in
this.color = color;
this.FrameWidth = frameWidth;
this.FrameHeight = frameHeight;
this.frameCount = frameCount;
this.frameTime = frametime;
this.scale = scale;
Looping = looping;
Position = position;
spriteStrip = texture;
// Set the time to zero
elapsedTime = 0;
currentFrame = 0;
// Set the Animation to active by default
Active = true;
}
public void Update(GameTime gameTime)
{
// Do not update the game if we are not active
if (Active == false)
return;
// Update the elapsed time
elapsedTime += (int)gameTime.ElapsedGameTime.TotalMilliseconds;
// If the elapsed time is larger than the frame time
// we need to switch frames
if (elapsedTime > frameTime)
{
// Move to the next frame
currentFrame++;
// If the currentFrame is equal to frameCount reset currentFrame to zero
if (currentFrame == frameCount)
{
currentFrame = 0;
// If we are not looping deactivate the animation
if (Looping == false)
Active = false;
}
// Reset the elapsed time to zero
elapsedTime = 0;
}
// Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
sourceRect = new Rectangle(currentFrame * FrameWidth, 0, FrameWidth, FrameHeight);
// Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
destinationRect = new Rectangle((int)Position.X - (int)(FrameWidth * scale) / 2,
(int)Position.Y - (int)(FrameHeight * scale) / 2,
(int)(FrameWidth * scale),
(int)(FrameHeight * scale));
}
public void Draw(SpriteBatch spriteBatch)
{
if (Active)
{
spriteBatch.Draw(spriteStrip, destinationRect, sourceRect, color);
}
}
}
}
In Game1.cs this is what checking the boundaries. However, this was not changed in this part of the tutorial, so I am not sure why it started to happen, have I missed something? Anything you guys can point out that I did wrong?
//Make sure the player does not go out of bounds
player.Position.X = MathHelper.Clamp(player.Position.X, 0, GraphicsDevice.Viewport.Width - player.Width);
player.Position.Y = MathHelper.Clamp(player.Position.Y, 0, GraphicsDevice.Viewport.Height - player.Height);
After looking at your code, My best guess is that the problem is with the draw function of your animation and how destinationRect is defined.
It looks like the game thinks that the center of your Animation is the top-left corner of your animation..
I think maybe you want to set destinationRect in the Update method of your animation like so
// Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
destinationRect = new Rectangle(
(int)Position.X,
(int)Position.Y,
(int)(FrameWidth * scale),
(int)(FrameHeight * scale));
with the Rectangle's X and Y coordinates being the top left corner of your animation instead of the center.
My collision detection seems to be working, all be it some of the collisions it is detecting are odd as in it'll say that the collision was on the bottom of the platform when it isn't. However that isn't the main problem.
When the player collides with the platform, instead of moving to the surface of the platform he moves above it and with my gravity in place it looks like he is constantly bouncing. I can't figure out why.
If you guys could help it would be much appreciated. It could be something very simple I'm missing since I'm new to XNA and C#.
I will list my Game1, Player and Platoform classes below. (My collision detection is in the player class)
Thanks
Game1 Class
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D background;
Movement character;
Platform[] platforms;
//private Vector2 SnapePosition = Vector2.Zero;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferHeight = 440;
graphics.PreferredBackBufferWidth = 782;
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
platforms = new Platform[15];
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
for (int i = 0; i < platforms.Length; i++)
{
platforms[i] = new Platform(
Content.Load<Texture2D>("Platforms/lvl2_platform"), new Rectangle(i*100, 410, 100, 30));
}
character = new Movement(Content.Load<Texture2D>("snape"), new Rectangle(0, 360, 50, 50), platforms);
// TODO: use this.Content to load your game content here
background = Content.Load<Texture2D>("Backgrounds/lvl2_background");
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
//Allows the player to move
character.Update();
// TODO: Add your update logic here
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
spriteBatch.Draw(background, Vector2.Zero, Color.White);
character.Draw(spriteBatch);
foreach (Platform platform in platforms)
{
platform.Draw(spriteBatch);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
Player Class
class Player
{
public Texture2D Snape;
public Rectangle SnapePosition;
public enum CollisionPosition { None, Top, Bottom, Left, Right };
public CollisionPosition collisionType;
public bool inCollision;
public int collisionDepth;
public Platform[] plat;
public int num;
public virtual void Update()
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Snape, SnapePosition, Color.White);
}
}
class Movement : Player
{
public Movement(Texture2D newSnape, Rectangle newSnapePosition, Platform[] a)
{
Snape = newSnape;
SnapePosition = newSnapePosition;
plat = a;
}
public override void Update()
{
// Check for collision
Collisions();
// Determine collision type
//DetermineCollisionType();
// Separate snape
//SeparateSnape();
KeyboardState keyBoard = Keyboard.GetState();
if (keyBoard.IsKeyDown(Keys.A))
{
SnapePosition.X -= 5;
}
if (keyBoard.IsKeyDown(Keys.D))
{
SnapePosition.X += 5;
}
if (keyBoard.IsKeyDown(Keys.W))
{
SnapePosition.Y -= 5;
}
//if (keyBoard.IsKeyDown(Keys.S))
//{
SnapePosition.Y += 5;
// }
// if (SnapePosition.X < 0)
// SnapePosition.X = 0;
// if (SnapePosition.Y < 0)
// SnapePosition.Y = 0;
// if (SnapePosition.X > GraphicsDevice.Viewport.Width - Snape.Width)
// SnapePosition.X = GraphicsDevice.Viewport.Width - Snape.Width;
// if (SnapePosition.Y > GraphicsDevice.Viewport.Height - Snape.Height)
// SnapePosition.Y = GraphicsDevice.Viewport.Height - Snape.Height;
}
public void Collisions()
{
for (int i = 0; i < plat.Length; i++)
{
if (plat[i].rectangle.Intersects(SnapePosition))
{
inCollision = true;
num = i;
DetermineCollisionType();
}
}
}
public void DetermineCollisionType()
{
if (inCollision == false)
{
collisionType = CollisionPosition.None;
collisionDepth = 0;
}
else
{
// Determine the side of *least intersection* for snape
int minColDepth = int.MaxValue;
// Check the top side
int tColDepth = (plat[num].rectangle.Y + plat[num].texture.Height / 2) - (SnapePosition.Y - Snape.Height / 2);
if (tColDepth > 0 && tColDepth < minColDepth)
{
collisionType = CollisionPosition.Top;
minColDepth = tColDepth;
}
// Check the bottom side
int bColDepth = (SnapePosition.Y + Snape.Height / 2) - (plat[num].rectangle.Y - plat[num].texture.Height / 2);
if (bColDepth > 0 && bColDepth < minColDepth)
{
collisionType = CollisionPosition.Bottom;
minColDepth = bColDepth;
}
// Check the right overlap
int rColDepth = (SnapePosition.X + Snape.Width / 2) - (plat[num].rectangle.X - plat[num].texture.Width / 2);
if (rColDepth > 0 && rColDepth < minColDepth)
{
collisionType = CollisionPosition.Right;
minColDepth = rColDepth;
}
// Check the left overlap
int lColDepth = (plat[num].rectangle.X + plat[num].texture.Width / 2) - (SnapePosition.X - Snape.Width / 2);
if (lColDepth > 0 && lColDepth < minColDepth)
{
collisionType = CollisionPosition.Left;
minColDepth = lColDepth;
}
// Update the collision depth
collisionDepth = minColDepth;
SeparateSnape();
}
}
public void SeparateSnape()
{
switch (collisionType)
{
case CollisionPosition.None:
break;
case CollisionPosition.Top:
SnapePosition.Y += (collisionDepth);
break;
case CollisionPosition.Bottom:
SnapePosition.Y -= collisionDepth;
break;
case CollisionPosition.Right:
SnapePosition.X -= collisionDepth;
break;
case CollisionPosition.Left:
SnapePosition.X += collisionDepth;
break;
}
}
}
Platform Class
class Platform
{
public Texture2D texture;
public Rectangle rectangle;
public Platform(Texture2D newTexture, Rectangle newRectangle)
{
texture = newTexture;
rectangle = newRectangle;
}
public void Update()
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, rectangle, Color.White);
}
}
I fixed up your collision.
All of your depth calculations were incorrect. You were doing them based upon the center of the entity (player/platform) and using their texture sizes instead of their rectangle sizes.
You may have been thinking that everything draws from the middle, but by default it draws from the top left in XNA.
Here are the new depth calculations located in your "Movement" class under the "DetermineCollisionType()" function.
The top depth needs to work on the top of the platform (Y), and on the bottom of snape (Y + Height).
int tColDepth =
(SnapePosition.Y + SnapePosition.Height) - (plat[num].rectangle.Y);
The bottom depth needs to work on the bottom of the playform (Y + Height) and on the top of snape (Y).
int bColDepth =
(plat[num].rectangle.Y + plat[num].rectangle.Height) - (SnapePosition.Y);
The right depth needs to work on the left of the platform (X) and the right of snape (X + Width).
int rColDepth =
(SnapePosition.X + SnapePosition.Width) - (plat[num].rectangle.X);
The left depth needs to work on the right of the platform (X + Width) and on the left of Snape (X).
int lColDepth =
(plat[num].rectangle.X + plat[num].rectangle.Width) - (SnapePosition.X);
This will work from now on in. However you may want to use lists for your platform. Lists are easier for when/if you do a level editor as you don't have to say "I want 15 platforms".
I am using this code, but I still dont figure out why the ball is blurry when I started the game, can someone help me??, I just tryingto to me the ball when the user click but I dont know why It is blurry, I still cheking the code, please help
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 Critters
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D ball;
Vector2 playerPosition;
Vector2 direction;
Vector2 destination;
float speed;
float playerPosX;
float playerPosY;
MouseState oldState;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
this.IsMouseVisible = true;
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
graphics.PreferredBackBufferWidth = 700;
graphics.PreferredBackBufferHeight = 500;
graphics.IsFullScreen = false;
graphics.ApplyChanges();
Window.Title = "Darrells Game";
playerPosY = graphics.GraphicsDevice.Viewport.Height / 10 * 8;
playerPosX = graphics.GraphicsDevice.Viewport.Width / 2;
playerPosition = new Vector2(playerPosX, playerPosY);
destination = playerPosition;
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
ball = Content.Load<Texture2D>("orb");
// TODO: use this.Content to load your game content her
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (Vector2.DistanceSquared(destination, playerPosition) >= speed * speed)
{
MovePlayer();
}
else
{
playerPosition = destination;
}
MouseState leftState = Mouse.GetState();
MouseState rightState = Mouse.GetState();
if ((leftState.LeftButton == ButtonState.Pressed && rightState.RightButton == ButtonState.Pressed))
{
int mouseX = leftState.X;
int mouseY = leftState.Y;
destination = new Vector2(mouseX, mouseY);
speed = 8.0f;
}
else if (leftState.LeftButton == ButtonState.Pressed)
{
int mouseX = leftState.X;
int mouseY = leftState.Y;
destination = new Vector2(mouseX, mouseY);
speed = 2.0f;
}
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
DrawPlayer();
spriteBatch.End();
// TODO: Add your drawing code here
base.Draw(gameTime);
}
private void DrawPlayer()
{
Vector2 textureCentre = new Vector2(ball.Width / 2, ball.Height / 2);
spriteBatch.Draw(ball, playerPosition, null, Color.White, 0f, textureCentre, 0.8f, SpriteEffects.None, 1f);
}
private void MovePlayer()
{
{
direction = destination - playerPosition;
direction.Normalize();
playerPosition += direction * speed;
}
}
}
}
In your draw call:
spriteBatch.Draw
(
ball, // texture
playerPosition, // location
null, // source rect
Color.White, // color
0f, // rotation
textureCentre, // origin
0.8f, // scale
SpriteEffects.None, // effects
1f // layerDepth
);
You have set the scale to 0.8f. This will draw your texture smaller than it really is, which will involve some 'blurring'. Changing the scale value to 1f should get rid of any blurring caused by scaling.
EDIT: If the blurring you mean is the flickering that happens before you have clicked, that is caused by having a destination that is exactly equal to the current location. Your MovePlayer method then causes the current position to become (NaN, NaN):
// before the user has clicked, destination == playerPosition
private void MovePlayer()
{
direction = destination - playerPosition; // direction = (0, 0)
direction.Normalize(); // direction = (NaN, NaN)
playerPosition += direction * speed; // playerPosition = (NaN, NaN)
}
A quick fix for this would be in your Initialize method, change the line:
protected override void Initialize()
{
...
// change this
mDestination = mPlayerPosition;
// to this
mDestination = mPlayerPosition + new Vector2(1, 1);