Slow down texture changes in an array when dealing with a sprite. - c#

I am making a little game in c# using XNA 4.0. I have successfully made my sprite move in all directions and make it look like it is actually walking using an array. So far I have only tested this with the "Up" key. The problem is that when I push the up key, the sprite moves, but it goes through all the elements in the array so fast that it looks like he is running way to fast for the amount of space he is going. Is there any way to slow down the speed at which the textures change between each other, such as a pause method or something. Any bit of help is appreciated, Thanks.
namespace RandomGame
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Color backColor = Color.FromNonPremultiplied(190, 230, 248, 250);
int i = 0;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.IsFullScreen = false;
graphics.PreferredBackBufferHeight = 500;
graphics.PreferredBackBufferWidth = 800;
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
Texture2D[] UpTextures = new Texture2D[6];
Texture2D startTexture;
Texture2D leftTexture;
Texture2D rightTexture;
Vector2 position = new Vector2(380, 230);
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
startTexture = Content.Load<Texture2D>("BlueLinkStart");
leftTexture = Content.Load<Texture2D>("BlueLinkLeft");
rightTexture = Content.Load<Texture2D>("BlueLinkRight");
UpTextures[0] = Content.Load<Texture2D>("BlueLinkUp");
UpTextures[1] = Content.Load<Texture2D>("BlueLinkUp2");
UpTextures[2] = Content.Load<Texture2D>("BlueLinkUp3");
UpTextures[3] = Content.Load<Texture2D>("BlueLinkUp4");
UpTextures[4] = Content.Load<Texture2D>("BlueLinkUp5");
UpTextures[5] = Content.Load<Texture2D>("BlueLinkUp6");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape))
{
this.Exit();
}
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Left) && position.X > -3)
{
position.X -= 2;
}
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right) && position.X < 772)
{
position.X += 2;
}
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up) && position.Y > -3)
{
position.Y -= 2;
}
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Down) && position.Y < 472)
{
position.Y += 2;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.FromNonPremultiplied(188, 231, 241, 255));
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Left))
{
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
spriteBatch.Draw(leftTexture, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
else if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right))
{
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
spriteBatch.Draw(rightTexture, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
else if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up))
{
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
spriteBatch.Draw(UpTextures[i], position, Color.White);
spriteBatch.End();
i++;
if (i == 6) { i = 0; }
base.Draw(gameTime);
}
else
{
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
spriteBatch.Draw(startTexture, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
}

Yes, there is.
First of all, you need a variable that holds the animation state. Your i is probably supposed to be that. However, you should rename it to e.g. animationState to reflect its purpose. Furthermore, it is easier to make it a float or double variable.
Then updating the animation is a task for the Update() method. You obviously rely on the 60 Hz update frequency. This is ok for a small game, but you should take possible slow downs into consideration for bigger ones. If you have n sprites, and you want to change the sprite every m ms, then you update the animationState as follows:
animationState += updateDuration * m;
if(animationState >= n) animationState -= n;
updateDuration is the time since the last update. So for 60 Hz this is 1000.0 / 60.
And then you need to draw the correct sprite in the Draw() method:
spriteBatch.Draw(UpTextures[(int)animationState], position, Color.White);

Related

Making a Texture2D move in the direction of a mouse click with XNA?

This is the code I have so far. I'm trying to get the bullet to move in the direction of where the mouse is clicked. I have a bullet Rectangle, and a Texture2D, and the same goes for the cannon from where the bullet is fired.
namespace Targeted
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
int screenWidth;
int screenHeight;
int speedX;
int speedY;
MouseState oldMouse;
Texture2D cannon;
Rectangle cannonRect;
Texture2D bullet;
Rectangle bulletRect;
KeyboardState kb;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
screenWidth = graphics.GraphicsDevice.Viewport.Width;
screenHeight = graphics.GraphicsDevice.Viewport.Height;
oldMouse = Mouse.GetState();
speedX = 0;
speedY = 0;
cannonRect = new Rectangle((screenWidth / 2) - 100, (screenHeight / 2) - 100, 100, 100);
bulletRect = new Rectangle(cannonRect.X, cannonRect.Y, 10, 10);
this.IsMouseVisible = true;
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
cannon = Content.Load<Texture2D>("Smoothed Octagon");
bullet = Content.Load<Texture2D>("White Square");
// TODO: use this.Content to load your game content here
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
bulletRect.X += speedX;
bulletRect.Y += speedY;
this.IsMouseVisible = true;
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || kb.IsKeyDown(Keys.Escape))
this.Exit();
// TODO: Add your update logic here
MouseState mouse = Mouse.GetState();
kb = Keyboard.GetState();
if (mouse.LeftButton == ButtonState.Pressed && oldMouse.LeftButton == ButtonState.Released)
{
bulletRect.X += speedX;
bulletRect.Y += speedY;
}
oldMouse = mouse;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
// TODO: Add your drawing code here
spriteBatch.Begin();
spriteBatch.Draw(bullet, bulletRect, Color.White);
spriteBatch.Draw(cannon, cannonRect, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Here's some pseudocode of how to handle bullet velocity and orientation relative to a point.
// On MouseClick
float angle = Math.Atan2(mouseClick.X - player.X, mouseClick.Y - player.Y);
bulletVelocity.X = (Math.Cos(angle) + Math.Sin(angle)) * bulletSpeed;
bulletVelocity.Y = (-Math.Sin(angle) + Math.Cos(angle)) * bulletSpeed;
// On Update Positions
bullet.X += bulletVelocity.X;
bullet.Y += bulletVelocity.Y;
For static entities like cannons, replace "player" with "cannon" and "mouseClick" with "player".
(I'm recalling the positions of Sin and Cos from memory, so hopefully someone can correct me if that's the wrong setup.)

Drawing Multiple Sprites with Different Properties in XNA 4.0

I'm writing a bit of code where I animate a hundred copies of the same sprite onto the screen by creating a sprite class. I want the sprites, an animation of four-ring interlocking rings spinning within each other, to be drawn at a certain height, drop down on the screen, and bounce like a ball, with each bounce being progressively less until it they stop completely. I have managed to get this part done; however, I can't seem to find a way to randomize the acceleration and animation speed of each different sprite. Can someone provide some suggestions to my code?
Game 1.cs
namespace lab_6
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Sprite rings;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferHeight = 600;
graphics.PreferredBackBufferWidth = 800;
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Texture2D rings_texture = Content.Load<Texture2D>("Images/threerings");
//animation
Point frameSize = new Point(75, 75);
Point currentFrame = new Point(0, 0);
Point sheetSize = new Point(6, 8);
int millisecondsPerFrame = 50;
rings = new Sprite(rings_texture, ringsPos,
frameSize, 0, currentFrame, sheetSize, ringsSpeed, millisecondsPerFrame);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <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();
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
// TODO: Add your update logic here
rings.Update(gameTime, Window.ClientBounds);
base.Update(gameTime);
}
/// <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();
rings.Draw(gameTime, spriteBatch);
spriteBatch.End();
}
}
}
Sprite.cs
namespace lab_6
{
public class Sprite
{
//basics
protected Texture2D rings;
protected Vector2 ringsPos = new Vector2(0,0);
protected Color tint = Color.White;
protected Vector2 ringsSpeed = new Vector2(0,0);
protected Vector2 ringsAccel = new Vector2(0, 1);
//animation
protected Point frameSize = new Point(75,75);
protected Point currentFrame = new Point(0, 0);
protected Point sheetSize = new Point(6,8);
//animation timing
protected int timeSinceLastFrame = 0;
protected int millisecondsPerFrame = 50;
const int defaultMillisecondsPerFrame = 16;
//bounding box offset
protected int collisionOffset;
Random r = new Random(DateTime.Now.Millisecond);
public Sprite(Texture2D rings, Vector2 ringsPos, Point frameSize,
int collisionOffset, Point currentFrame, Point sheetSize, Vector2 ringsSpeed,
int millisecondsPerFrame)
{
this.rings = rings;
this.ringsPos = ringsPos;
this.frameSize = frameSize;
this.collisionOffset = collisionOffset;
this.currentFrame = currentFrame;
this.sheetSize = sheetSize;
this.ringsSpeed = ringsSpeed;
this.millisecondsPerFrame = millisecondsPerFrame;
}
public virtual void Update(GameTime gameTime, Rectangle clientBounds)
{
int maxY = (600 - frameSize.Y );
ringsAccel.Y += (byte)r.Next((1 / 10), 1);
ringsSpeed.Y += ringsAccel.Y;
ringsPos.Y += ringsSpeed.Y;
if (ringsPos.Y > maxY)
{
ringsSpeed *= -0.8f;
ringsPos.Y = maxY;
}
//Update animation frame
millisecondsPerFrame = 50;
millisecondsPerFrame *= ((byte)r.Next(1, 10));
timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
if (timeSinceLastFrame > millisecondsPerFrame)
{
timeSinceLastFrame = 0;
++currentFrame.X;
if (currentFrame.X >= sheetSize.X)
{
currentFrame.X = 0;
++currentFrame.Y;
if (currentFrame.Y >= sheetSize.Y)
currentFrame.Y = 0;
}
}
}
public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
for(int i = 0; i < 100; )
{
Vector2 newPos = ringsPos + new Vector2((10 * i), (1 * (byte)r.Next((1/10), 1)));
spriteBatch.Draw(rings, newPos,
new Rectangle(currentFrame.X * frameSize.X,
currentFrame.Y * frameSize.Y,
frameSize.X, frameSize.Y),
tint, 0, Vector2.Zero, 1f, SpriteEffects.None, 0);
i++;
r = new Random(DateTime.Now.Second);
}
}
}
}
Move the constructor for ringSpeed and ringAccel to the constructor and randomize them there.

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.

Having problems drawing animations in monogame

I am trying to create a spaceship with multiple animations (idle, attack, damaged, etc)
But when I'm trying to change the animations I see the first frame of the current animation for a split second on the "old" position (where the animation was changed the last time)
Picture for explanation: http://i.imgur.com/L3O8rsc.png
The red rectangle is supposed to be a health bar.
The class that runs my animations:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace Test
{
class Animation
{
Texture2D spriteStrip;
float scale;
int elapsedTime;
int frameTime;
int frameCount;
int currentFrame;
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();
public int FrameWidth;
public int FrameHeight;
public bool Active;
public bool Looping;
public Vector2 Position;
public void Initialize(Texture2D texture, Vector2 position, int frameWidth, int frameHeight, int frameCount, int frametime, Color color, float scale, bool looping)
{
this.color = color;
this.FrameWidth = frameWidth;
this.FrameHeight = frameHeight;
this.frameCount = frameCount;
this.frameTime = frametime;
this.scale = scale;
Looping = looping;
Position = position;
spriteStrip = texture;
elapsedTime = 0;
currentFrame = 0;
Active = true;
}
public void Update(GameTime gameTime)
{
if (Active == false) return;
elapsedTime += (int)gameTime.ElapsedGameTime.TotalMilliseconds;
if (elapsedTime > frameTime)
{
currentFrame++;
if (currentFrame == frameCount)
{
currentFrame = 0;
if (Looping == false)
Active = false;
}
elapsedTime = 0;
}
sourceRect = new Rectangle(currentFrame * FrameWidth, 0, FrameWidth, FrameHeight);
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);
}
}
}
}
The reason that I wrote the whole code is because I don't know where the problem is.
In my Game1.cs class I have:
Global Variables:
Texture2D playerTexture;
Texture2D playerShootingTexure;
Animation playerAnimation = new Animation();
Animation ShootingAnimation = new Animation();
...
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
playerTexture = Content.Load<Texture2D>("Graphics/Player/PlayerShip");
playerShootingTexure = Content.Load<Texture2D>("Graphics/Player/Player_Shooting");
playerAnimation.Initialize(playerTexture, Vector2.Zero, playerTexture.Width / 5, playerTexture.Height, 5, 50, Color.Wheat, 1f, true);
ShootingAnimation.Initialize(playerShootingTexure, Vector2.Zero, playerShootingTexure.Width / 5, playerShootingTexure.Height, 5, 50, Color.WhiteSmoke, 0.75f, true);
}
Where I change the animations:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// Start drawing
spriteBatch.Begin();
if (Player_Attacking == false)
{
player.PlayerAnimation = playerAnimation;
}
else
{
player.PlayerAnimation = ShootingAnimation;
}
player.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
Note: Player_Attacking is a boolean variable. When 'Space' is pressed, the value of the variable changes to TRUE, when 'Space' is released, value is FALSE
Please help!
Thanks in advance!
And sorry for huge wall of text
I'm a little unclear on the exact issue, so maybe you can help clarify if I'm not understanding.
But based on your picture, it seems when you press space to fire, the player animation should change to light up his gun with blue flames (or w/e it is :)) And it looks like it is doing that, but it's in the wrong position (above the health bar - I see the laser it is shooting is in the right location :))
But then it corrects itself once the shooting is done, as shown by the second picture (no more blue flames).
So this implies the Animation for the Player Shooting is using the wrong position.
Are you:
Updating your Player Shooting Animation's Position in your Player Update?
Calling your Player Shooting Animation's Update in your Player Update?
so you should have this somewhere in your Player Update
PlayerAnimation.Position = Position;
PlayerAnimation.Update(gameTime);
Also, try moving the check for which Player Animation to use in the Update of your Game1.cs:
protected override void Update(GameTime gameTime)
{
if (Player_Attacking == false)
{
player.PlayerAnimation = playerAnimation;
}
else
{
player.PlayerAnimation = ShootingAnimation;
}
player.Update(gameTime);
}

Sprite vibrates. What is wrong?

My enemy sprite vibrates all the time after it has reached the variable endposition. What is wrong? Why is it vibrating?
In addition, the variable next_position is never true. But why? I want that the enemy sprite moves to a new random endposition after it reached the current endposition.
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D enemy;
Vector2 position, endposition;
bool next_position = false;
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);
enemy = Content.Load<Texture2D>("zombie");
Random randomstart = new Random();
position = new Vector2(randomstart.Next(100, 200), randomstart.Next(100, 200));
endposition = new Vector2(randomstart.Next(100, 600), randomstart.Next(100, 400));
}
protected override void Update(GameTime gameTime)
{
float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
Random random = new Random();
position.X += 5 * delta;
position.Y += 3 * delta;
if (next_position == true)
{
endposition = new Vector2(random.Next(100, 600), random.Next(100, 400));
next_position = false;
}
if (Vector2.Dot(endposition - position, endposition - position) > 0 || Vector2.Dot(endposition - position, endposition - position) < 0)
{
Vector2 enemyDirection = Vector2.Normalize(endposition - position) * 100f;
position += enemyDirection * delta;
}
else
{
next_position = true;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(enemy, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
I am slightly confused by what the line
if (Vector2.Dot(endposition - position, endposition - position) > 0 || Vector2.Dot(endposition - position, endposition - position) < 0)
is supposed to do exactly.
From the rest of the code what you are trying to achieve with it, is checking whether the sprite's position is the enemy's position.
What the line actually does is calculating dot products of vectors in opposite directions, which will never be zero, unless the vectors are zero. So in theory this might actually work, but only if the position equals the enemy's position precisely.
However, you are moving the sprite a fixed distance per unit of time, and so it actually does not reach the enemy but overshoots it. Finding itself then on the other side it moves back, where it came from, and overshoots it again. This continues and results in the vibration you describe.
Now, the way the behaviour you want to implement is usually done is calculating the distance between the two objects(sprite and enemy), using Pythagoras' theorem, and then accepting the arrival of the object when the distance is either below a certain threshold(easy but prone to error), or shorter than the distance the object could travel this particular update(in your case, since you move by a normalized vector times 100f * delta, this distance is equal to 100f * delta).
I hope my explanation is helpful.
Of course, feel free to ask for clarifications.
Edit(response to comment):
The limit vector you are creating is relatively meaningless, as it is just the position offset by max_distance in both x and y direction. There is no need for anything like that.
However, the other if() includes pretty much the code you want, check this out:
// first you calculate the distance we can move this update
float max_distance = 100f * delta;
// now, we compare the actual distance to the end position to that maximum
// if the actual distance is larger, then we are not there yet
// otherwise, (if the actual distance is smaller) we will overshoot the target,
// thus we are in fact there! (=close enough to continue)
// (note: we compare the distances squared to avoid a square root,
// which makes this check much faster, which is good practice,
// in case we ever scale this up to more objects)
if ((position - endposition).LengthSquared() > max_distance * max_distance)
{
/* we are not yet there, continue moving! */
}
else
{
/* we are there! */
}
It really is this simple and no other check is needed. Let me know if this works out for you!
It’s better now, but not perfect. The enemy sprite doesn’t vibrate anymore, but it always moves some pixels down right if it has reached the end position. Why does it always move some pixels down right?
The rest works fine.
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D enemy;
Vector2 position, endposition;
bool next_position = false;
int count_nextposition;
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);
enemy = Content.Load<Texture2D>("zombie");
Random randomstart = new Random();
position = new Vector2(randomstart.Next(100, 200), randomstart.Next(100, 200));
endposition = new Vector2(randomstart.Next(100, 600), randomstart.Next(100, 400));
count_nextposition = randomstart.Next(90, 121);
}
protected override void Update(GameTime gameTime)
{
float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
count_nextposition -= 1;
Random random = new Random();
position.X += 5 * delta;
position.Y += 3 * delta;
if (count_nextposition <= 0)
{
if (next_position == true)
{
endposition = new Vector2(random.Next(100, 600), random.Next(100, 400));
next_position = false;
}
float max_distance = 100f * delta;
if ((position - endposition).LengthSquared() > max_distance * max_distance)
{
Vector2 enemyDirection = Vector2.Normalize(endposition - position) * 100f;
position += enemyDirection * delta;
}
else
{
next_position = true;
count_nextposition = random.Next(90, 121);
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(enemy, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}

Categories

Resources