Sign in to follow this  
MrMorg

XNA Simple NPC movement is wonky

Recommended Posts

MrMorg    100
Hello Everyone! I'm embarking on a big group project as a programmer sometime in august and in preparation am making several simple games in XNA. However, this one I'm having a little trouble with. An NPC is supposed to move in a predictable pattern by way of waypoints, represented by 2 Vector2 variables. In short, I want my character to move from her starting position to point 1, then to point 2, and then back to the point 1 and repeat. However, when she gets to point 1, she gets 'stuck' there and jiggles around. Here is my source code so far:

[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 LetSee
{

public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Vector2 backPosition = new Vector2(0,0);
Texture2D back;
Vector2 mousepos;
Vector2 Scoutp = new Vector2(0, 0);
Texture2D Scouti;
Vector2 ScoutSpeed = new Vector2(5, 5);
bool eaten= false;
Texture2D Carriei;
Vector2 Carriep = new Vector2(300, 300);
int CarrieSpeed = 2;
Vector2 idlePoint = new Vector2(152, 124);
Vector2 idlePoint2 = new Vector2(111, 400);
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}


protected override void Initialize()
{

graphics.PreferredBackBufferHeight=500;
graphics.PreferredBackBufferWidth = 500;
graphics.IsFullScreen = false;
graphics.ApplyChanges();
Window.Title = "Prototype";
base.Initialize();

}


protected override void LoadContent()
{

spriteBatch = new SpriteBatch(GraphicsDevice);
back = this.Content.Load<Texture2D>("BackGroundEngi");
Scouti = this.Content.Load<Texture2D>("Scout");
Carriei = this.Content.Load<Texture2D>("car");


}


protected override void UnloadContent()
{

}


protected override void Update(GameTime gameTime)
{

if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();


bool idle = true;
bool idle2 = false;
Rectangle ScoutRec = new Rectangle((int)Scoutp.X, (int)Scoutp.Y, Scouti.Width, Scouti.Height);
Rectangle CarrieRec = new Rectangle((int)Carriep.X, (int)Carriep.Y, Carriei.Width, Carriei.Height);
MouseState ms = Mouse.GetState();
#if WINDOWS
mousepos.X=ms.X;
mousepos.Y=ms.Y;
#endif
KeyboardState moveme = Keyboard.GetState();
if (moveme.IsKeyDown(Keys.Up))
{
Scoutp.Y -= ScoutSpeed.X;
}
else if (moveme.IsKeyDown(Keys.Down))
{
Scoutp.Y += ScoutSpeed.X;
}
else if (moveme.IsKeyDown(Keys.Right))
{
Scoutp.X += ScoutSpeed.Y;
}
else if (moveme.IsKeyDown(Keys.Left))
{
Scoutp.X -= ScoutSpeed.Y;
}
if (idle == true && idle2==false)
{
if (Carriep == idlePoint)
{

idle = false;
idle2 = true;
Carriep.X = 22;
Carriep.Y = 200;
}
if (Carriep.Y >= idlePoint.Y)
{
Carriep.Y -= CarrieSpeed;
}
else if (Carriep.Y <= idlePoint.Y)
{
Carriep.Y += CarrieSpeed;
}
if (Carriep.X >= idlePoint.X)
{
Carriep.X -= CarrieSpeed;
}
else if (Carriep.X <= idlePoint.X)
{
Carriep.X += CarrieSpeed;
}

}
if (idle2 == true && idle==false)
{
if (Carriep == idlePoint2)
{
idle = true;
idle2 = false;
Carriep.X = 222;
Carriep.Y = 66;
}
if (Carriep.Y >= idlePoint2.Y)
{
Carriep.Y -= CarrieSpeed;
}
else if (Carriep.Y <= idlePoint2.Y)
{
Carriep.Y += CarrieSpeed;
}
if (Carriep.X >= idlePoint2.X)
{
Carriep.X -= CarrieSpeed;
}
else if (Carriep.X <= idlePoint2.X)
{
Carriep.X += CarrieSpeed;
}

}
if (CarrieRec.Intersects(ScoutRec))
{
eaten = true;
}

base.Update(gameTime);

}


protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(back, backPosition, Color.White);
spriteBatch.Draw(Scouti, Scoutp, Color.Pink);
spriteBatch.End();
if (eaten == false)
{
spriteBatch.Begin();
spriteBatch.Draw(Carriei, Carriep, Color.White);
spriteBatch.End();
}
base.Draw(gameTime);
}
}
}
[/code]

I tried to make it so that she 'teleports' away from the waypoint once she reaches it, but that didn't work.

Share this post


Link to post
Share on other sites
l0k0    278
I see a number of problems that may be causing this issue. One, is that there are no tolerances at all.
[quote name='MrMorg' timestamp='1311200326' post='4838165']
[code]
if (Carriep == idlePoint)
{
idle = false;
idle2 = true;
Carriep.X = 22;
Carriep.Y = 200;
}
[/code]
[/quote]
Floating point error will inevitably accumulate, and if the value is off by just one bit, this section of code will never be hit. Try using the distance formula to see if the point is within an appropriate tolerance. Using squared values is better for performance, but for now, try using:
[code]
if (Vector2.Distance(Carriep, idlePoint) <= 2.0f)
[/code]
You could of course replace this with a more appropriate tolerance value.

Secondly, your code will seek even if it is at the correct coordinates on a given axis because you are using less than/greater than OR EQUAL comparisons.
[quote name='MrMorg' timestamp='1311200326' post='4838165']
[code]
if (Carriep == idlePoint)
{

idle = false;
idle2 = true;
Carriep.X = 22;
Carriep.Y = 200;
} // consider putting an else here {
if (Carriep.Y >= idlePoint.Y)
{
Carriep.Y -= CarrieSpeed;
}
else if (Carriep.Y <= idlePoint.Y)
{
Carriep.Y += CarrieSpeed;
}
if (Carriep.X >= idlePoint.X)
{
Carriep.X -= CarrieSpeed;
}
else if (Carriep.X <= idlePoint.X)
{
Carriep.X += CarrieSpeed;
}
// end else here
[/code]
[/quote]
Think about this logically for a second. If the target.X is at 400 and you are positioned at 400 on the X-axis, do you want to move by 2 units on that axis? Change your <= to < comparisons, and your >= to > comparisons.

My guess is that the main culprit is the first tolerance issue I discussed above. Since you are using absolute comparisons, I think your code never registers as reaching "idlePoint" and continuously seeks it. It's easy to test for yourself though. Inside the comparison, put a write line statement like so:
[code]
if (Carriep == idlePoint)
{
idle = false;
idle2 = true;
Carriep.X = 22;
Carriep.Y = 200;
Console.WriteLine("Idle Point Reached!");
}
[/code]
I suspect this will never be printed in your console window. Note: if you don't have a console at all, you'll need to change your project settings from a WindowsApplication to a ConsoleApplication. If you're looking for something more challenging you could try Googling Steering Behaviors, specifically Seek, Arrival, and Path Following.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this