How to make an enemy face a character - c#

Hey guys ive got this problem where i just can't get my enemy to rotate towards my character
ive been trying for days and have asked around but nothing and so it would be awsome if you could give me some ideas.
this is my enemy class now in this code here everything works fine it does what i want however it faces the mouse and not my character
class Class1
{
Character character = new Character();
EnemyShip blah = new EnemyShip();
Texture2D texture;
Rectangle rectangle;
public Vector2 origin;
public Vector2 velocity;
public Vector2 position;
float rotation;
const float forwardvelocity = 1f;
float friction = 0.1f;
public Vector2 distance;
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("Ships/WarShip");
position = new Vector2(800, 300);
}
public void Update(GameTime gameTime)
{
MouseState mouse = Mouse.GetState();
distance.X = mouse.X - position.X; // these two line are the one i want to
distance.Y = mouse.Y - position.Y; // change however when i change mouse.X to //say character.Position.X my enemy ship moves towards the top left corner of the screen //and not the character
rotation = (float)Math.Atan2(distance.Y, distance.X);
position = velocity + position;
velocity.X = (float)Math.Cos(rotation) * forwardvelocity;
velocity.Y = (float)Math.Sin(rotation) * forwardvelocity;
rectangle = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
origin = new Vector2(rectangle.Width / 2, rectangle.Height / 2);
}
public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
{
spriteBatch.Draw(texture, position, null, Color.White, rotation, origin, 1f, SpriteEffects.None, 0);
}
}
}
And this is my Character class
class Character
{
public Texture2D texture;
public float angle = 0;
public Vector2 velocity;
public Vector2 Position = new Vector2(0, 0);
public float forwardvelocity = 5;
public float friction = 0.03f;
public Vector2 origin;
public Rectangle sourcerectangle;
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("Ships/charactership");
}
public void Update(GameTime gameTime)
{
Position += velocity;
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
velocity.X = (float)Math.Cos(angle ) * forwardvelocity;
velocity.Y = (float)Math.Sin(angle) * forwardvelocity;
}
if (Keyboard.GetState().IsKeyDown(Keys.S))
{
velocity.X = -(float)Math.Cos(angle) * forwardvelocity;
velocity.Y = -(float)Math.Sin(angle) * forwardvelocity;
}
if (Keyboard.GetState().IsKeyDown(Keys.A)) angle -= 0.05f;
if (Keyboard.GetState().IsKeyDown(Keys.D)) angle += 0.05f;
else if (velocity != Vector2.Zero)
{
float i = velocity.X;
float j = velocity.Y;
velocity.X = i -= friction * i;
velocity.Y = j -= friction * j;
}
//--------------------------------------------------------------
}
public void Draw(SpriteBatch spriteBatch)
{
sourcerectangle = new Rectangle(0, 0, texture.Width, texture.Height);
origin = new Vector2(texture.Width / 2, texture.Height / 2);
spriteBatch.Draw(texture, Position, sourcerectangle, Color.White, angle, origin, 1.0f, SpriteEffects.None, 0);
}
}
}

I notice you have a Character variable in your Class1. It is set to new Character() but then nothing else is ever done with it ever. I'm guessing this means your actual Character is within your Game somewhere, and this other Character in this Class1 is a completely different variable entirely. So naturally, using its Position is meaningless.
Since your enemy depends on the Character variable for its own computations, pass in the dependency:
public void Update(Character c, GameTime gameTime)
{
MouseState mouse = Mouse.GetState();
distance.X = c.Position.X - position.X;
distance.Y = c.Position.Y - position.Y;
...
Then in the top level Game or what not:
//your actual character
Character c;
...
//in Game.Update
c.Update(gameTime);
c1.Update(c, gameTime);
Then you can simply remove that Character character = new Character(); in Class1, as it is useless.
There are "lazier" methods such as singletons and other staticness-related methods, but I don't recommend these.

You say that "Class1" is your enemy class...
class Class1
{
Character character = new Character();
EnemyShip blah = new EnemyShip();
Instanciate the character inside your enemy class makes no sense, I think you are not referencing the right character instance in your enemy class.
Seems that the character variable inside your enemy class is never updated, what can be the reason it is always at (0,0)

Related

wander & chase AI code not working

Put together an enemy AI system for an enemy in which it should wander around idly when the player is not within distance to the enemy and when player is within enemy distance it should initiate chase behaviour and chase after player until player has managed to exit out of the enemy's chase radius.
Currently the enemy is able to wonder freely yet when the player comes within proximity of the enemy the enemy will carry on wandering instead of chasing player.
Anyone help me fix this problem?
Code is as follows.
public enum AIState
{
Chasing,
Wander
}
private float maxSpeed;
private float maxRotation;
private float chaseDistance;
private float hysteresis;
private Texture2D texture;
private Vector2 drawingOrigin;
private Vector2 position;
public AIState aiState = AIState.Wander;
private float orientation;
private Random random = new Random();
private Rectangle viewportbounds;
public Rectangle boundingBox;
public Vector2 playerPosition;
private Vector2 heading;
public Virtual_Aliens(Rectangle pos, Rectangle b)
{
position = new Vector2(300, 400);
boundingBox = new Rectangle(pos.X, pos.Y, pos.Width, pos.Height);
viewportbounds = new Rectangle(b.X, b.Y, b.Width, b.Height);
orientation = 0.0f;
heading = new Vector2(0, 0);
maxSpeed = 2.0f;
maxRotation = 0.20f;
hysteresis = 15.0f;
chaseDistance = 250.0f;
Thread.Sleep(200);
random = new Random();
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("images/asteroid");
}
private Vector2 OrientationAsVector(float orien)
{
Vector2 orienAsVect;
orienAsVect.X = (float)Math.Cos(orien);
orienAsVect.Y = (float)Math.Sin(orien);
return orienAsVect;
}
Vector2 wanderPosition = new Vector2();
public void Wander()
{
// the max +/- the agent will wander from its current position
float wanderLimits = 0.5f;
// this defines what proportion of its maxRotation speed the agent will turn
float turnFactor = 0.15f;
// randomly define a new position
wanderPosition.X += MathHelper.Lerp(-wanderLimits, wanderLimits, (float)random.NextDouble());
wanderPosition.Y += MathHelper.Lerp(-wanderLimits, wanderLimits, (float)random.NextDouble());
if (wanderPosition != Vector2.Zero)
{
wanderPosition.Normalize();
}
orientation = TurnToFace(wanderPosition, orientation, turnFactor * maxRotation);
heading = OrientationAsVector(orientation);
position += heading * 0.5f * maxSpeed;
WrapForViewport();
}
private void WrapForViewport()
{
if (position.X < 0)
{
position.X = viewportbounds.Width;
}
else if (position.X > viewportbounds.Width)
{
position.X = 0;
}
if (position.Y < 0)
{
position.Y = viewportbounds.Height;
}
else if (position.Y > viewportbounds.Height)
{
position.Y = 0;
}
}
private float WrapAngle(float radian)
{
while (radian < -MathHelper.Pi)
{
radian += MathHelper.TwoPi;
}
while (radian > MathHelper.Pi)
{
radian -= MathHelper.TwoPi;
}
return radian;
}
private float TurnToFace(Vector2 steering, float currentOrientation, float turnSpeed)
{
float newOrientation;
float desiredOrientation;
float orientationDifference;
float x = steering.X;
float y = steering.Y;
// the desiredOrientation is given by the steering vector
desiredOrientation = (float)Math.Atan2(y, x);
// find the difference between the orientation we need to be
// and our current Orientation
orientationDifference = desiredOrientation - currentOrientation;
// now using WrapAngle to get result from -Pi to Pi
// ( -180 degrees to 180 degrees )
orientationDifference = WrapAngle(orientationDifference);
// clamp that between -turnSpeed and turnSpeed.
orientationDifference = MathHelper.Clamp(orientationDifference, -turnSpeed, turnSpeed);
// the closest we can get to our target is currentAngle + orientationDifference.
// return that, using WrapAngle again.
newOrientation = WrapAngle(currentOrientation + orientationDifference);
return newOrientation;
}
public void Update(GameTime gameTime)
{
if (aiState == AIState.Wander)
{
chaseDistance -= hysteresis / 2;
}
else if (aiState == AIState.Chasing)
{
chaseDistance += hysteresis / 2;
}
float distanceFromPlayer = Vector2.Distance(position, playerPosition);
if (distanceFromPlayer > chaseDistance)
{
aiState = AIState.Wander;
}
else
{
aiState = AIState.Chasing;
}
float currentSpeed;
if (aiState == AIState.Chasing)
{
orientation = TurnToFace(playerPosition, orientation, maxRotation);
currentSpeed = maxSpeed;
}
else if (aiState == AIState.Wander)
{
Wander();
}
}
public void Draw(SpriteBatch spriteBatch)
{
boundingBox.X = (int)position.X;
boundingBox.Y = (int)position.Y;
drawingOrigin = new Vector2(texture.Width / 2, texture.Height / 2);
spriteBatch.Draw(texture, boundingBox, null, Color.White, orientation, drawingOrigin, SpriteEffects.None, 0.0f);
}
public Vector2 PlayerPosition
{
set
{
playerPosition = value;
}
get
{
return playerPosition;
}
}
You get the distance from the player using:
float distanceFromPlayer = Vector2.Distance(position, playerPosition);
But you never actually set the variable playerPosition in your class. So effectively if the enemy is within the chase radius from the point (0,0) they will chase your player, but otherwise will they will just wander around.
I would recommend doing one of two things to solve this issue.
First off you could change the parameters of your Update method to take in the Vector2 of the players position.
A second approach (the one I would personally choose) would be to add a new field (class variable) that is of type Player and then in your Virtual_Aliens' constructor pass in an instance of the player class. That way any time you reference playerPosition you would be able to just say player.Position (or however you have your position field named).

XNA enemy wandering

Can anyone help me. I want my sprite to only move left and right / up and down. Then if the player goes near the enemy in a specific range of X / Y the enemy would follow the Player until the Player escape in a specific range. ( this code can only follow the player in the X coordinate )
class Enemy
{
Texture2D enemy_Texture;
Vector2 enemy_Position;
Vector2 enemy_Origin;
Vector2 enemy_Velocity;
Rectangle enemy_Rectangle;
float enemy_Rotation = 0f;
float enemy_DistanceFromPlayer;
float enemy_OldDistanceFromPlayer;
bool right = true;
public Enemy(Texture2D texture, Vector2 position, float distance)
{
enemy_Texture = texture;
enemy_Position = position;
enemy_DistanceFromPlayer = distance;
enemy_OldDistanceFromPlayer = enemy_DistanceFromPlayer;
}
float player_Position;
public void Update(Player player)
{
enemy_Position += enemy_Velocity;
enemy_Origin = new Vector2(enemy_Texture.Width / 2, enemy_Texture.Height / 2);
player_Position = player.X - enemy_Position.X;
if (player_position<enemy_DistanceFromPlayer)
{
enemy_Position += new Vector2(1, 0);
}
if (player_position > enemy_DistanceFromPlayer)
{
enemy_Position += new Vector2(-1, 0);
}
/*
if (enemy_DistanceFromPlayer <= enemy_OldDistanceFromPlayer)
{
right = true;
enemy_Velocity.X = 1f;
}
else if (enemy_DistanceFromPlayer >= enemy_OldDistanceFromPlayer)
{
right = false;
enemy_Velocity.X = -1f;
}
//if (right) enemy_DistanceFromPlayer += 1; enemy_DistanceFromPlayer -= 1;
if (player_Position >= -20 && player_Position <= 20)
{
if (player_Position < -1)
{
enemy_Velocity.X = 1f;
}
else if (player_Position > 1)
{
enemy_Velocity.X = -1f;
}
else if (player_Position == 0)
{
enemy_Velocity.X = 0f;
}
}*/
}
public void Draw(SpriteBatch spritebatch)
{
if (enemy_Velocity.X > 0)
{
spritebatch.Draw(enemy_Texture, enemy_Position, null, Color.Wheat, enemy_Rotation, enemy_Origin, 1f,SpriteEffects.FlipHorizontally, 0f);
}
else
{
spritebatch.Draw(enemy_Texture, enemy_Position, null, Color.Wheat, enemy_Rotation, enemy_Origin, 1f, SpriteEffects.None, 0f);
}
}
}
An easier way would be to just go by distance instead of handling X/Y independently. Define a chase_threshold somewhere like a class-level field.
const float chase_threshold = 4f; // Chase player if less than 4 squares away
Then this could be your chase logic:
float distance = Vector2.Distance(player, enemy);
if (distance < chase_threshold)
{
Vector2 direction;
// Should we go left/right or up/down?
if (Math.Abs(player.X - enemy_Position.X) > Math.Abs(player.Y - enemy_Position.Y)
direction = new Vector2(player.X - enemy_Position.X, 0);
else
direction = new Vector2(0, player.Y - enemy_Position.Y);
enemy_Position += direction * enemy_Velocity;
}
This is now a working Code, but the sprite keeps following me. I wanted to know how to make it stop.
class Enemy
{
Texture2D enemy_Texture;
Vector2 enemy_Position;
Vector2 enemy_Origin;
Vector2 enemy_Velocity;
Rectangle enemy_Rectangle;
float enemy_Rotation = 0f;
float enemy_DistanceFromPlayer;
float enemy_OldDistanceFromPlayer;
bool right = true;
public Enemy(Texture2D texture, Vector2 position, float distance)
{
enemy_Texture = texture;
enemy_Position = position;
enemy_DistanceFromPlayer = distance;
enemy_OldDistanceFromPlayer = enemy_DistanceFromPlayer;
}
Vector2 player_Position;
Vector2 distanceFromTarget;
float rangeToMove = 4f; // this is the range where the enemy will start to move, if the player get near it
float distanceFromPlayer;
public void Update(Player player, GameTime gameTime)
{
player_Position = new Vector2(player.X, player.Y);
distanceFromTarget = player_Position - enemy_Position;
distanceFromPlayer = Vector2.Distance(player_Position, enemy_Position);
distanceFromTarget.Normalize();
if (rangeToMove<distanceFromPlayer)
{
enemy_Position += distanceFromTarget * (float)gameTime.ElapsedGameTime.TotalMilliseconds * .1f;
}
}
I'm assuming your .1f; is referring to the speed your enemy is chasing the player at.
If so, if you add in a speed variable where your .1f is for your enemy.
Try adding to your
float speed;
if (rangeToMove<distanceFromPlayer)
{
enemy_Position += distanceFromTarget * (float)gameTime.ElapsedGameTime.TotalMilliseconds * speed;
}
else
{
speed = 0.0f;
}

I tried to make the camera to move the same way in first person game but its not moving why?

This is my Game1.cs code i marked the areas of the camera movement code parts:
Added the camera code in my Game1.cs i used the riemers tutorials camera code here:
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series4/Mouse_camera.php
I also tried the code in the bottom by user31911 but same results the camera pointer/cursor is dancing/shaking in the middle and not responding.
Im trying to use the Camera class to move the camera around using the mouse.
http://pastebin.com/SF3iiftq
In the constructor i have this line:
viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraRotatedUpVector);
If i use this line instead assign the viewMatrix variable later in my code then i dont see the terrain at all.
And the big main problem is that the mouse is not responding at all what i get is the mouse pointer dancing/shaking in the middle.
The only thing that responding is my ProcessInput method i did the keys there are working but the method ProcessInputCamera the kkeys and mouse there are not resopnding when im moving the camera the mouse cursor is shaking/dancing in the middle.
I can't figure out why it happen.
But the mouse is not moving the camera.
Pls edit your Question! There are to many unnecessary informations...
here is my camera (1st person) class
class Camera
{ // up in here normal needed vars
public Vector3 cameraPosition;
public float moveSpeed, rotateSpeed;
public bool playing = true;
public GraphicsDevice device;
public Matrix view, projection;
Matrix rotation;
float yaw = 0;
float pitch = 0;
int oldX, oldY;
public Camera(Vector3 cameraPosition, float moveSpeed, float rotateSpeed, float filedOfView, GraphicsDevice device, float PerspectiveFieldOfView)
{
this.cameraPosition = cameraPosition;
this.moveSpeed = moveSpeed;
this.rotateSpeed = rotateSpeed;
this.device = device;
view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up);
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(PerspectiveFieldOfView), device.Viewport.AspectRatio, 0.1f, filedOfView);
ResetMouseCursor();
}
public void Update()
{
KeyboardState kState = Keyboard.GetState(); // make is able to use your keys
Vector3 v = new Vector3(0, 0, -50) * moveSpeed; // let you permanent walk
move(v); // isnt essential could be deleted if you wont that
}
if (kState.IsKeyDown(Keys.W))
{
Vector3 v = new Vector3(0, 0, -100) * moveSpeed;
move(v);
}
if (kState.IsKeyDown(Keys.S))
{
Vector3 v = new Vector3(0, 0, 50) * moveSpeed;
move(v);
}
if (kState.IsKeyDown(Keys.A))
{
Vector3 v = new Vector3(-50, 0, 0) * moveSpeed;
move(v);
projection = Matrix.
}
if (kState.IsKeyDown(Keys.D))
{
Vector3 v = new Vector3(50, 0, 0) * moveSpeed;
move(v);
}
pitch = MathHelper.Clamp(pitch, -1.5f, 1.5f);
MouseState mState = Mouse.GetState();
int dx = mState.X - oldX; /* is for turning you objekt / camera
yaw -= rotateSpeed * dx; *
*
int dy = mState.Y - oldY; *
pitch -= rotateSpeed * dy; */
ResetMouseCursor(); // this makes your mouse "dancing" in the middle
UpdateMatrices();
}
private void ResetMouseCursor() // mouse settings for the camera
{
int centerX = device.Viewport.Width / 2;
int centerY = device.Viewport.Height / 2;
Mouse.SetPosition(centerX, centerY);
oldX = centerX;
oldY = centerY;
}
private void UpdateMatrices() //standart camera things
{
rotation = Matrix.CreateRotationY(yaw) * Matrix.CreateRotationX(pitch);
Vector3 transformedReference = Vector3.Transform(new Vector3(0, 0, -1), rotation);
Vector3 lookAt = cameraPosition + transformedReference;
view = Matrix.CreateLookAt(cameraPosition, lookAt, Vector3.Up);
}
public void move(Vector3 v) // is the self programmed method to let you move
{
Matrix yRotation = Matrix.CreateRotationY(yaw);
v = Vector3.Transform(v, yRotation);
cameraPosition += v;
}
}
It's pretty standart, but good.
In most cases this class is all you need for the Camera and it's configuration.
Rewrite/Fix it, like however you need it...
Tipp: You could also consider a Arc-Ball-Cam..

Ground and model are flickering and somewhat invisable

I really don't know whats is going wrong here. The game seams to be drawing funny. The first thing I notice is that when the player moves, the camera move before the avatar does so the camera comes out of the avatars head a bit. Then I noticed that when you look at the avatar from the side you can see though his shoulder and into his cheast cavity (it does not do this in the animation player I build and also in Maya). The next thing I notice is when the player moves forward, the ground starts to flicker. Am I calling the draw method wrong or something?
here is the camera class I am using
public class Camera : Microsoft.Xna.Framework.GameComponent
{
//Cam Matrices
//viw is composed of position, direction, and up vectors
public Matrix view { get; protected set; }
public Matrix projection { get; protected set; }
//to move the camera
//used to recreate view matrix each frame
public Vector3 cameraPosition { get; protected set; }
public Vector3 cameraDirection; //not the target/ point camera is looking at a relative direction camrea is faceing
//to find target add the cameraPosition and cameraDirection togeater
public Vector3 cameraUp;
public Vector3 target;
//camera controls
float speed = 3;
MouseState prevMouseState;
// Pi/180 = 1 degree
// Max yaw/pitch variables
//this is for moving the head only not the body
float totalYaw = MathHelper.PiOver2;
public float currentYaw = 0;
float totalPitch = MathHelper.PiOver2;
public float currentPitch = 0;
public float leftTrigYaw;
public float rightTrigYaw;
//constructor
public Camera(Game game, Vector3 pos, Vector3 target, Vector3 up)
: base(game)
{
//build camera view matrix
cameraPosition = pos;
cameraDirection = target - pos;
cameraDirection.Normalize(); //Convert to magintue 1
//make it easy to apply differt speeds to movement of camera
cameraUp = up;
CreateLookAt();
projection = Matrix.CreatePerspectiveFieldOfView
(
MathHelper.PiOver4,
(float)Game.Window.ClientBounds.Width / (float)Game.Window.ClientBounds.Height,
1, 3000);
}
private void CreateLookAt()
{
//middle variable is the target!
view = Matrix.CreateLookAt(cameraPosition, cameraPosition + cameraDirection, cameraUp);
}
public override void Initialize()
{
Mouse.SetPosition(Game.Window.ClientBounds.Width / 2,
Game.Window.ClientBounds.Height / 2);
prevMouseState = Mouse.GetState();
base.Initialize();
}
public override void Update(GameTime gameTime)
{
GamePadState currentState = GamePad.GetState(PlayerIndex.One);
//move forward
if (currentState.ThumbSticks.Left.Y > 0 || Keyboard.GetState().IsKeyDown(Keys.W))
{
//move just on x and x axis Y is controled other places.
cameraPosition += new Vector3(cameraDirection.X, 0, cameraDirection.Z) * speed;
}
//move backward
if (currentState.ThumbSticks.Left.Y < 0 || Keyboard.GetState().IsKeyDown(Keys.S))
{
//move just on x and x axis Y is controled other places.
cameraPosition -= new Vector3(cameraDirection.X, 0, cameraDirection.Z) * speed;
}
//move left
if (currentState.ThumbSticks.Left.X < 0 || Keyboard.GetState().IsKeyDown(Keys.A))
{
//cross product of the up and direction vectors can give the side direction
cameraPosition += Vector3.Cross(cameraUp, cameraDirection) * speed;
}
//move right
if (currentState.ThumbSticks.Left.X > 0 || Keyboard.GetState().IsKeyDown(Keys.D))
{
cameraPosition -= Vector3.Cross(cameraUp, cameraDirection) * speed;
}
//mouse movements
// Yaw rotation
float yawAngle = (-MathHelper.PiOver4 / 150) *
(Mouse.GetState().X - prevMouseState.X);
float padYaw = (-MathHelper.PiOver2 / 50) *
(currentState.ThumbSticks.Right.X);
if (Math.Abs(currentYaw + yawAngle) < totalYaw)
{
cameraDirection = Vector3.Transform(cameraDirection,
Matrix.CreateFromAxisAngle(cameraUp, yawAngle));
currentYaw += yawAngle;
}
//rotate left and right
if (currentState.ThumbSticks.Right.X < 0 || currentState.ThumbSticks.Right.X > 0)
{
if (Math.Abs(currentYaw + padYaw) < totalYaw)
{
cameraDirection = Vector3.Transform(cameraDirection,
Matrix.CreateFromAxisAngle(cameraUp, padYaw));
currentYaw += padYaw;
}
}
leftTrigYaw = (MathHelper.PiOver2 / 50) *
(currentState.Triggers.Left);
if (currentState.Triggers.Left > 0.0f)
{
cameraDirection = Vector3.Transform(cameraDirection,
Matrix.CreateFromAxisAngle(cameraUp, leftTrigYaw));
}
rightTrigYaw = (-MathHelper.PiOver2 / 50) *
(currentState.Triggers.Right);
if (currentState.Triggers.Right > 0.0f)
{
cameraDirection = Vector3.Transform(cameraDirection,
Matrix.CreateFromAxisAngle(cameraUp, rightTrigYaw));
}
// Pitch rotation
float pitchAngle = (MathHelper.PiOver4 / 150) *
(Mouse.GetState().Y - prevMouseState.Y);
float padPitch = (-MathHelper.PiOver2 / 50) *
(currentState.ThumbSticks.Right.Y);
if (Math.Abs(currentPitch + pitchAngle) < totalPitch)
{
cameraDirection = Vector3.Transform(cameraDirection,
Matrix.CreateFromAxisAngle(
Vector3.Cross(cameraUp, cameraDirection),
pitchAngle));
currentPitch += pitchAngle;
}
if (currentState.ThumbSticks.Right.Y < 0 || currentState.ThumbSticks.Right.Y > 0)
{
if (Math.Abs(currentPitch + padPitch) < totalPitch)
{
cameraDirection = Vector3.Transform(cameraDirection,
Matrix.CreateFromAxisAngle(
Vector3.Cross(cameraUp, cameraDirection),
padPitch));
currentPitch += padPitch;
}
}
//reset mouse state
target = cameraPosition + cameraDirection;
prevMouseState = Mouse.GetState();
//for testing only!! get rid of this when done
if (currentState.Buttons.A == ButtonState.Pressed)
{
//fly upwar
cameraPosition += new Vector3(0, 15, 0);
}
if (currentState.Buttons.B == ButtonState.Pressed)
{
//fly upwar
cameraPosition -= new Vector3(0, 15, 0);
}
//call camera creat look at method to build new view matrix
CreateLookAt();
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
{
Game.Exit();
}
base.Update(gameTime);
}
}
}
I am also using a custom model handler to draw the ground and the avatar
public class CModel
{
public Vector3 Position { get; set; }
public Vector3 Rotation { get; set; }
public Vector3 Scale { get; set; }
public Model Model { get; private set; }
private Matrix[] modelTransforms;
private GraphicsDevice graphicsDevice;
public CModel(Model Model, Vector3 Position, Vector3 Rotation,
Vector3 Scale, GraphicsDevice graphicsDevice)
{
this.Model = Model;
modelTransforms = new Matrix[Model.Bones.Count];
Model.CopyAbsoluteBoneTransformsTo(modelTransforms);
this.Position = Position;
this.Rotation = Rotation;
this.Scale = Scale;
this.graphicsDevice = graphicsDevice;
}
public void Draw(Matrix View, Matrix Projection)
{
// Calculate the base transformation by combining
// translation, rotation, and scaling
Matrix baseWorld = Matrix.CreateScale(Scale)
* Matrix.CreateFromYawPitchRoll(
Rotation.Y, Rotation.X, Rotation.Z)
* Matrix.CreateTranslation(Position);
foreach (ModelMesh mesh in Model.Meshes)
{
Matrix localWorld = modelTransforms[mesh.ParentBone.Index]
* baseWorld;
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
BasicEffect effect = (BasicEffect)meshPart.Effect;
effect.World = localWorld;
effect.View = View;
effect.Projection = Projection;
effect.EnableDefaultLighting();
}
mesh.Draw();
}
}
}
}
I dont know where the problem is originating from but these are the only two things that I can think of that would give the problem.
Thanks for any help with this.
Here is what is going on with the model. I am sure that the normal are right in maya because I used the simple model drawer that Microsoft has up on the tutorials but then you can somewhat see though the guys shoulder and arm. I could not get a picture of the ground flickering because it happens too fast to really screen capture it.But every time i move the camera, the ground jumps up and down a lot. and then stops when I stop moving the camera to look around. am I not calling the the camera.Update() method because its a game component and is linked up with the game1 class.
This is how I am drawing the models
it is a draw method in the custom model class
public void Draw(Matrix View, Matrix Projection)
{
// Calculate the base transformation by combining
// translation, rotation, and scaling
Matrix baseWorld = Matrix.CreateScale(Scale)
* Matrix.CreateFromYawPitchRoll(
Rotation.Y, Rotation.X, Rotation.Z)
* Matrix.CreateTranslation(Position);
foreach (ModelMesh mesh in Model.Meshes)
{
Matrix localWorld = modelTransforms[mesh.ParentBone.Index]
* baseWorld;
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
BasicEffect effect = (BasicEffect)meshPart.Effect;
effect.World = localWorld;
effect.View = View;
effect.Projection = Projection;
effect.EnableDefaultLighting();
}
mesh.Draw();
}
}
For the artifacts on the model: The model doesn't look like it's being rendered properly. Your DrawPrimitives call probably isn't feeding the graphics card the right data (either your vertex/index buffers are filled in wrong or you have the primitive type/count wrong). Try rendering it in wireframe mode, you should be able to see the triangles that are getting distorted, producing these artifacts.
As for the ground - I will look some more through the code and see if I can think of anything.

XNA - Pong Clone - Reflecting ball when it hits a wall?

I'm trying to make the ball bounce off of the top and bottom 'Walls' of my UI when creating a 2D Pong Clone.
This is my Game.cs
public void CheckBallPosition()
{
if (ball.Position.Y == 0 || ball.Position.Y >= graphics.PreferredBackBufferHeight)
ball.Move(true);
else
ball.Move(false);
if (ball.Position.X < 0 || ball.Position.X >= graphics.PreferredBackBufferWidth)
ball.Reset();
}
At the moment I'm using this in my Ball.cs
public void Move(bool IsCollidingWithWall)
{
if (IsCollidingWithWall)
{
Vector2 normal = new Vector2(0, 1);
Direction = Vector2.Reflect(Direction,normal);
this.Position += Direction;
Console.WriteLine("WALL COLLISION");
}
else
this.Position += Direction;
}
It works, but I'm using a manually typed Normal and I want to know how to calculate the normal of the top and bottom parts of the screen?
Well, this is how I would handle it
public void CheckBallPositionAndMove()
{
if (ball.Position.Y <= 0 || ball.Position.Y >= graphics.PreferredBackBufferHeight)
ball.HandleWallCollision();
ball.Move();
if (ball.Position.X < 0 || ball.Position.X >= graphics.PreferredBackBufferWidth)
ball.Reset();
}
//In Ball.cs:
private void HandleWallCollision(Vector2 normal)
{
Direction.Y *= -1; //Reflection about either normal is the same as multiplying y-vector by -1
}
private void Move()
{
this.Position += Direction;
}
Note however that using this "discrete" collision detection, you wait until after the ball has moved past the top/bottom of the screen to detect a collision; collisions that occur "between" frames may be noticably off, especially if the ball is moving fast. This is especially a problem if you are using this collision-detection method to detect collision with a paddle, since, if the ball is moving fast enough, it is possible for the ball to move right through the paddle!
The solution to this problem is to use what is known as Continuous Collision Detection. CCD is usually significantly more complex than discrete collision detection; fortunately, pong is simple enough that doing CCD would only be slightly more complex. However, you'd still need a solid grasp of high-school algebra to solve the equations.
If you are still interested, there is a good explaination of CCD in this lecture, and this GameDev article goes a bit more in-depth. There are also many questions relating to it on SO.
You could change boolean IsCollidingWithWall with some enum like:
enum CollideType
{
None,
Vertical,
Horizontal
}
and check this type when creating normal.
Each of the boundaries in your world is a line. One side of the line is solid and the other is not. The normal you are trying to compute is one part of the equation for that line. It points toward the non-solid side of the line. The other part of the line equation is the distance from the line to the origin. The equation for the line can be found from two points on that line. You can define these two points based on the coordinates in your game space where you want a wall.
The normal is computed by rotating the line segment defined by the two points 90 degrees and then Normalizing.
public static Vector2 ComputeNormal(Vector2 point1, Vector2 point2)
{
Vector2 normal = new Vector2();
normal.X = point2.Y - point1.Y;
normal.Y = point1.X - point2.X;
normal.Normalize();
return normal;
}
You are using the preferred back buffer width and height to define your world space so your would use these to define the points used to compute the normals.
float left = 0.0f;
float right = graphics.PreferredBackBufferWidth;
float top = 0.0f;
float bottom = graphics.PreferredBackBufferHeight;
Vector2 topNormal = ComputeNormal(new Vector2(left, top), new Vector2(right, top));
Vector2 bottomNormal = ComputeNormal(new Vector2(right, bottom), new Vector2(left, bottom));
Note that the points must be given in clockwise order so that the normal points in the correct direction.
The following XNA 4.0 program demonstrates these concepts in use:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace WindowsGame
{
public class Ball
{
const int DIAMETER = 40;
const float RADIUS = DIAMETER * 0.5f;
const float MASS = 0.25f;
const int PIXELS = DIAMETER * DIAMETER;
static readonly uint WHITE = Color.White.PackedValue;
static readonly uint BLACK = new Color(0, 0, 0, 0).PackedValue;
Texture2D m_texture;
Vector2 m_position;
Vector2 m_velocity;
public Ball(GraphicsDevice graphicsDevice)
{
m_texture = new Texture2D(graphicsDevice, DIAMETER, DIAMETER);
uint[] data = new uint[PIXELS];
for (int i = 0; i < DIAMETER; i++)
{
float iPosition = i - RADIUS;
for (int j = 0; j < DIAMETER; j++)
{
data[i * DIAMETER + j] = new Vector2(iPosition, j - RADIUS).Length() <= RADIUS ? WHITE : BLACK;
}
}
m_texture.SetData<uint>(data);
}
public float Radius
{
get
{
return RADIUS;
}
}
public Vector2 Position
{
get
{
return m_position;
}
}
public Vector2 Velocity
{
get
{
return m_velocity;
}
set
{
m_velocity = value;
}
}
public void ApplyImpulse(Vector2 impulse)
{
Vector2 acceleration = impulse / MASS;
m_velocity += acceleration;
}
public void Update(float dt)
{
m_position += m_velocity; // Euler integration - innaccurate and unstable but it will do for this simulation
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(m_texture, DrawRectangle, Color.White);
}
private Rectangle DrawRectangle
{
get
{
int x = (int)Math.Round(m_position.X - RADIUS);
int y = (int)Math.Round(m_position.Y - RADIUS);
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
}
public class Boundary
{
private Vector2 m_point1;
private Vector2 m_point2;
private Vector2 m_normal;
private float m_distance;
public Boundary(Vector2 point1, Vector2 point2)
{
m_point1 = point1;
m_point2 = point2;
m_normal = new Vector2();
m_normal.X = point2.Y - point1.Y;
m_normal.Y = point1.X - point2.X;
m_distance = point2.X * point1.Y - point1.X * point2.Y;
float invLength = 1.0f / m_normal.Length();
m_normal *= invLength;
m_distance *= invLength;
}
public Vector2 Normal
{
get
{
return m_normal;
}
}
public void PerformCollision(Ball ball)
{
float distanceToBallCenter = DistanceToPoint(ball.Position);
if (distanceToBallCenter <= ball.Radius)
{
ResolveCollision(ball);
}
}
public void ResolveCollision(Ball ball)
{
ball.Velocity = Vector2.Reflect(ball.Velocity, m_normal);
}
private float DistanceToPoint(Vector2 point)
{
return
m_normal.X * point.X +
m_normal.Y * point.Y +
m_distance;
}
}
public class World
{
Boundary m_left;
Boundary m_right;
Boundary m_top;
Boundary m_bottom;
public World(float left, float right, float top, float bottom)
{
m_top = new Boundary(new Vector2(right, top), new Vector2(left, top));
m_right = new Boundary(new Vector2(right, bottom), new Vector2(right, top));
m_bottom = new Boundary(new Vector2(left, bottom), new Vector2(right, bottom));
m_left = new Boundary(new Vector2(left, top), new Vector2(left, bottom));
}
public void PerformCollision(Ball ball)
{
m_top.PerformCollision(ball);
m_right.PerformCollision(ball);
m_bottom.PerformCollision(ball);
m_left.PerformCollision(ball);
}
}
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Matrix viewMatrix;
Matrix inverseViewMatrix;
Ball ball;
World world;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
ball = new Ball(GraphicsDevice);
float right = Window.ClientBounds.Width * 0.5f;
float left = -right;
float bottom = Window.ClientBounds.Height * 0.5f;
float top = -bottom;
world = new World(left, right, top, bottom);
viewMatrix = Matrix.CreateTranslation(Window.ClientBounds.Width * 0.5f, Window.ClientBounds.Height * 0.5f, 0.0f);
inverseViewMatrix = Matrix.Invert(viewMatrix);
base.Initialize();
}
private void ProcessUserInput()
{
MouseState mouseState = Mouse.GetState();
Vector2 mousePositionClient = new Vector2((float)mouseState.X, (float)mouseState.Y);
Vector2 mousePositionWorld = Vector2.Transform(mousePositionClient, inverseViewMatrix);
if (mousePositionWorld != ball.Position)
{
Vector2 impulse = mousePositionWorld - ball.Position;
impulse *= 1.0f / impulse.LengthSquared();
ball.ApplyImpulse(-impulse);
}
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
ProcessUserInput();
ball.Update(dt);
world.PerformCollision(ball);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, viewMatrix);
ball.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Wouldn't you just take the position of the ball minus the position of the wall and then normalize that vector to get what you needed without hardcoding it?
Vector2 normal = Position - WallPosition;
normal.Normalize();
The rest of your code should just work the same.

Categories