Ground and model are flickering and somewhat invisable - c#

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.

Related

Monogame - Making the camera stop when my player collides

I have come to a position with my 3D game where I am now trying to perfect the camera. What I ultimately want is a working first person camera that stops when it collides with a wall. I assume you do this by having the camera move with a model and have the model collide to stop the camera also, i am just having issues seeing how to do that.
I have the model working so it stops, i just need to lock the camera from moving also. So far this is the code I have, making the model stop with collison:
if (player_health != 0)
{
if (kb.IsKeyDown(Keys.Left))
{
player_x = player_x + 0.05f;
world_player = Matrix.CreateTranslation(new Vector3(player_x, player_y, player_z));
if (IsCollision(ball, world_player, ball, world_spike))
{
player_x = player_x - 0.05f;
world_player = Matrix.CreateTranslation(new Vector3(player_x, player_y, player_z));
player_health = 0;
}
if (IsCollision(ball, world_player, ball, world_bullet[0]))
{
player_health = 0;
}
// use this code for any standard collision
if ((IsCollision(ball, world_player, ball, world_cannon)) || (IsCollision(ball, world_player, ball, walls[0])) || (IsCollision(ball, world_player, ball, walls[1])))
{
player_x = player_x - 0.05f;
world_player = Matrix.CreateTranslation(new Vector3(player_x, player_y, player_z));
}
}
My camera added into the game1 class:
camera = new Camera(this, new Vector3(10f, 3f, 5f), Vector3.Zero, 5f);
Components.Add(camera);
And the camera class itself (I have been told this is rather over complicated? for a camera class, but the simpler ones didnt work):
namespace Game7
{
class Camera : GameComponent
{
private Vector3 cameraPosition;
private Vector3 cameraRotation;
private float cameraSpeed;
private Vector3 cameraLookAt;
private Vector3 mouseRotationBuffer;
private MouseState currentMouseState;
private MouseState previousMouseState;
// Properties
public Vector3 Position
{
get { return cameraPosition; }
set
{
cameraPosition = value;
UpdateLookAt();
}
}
public Vector3 Rotation
{
get { return cameraRotation; }
set
{
cameraRotation = value;
UpdateLookAt();
}
}
public Matrix Projection
{
get;
protected set;
}
public Matrix View
{
get
{
return Matrix.CreateLookAt(cameraPosition, cameraLookAt, Vector3.Up);
}
}
//Constructor
public Camera(Game game, Vector3 position, Vector3 rotation, float speed)
: base(game)
{
cameraSpeed = speed;
// projection matrix
Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.PiOver4,
Game.GraphicsDevice.Viewport.AspectRatio,
0.05f,
1000.0f);
// set camera positiona nd rotation
MoveTo(position, rotation);
previousMouseState = Mouse.GetState();
}
// set Camera's position and rotation
private void MoveTo(Vector3 pos, Vector3 rot)
{
Position = pos;
Rotation = rot;
}
//update the look at vector
private void UpdateLookAt()
{
// build rotation matrix
Matrix rotationMatrix = Matrix.CreateRotationX(cameraRotation.X) * Matrix.CreateRotationY(cameraRotation.Y);
// Look at ofset, change of look at
Vector3 lookAtOffset = Vector3.Transform(Vector3.UnitZ, rotationMatrix);
// update our cameras look at vector
cameraLookAt = cameraPosition + lookAtOffset;
}
// Simulated movement
private Vector3 PreviewMove(Vector3 amount)
{
// Create rotate matrix
Matrix rotate = Matrix.CreateRotationY(cameraRotation.Y);
// Create a movement vector
Vector3 movement = new Vector3(amount.X, amount.Y, amount.Z);
movement = Vector3.Transform(movement, rotate);
return cameraPosition + movement;
}
// Actually move the camera
private void Move(Vector3 scale)
{
MoveTo(PreviewMove(scale), Rotation);
}
// updat method
public override void Update(GameTime gameTime)
{
// smooth mouse?
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
currentMouseState = Mouse.GetState();
KeyboardState ks = Keyboard.GetState();
// input
Vector3 moveVector = Vector3.Zero;
if (ks.IsKeyDown(Keys.W))
moveVector.Z = 1;
if (ks.IsKeyDown(Keys.S))
moveVector.Z = -1;
if (ks.IsKeyDown(Keys.A))
moveVector.X = 1;
if (ks.IsKeyDown(Keys.D))
moveVector.X = -1;
if (moveVector != Vector3.Zero)
{
//normalize it
//so that we dont move faster diagonally
moveVector.Normalize();
// now smooth and speed
moveVector *= dt * cameraSpeed;
// move camera
Move(moveVector);
}
// Handle mouse input
float deltaX;
float deltaY;
if(currentMouseState != previousMouseState)
{
//Cache mouse location
deltaX = currentMouseState.X - (Game.GraphicsDevice.Viewport.Width / 2);
deltaY = currentMouseState.Y - (Game.GraphicsDevice.Viewport.Height / 2);
// smooth mouse ? rotation
mouseRotationBuffer.X -= 0.01f * deltaX * dt;
mouseRotationBuffer.Y -= 0.01f * deltaY * dt;
if (mouseRotationBuffer.Y < MathHelper.ToRadians(-75.0f))
mouseRotationBuffer.Y = mouseRotationBuffer.Y - (mouseRotationBuffer.Y - MathHelper.ToRadians(-75.0f));
if (mouseRotationBuffer.Y > MathHelper.ToRadians(75.0f))
mouseRotationBuffer.Y = mouseRotationBuffer.Y - (mouseRotationBuffer.Y - MathHelper.ToRadians(75.0f));
Rotation = new Vector3(-MathHelper.Clamp(mouseRotationBuffer.Y, MathHelper.ToRadians(-75.0f), MathHelper.ToRadians(75.0f)), MathHelper.WrapAngle(mouseRotationBuffer.X), 0);
deltaX = 0;
deltaY = 0;
}
// Alt + F4 to close now.
// Makes sure the mouse doesn't wander across the screen (might be a little buggy by showing the mouse)
Mouse.SetPosition(Game.GraphicsDevice.Viewport.Width / 2, Game.GraphicsDevice.Viewport.Height / 2);
previousMouseState = currentMouseState;
base.Update(gameTime);
}
}
}
The Preview Move part of the camera class is meant to be where it detects for collision, at least the guide i followed said so, i just dont see how to integrate it. Thanks for any help or input, even if it is just a link to another guide or resource, would be very appreciated!
If your hero model (player) already has move functionality and collision functionality, and you want the camera to follow the model, then you can simplify the camera update tremendously.
Assuming after moving the player, the new position and/or orientation of the player is represented in player_world, simply borrow the location and orientation information stored in the player_world matrix to build a view matrix each frame.
//after moving player and setting its matrix accordingly:
view = Matrix.Invert(player_world);
And that is your complete camera class update. This creates a view matrix that is in the same position as the player and facing the same direction he is. If the player model stops because it hits a wall, then the camera (view matrix) stops too, because it is built from the player's 'stopped' matrix. No need to create a whole class for moving and rotating the camera around when the movement and rotation is the same as the player.
Sometimes the local player model origin would be located at the player's feet or belly and you want the camera up in the head where the eyes are. If so, simply apply something like this:
//after moving player and setting its matrix accordingly:
Matrix camera_world = player_world;
camera_world *= Matrix.CreateTranslation(Vector3.Up * ??f);// set ??f to the height difference between feet and head
view = Matrix.Invert(camera_world);

How to draw a sprite on a moving canvas

I generally figure this sort of thing out normally but I am stumped. I suspect theres a mathematical combination I have missed but anyway.
I have a moving background (currently goes up and down from top to bottom)
I have a moving object (currently moves left and right from the centre of the canvas programatically).
So this is the question, How can I make an object move relatively to the position on the canvas in x and y directions?
Here is my relevant codes:
//Helper method
private Vector2 CalculateDirection()
{
Vector2 calculatedDirection = new Vector2((float)Math.Cos(direction),
(float)Math.Sin(direction));
calculatedDirection.Normalize();
return calculatedDirection;
}
object on canvas
public void Update(GameTime gameTime, Vector2 center)
{
this.currentCentre = originalCentre - center;
//movement logic here
Vector2 calculatedDirection = CalculateDirection();
//deltaTime = ((float)gameTime.ElapsedGameTime.TotalMilliseconds) / 15f;
if (speed > 0f || speed < 0f)
{
///TODO: work this out!!
Velocity = calculatedDirection * speed;
float dir = (originalCentre.Y - currentCentre.Y);
position.X += Velocity.X * (1.0f - 0.9f);
position.Y = dir;// *(1.0f - 0.9f);
}
}
canvas moving methods
private void determinePitchSize()
{
int newHeight = Convert.ToInt32(pitch.Height * ratio);
this.canvas = new Rectangle(
0, posHeight,
device.PresentationParameters.BackBufferWidth,
newHeight
);
}
public void increasePosHeight()
{
posHeight++;
}
public void decreasePosHeight()
{
posHeight--;
}
private void determineDirection()
{
if (!direction)
{
if (this.canvas.Height + this.canvas.Y <= this.screenY)
direction = true;
}
else
{
if (this.canvas.Y >= 0)
direction = false;
}
}
private void useDirection()
{
this.determineDirection();
if (direction)
this.increasePosHeight();
else decreasePosHeight();
}
If you need any more info I can add it here.
Thanks
Ok so thanks to Nico, I was able to answer this.
Vector2 Velocity { get; set; }
Vector2 relative { get; set; }
public void Update(GameTime gameTime, Vector2 center)
{
this.currentCentre = center;
Vector2 calculatedDirection = CalculateDirection();
if (speed > 0f || speed < 0f)
{
Velocity = calculatedDirection * speed * 0.1f;
relative = relative - Velocity;
position = currentCentre + relative;
}
}
The velocity creates object movement to test that it ends up in a different place.
Relative starts at 0,0 (the center) and is adjusted by the velocity.
Position is then set to the centre plus the relative position. which has been set by the velocity.

XNA 2D Cam Zoom not correct

I built a camera based on the class from http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/ . I'm currently making a kinda space-shooter game (but with story and this stuff) and want to have the camera working fine first. But the Zoom doesn't work as I want. I don't really know why, but I hope you can help me ^^
The Issue is, that the sprite moves around for like 30 pixels in some direction. Propbably i didn't set the Position of the main-spaceship properly or the camera is just bugging.
The game is running in full-screen.
Game1 Method:
InputHandler.Update(gameTime, graphics.GraphicsDevice);
World.Camera.Position = new Vector2(Player.Ship.Position.X + Player.Ship.Texture.Width/2, Player.Ship.Position.Y+Player.Ship.Texture.Height/2);
World.Camera.Zoom = InputHandler.ZoomValue;
I add half the size of the texture of the main-spaceship to the cameraposition so that the middle of the texture should be in the middle. It doesn't work either without it..
How I set fullscreen (I know... It's not the way I should have done it but it doesn't work with the normal code.)
graphics.PreferredBackBufferHeight = 10000;
graphics.PreferredBackBufferWidth = 10000;
graphics.ToggleFullScreen();
graphics.PreferMultiSampling = true;
graphics.IsFullScreen = true;
graphics.ApplyChanges();
The InputHandler Class:
public static void Update(GameTime gameTime, GraphicsDevice graphics)
{
_oldKeyboardState = keyboardState;
_oldMouseState = mouseState;
keyboardState = Keyboard.GetState();
mouseState = Mouse.GetState();
MousePosition = new Vector2(mouseState.X, mouseState.Y);
MatrixMousePosition = Vector2.Transform(MousePosition, Matrix.Invert(World.Camera.GetTransformation(graphics)));
OldScrollWheelValue = ScrollWheelValue;
ScrollWheelValue = mouseState.ScrollWheelValue;
if (ScrollWheelValue > OldScrollWheelValue) ZoomValue += 0.1f;
if (ScrollWheelValue < OldScrollWheelValue) ZoomValue -= 0.1f;
ZoomValue = MathHelper.Clamp(ZoomValue, 0.5f, 1.5f);
}
And finally the camera class:
protected float _zoom; // Camera Zoom
public Matrix _transform; // Matrix Transform
public Vector2 _pos; // Camera Position
protected float _rotation; // Camera Rotation
public float Zoom
{
get { return _zoom; }
set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; }
}
public float Rotation
{
get { return _rotation; }
set { _rotation = value; }
}
public Vector2 Position
{
get { return _pos; }
set { _pos = value; }
}
public Camera()
{
_zoom = 1.0f;
_rotation = 0.0f;
_pos = Vector2.Zero;
}
public Matrix GetTransformation(GraphicsDevice graphicsDevice)
{
var viewport = graphicsDevice.Viewport;
_transform =
Matrix.CreateTranslation(new Vector3(-_pos.X*Zoom, -_pos.Y*Zoom, 0)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
Matrix.CreateTranslation(new Vector3(viewport.Width * 0.5f, viewport.Height * 0.5f, 0));
return _transform;
}
I see what you did wrong, this line:
transform = Matrix.CreateTranslation(new Vector3(-_pos.X*Zoom, -_pos.Y*Zoom, 0)) * ....
should be:
transform = Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) * ....
Because right now when you zoom you also translate the image, which is causing the moving sprites.

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 - 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