How to make a player stay within bounds of world with 2D Camera
- by Craig
Im creating a simple top down survival game. At the moment, i have the sprite which is a ship and moves by rotating left or right then going forward in that direction.
I have implemented a 2D camera, its always centered on the player.
However, when i move towards the bounds of the world that the sprite is in it just keeps on going :(
How to i sort it that it stops at the edge of the world and cant go beyond it?
Cheers :)
Below is the main game class
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace GamesCoursework_1
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
// player variables
Texture2D Ship;
Vector2 Ship_Position;
float Ship_Rotation = 0.0f;
Vector2 Ship_Origin;
Vector2 Ship_Velocity;
const float tangentialVelocity = 4f;
float friction = 0.05f;
static Point CameraViewport = new Point(800, 800);
Camera2d cam = new Camera2d((int)CameraViewport.X, (int)CameraViewport.Y);
//Size of world
static Point worldSize = new Point(1600, 1600);
// Screen variables
static Point worldCenter = new Point(worldSize.X / 2, worldSize.Y / 2);
Rectangle playerBounds = new Rectangle(CameraViewport.X / 2, CameraViewport.Y / 2, worldSize.X - CameraViewport.X, worldSize.Y - CameraViewport.Y);
Rectangle worldBounds = new Rectangle(0, 0, worldSize.X, worldSize.Y);
Texture2D background;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = CameraViewport.X;
graphics.PreferredBackBufferHeight = CameraViewport.Y;
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
Ship = Content.Load<Texture2D>("Ship");
Ship_Origin.X = Ship.Width / 2;
Ship_Origin.Y = Ship.Height / 2;
background = Content.Load<Texture2D>("aus");
Ship_Position = new Vector2(worldCenter.X, worldCenter.Y);
cam.Pos = Ship_Position;
cam.Zoom = 1f;
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
Ship_Position = Ship_Velocity + Ship_Position;
keyPressed();
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null,null, cam.get_transformation(GraphicsDevice));
spriteBatch.Draw(background, Vector2.Zero, Color.White);
spriteBatch.Draw(Ship, Ship_Position, Ship.Bounds, Color.White, Ship_Rotation, Ship_Origin, 1.0f, SpriteEffects.None, 0f);
spriteBatch.End();
base.Draw(gameTime);
}
private void Ship_Move(Vector2 move)
{
Ship_Position += move;
}
private void keyPressed()
{
KeyboardState keyState;
// Move right
keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Right))
{
Ship_Rotation = Ship_Rotation + 0.1f;
}
if (keyState.IsKeyDown(Keys.Left))
{
Ship_Rotation = Ship_Rotation - 0.1f;
}
if (keyState.IsKeyDown(Keys.Up))
{
Ship_Velocity.X = (float)Math.Cos(Ship_Rotation) * tangentialVelocity;
Ship_Velocity.Y = (float)Math.Sin(Ship_Rotation) * tangentialVelocity;
if ((int)Ship_Position.Y < playerBounds.Bottom && (int)Ship_Position.Y > playerBounds.Top) cam._pos.Y = Ship_Position.Y;
if ((int)Ship_Position.X > playerBounds.Left && (int)Ship_Position.X < playerBounds.Right) cam._pos.X = Ship_Position.X;
//tried world bounds here
if (!worldBounds.Contains(new Point((int)Ship_Position.X, (int)Ship_Position.Y))) Ship_Position -= new Vector2(0.0f, -tangentialVelocity * 2);
if (!worldBounds.Contains(new Point((int)Ship_Position.X, (int)Ship_Position.Y))) Ship_Position -= new Vector2(0.0f, 2 * tangentialVelocity);
}
else if(Ship_Velocity != Vector2.Zero)
{
float i = Ship_Velocity.X;
float j = Ship_Velocity.Y;
Ship_Velocity.X = i -= friction * i;
Ship_Velocity.Y = j -= friction * j;
if ((int)Ship_Position.Y < playerBounds.Bottom && (int)Ship_Position.Y > playerBounds.Top) cam._pos.Y = Ship_Position.Y;
if ((int)Ship_Position.X > playerBounds.Left && (int)Ship_Position.X < playerBounds.Right) cam._pos.X = Ship_Position.X;
}
if (keyState.IsKeyDown(Keys.Q))
{
if (cam.Zoom < 2f) cam.Zoom += 0.05f;
}
if (keyState.IsKeyDown(Keys.A))
{
if (cam.Zoom > 0.3f) cam.Zoom -= 0.05f;
}
}
}
}
my 2d camera class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace GamesCoursework_1
{
public class Camera2d
{
protected float _zoom; // Camera Zoom
public Matrix _transform; // Matrix Transform
public Vector2 _pos; // Camera Position
protected float _rotation; // Camera Rotation
public int _viewportWidth, _viewportHeight; // viewport size
public Camera2d(int ViewportWidth, int ViewportHeight)
{
_zoom = 1.0f;
_rotation = 0.0f;
_pos = Vector2.Zero;
_viewportWidth = ViewportWidth;
_viewportHeight = ViewportHeight;
}
// Sets and gets zoom
public float Zoom
{
get { return _zoom; }
set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; } // Negative zoom will flip image
}
public float Rotation
{
get { return _rotation; }
set { _rotation = value; }
}
// Auxiliary function to move the camera
public void Move(Vector2 amount)
{
_pos += amount;
}
// Get set position
public Vector2 Pos
{
get { return _pos; }
set { _pos = value; }
}
public Matrix get_transformation(GraphicsDevice graphicsDevice)
{
_transform = // Thanks to o KB o for this solution
Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
Matrix.CreateTranslation(new Vector3(_viewportWidth * 0.5f, _viewportHeight * 0.5f, 0));
return _transform;
}
}
}