I want that my character makes a 40 pixel height jump if I press the A button once. But I don't know if 40f is equal to 40 pixel?
What do you think about my code? What is wrong?
In addition, I want that my program runs with the same speed on every computer.
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D image, water;
float Gravity = 5.0F;
float Acceleration = 20.0F;
Vector2 Position = new Vector2(1200,720);
Vector2 Velocity;
float rotation = 0;
SpriteEffects flip;
Vector2 Speed = new Vector2(0, 0);
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);
image = Content.Load<Texture2D>("cartoondolphin");
water = Content.Load<Texture2D>("background");
flip = SpriteEffects.None;
}
protected override void Update(GameTime gameTime)
{
float VelocityX = 0f;
float VelocityY = 0f;
float time = (float)gameTime.ElapsedGameTime.TotalSeconds;
KeyboardState kbState = Keyboard.GetState();
if(kbState.IsKeyDown(Keys.Left))
{
rotation = 0;
flip = SpriteEffects.None;
VelocityX += -5f;
}
if(kbState.IsKeyDown(Keys.Right))
{
rotation = 0;
flip = SpriteEffects.FlipHorizontally;
VelocityX += 5f;
}
// jump if the dolphin is under water
if(Position.Y >= 670)
{
if (kbState.IsKeyDown(Keys.A))
{
if (flip == SpriteEffects.None)
{
VelocityY += 40f;
}
else
{
VelocityY += 40f;
}
}
}
else
{
VelocityY += -10f;
}
float deltaY = 0;
float deltaX = 0;
deltaY = Gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;
deltaX += VelocityX * (float)gameTime.ElapsedGameTime.TotalSeconds * Acceleration;
deltaY += -VelocityY * (float)gameTime.ElapsedGameTime.TotalSeconds * Acceleration;
Speed = new Vector2(Speed.X + deltaX, Speed.Y + deltaY);
Position += Speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
Velocity.X = 0;
if (Position.Y + image.Height/2 > graphics.PreferredBackBufferHeight)
Position.Y = graphics.PreferredBackBufferHeight - image.Height/2;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(water, new Rectangle(0, graphics.PreferredBackBufferHeight -100, graphics.PreferredBackBufferWidth, 100), Color.White);
spriteBatch.Draw(image, Position, null, Color.White, MathHelper.ToRadians(rotation), new Vector2(image.Width / 2, image.Height / 2), 1, flip, 1);
spriteBatch.End();
base.Draw(gameTime);
}
}
The problem is that you're not taking the gameTime into account. If a computer with a fast CPU executes that code twice as fast as a slower PC, the value of velocity will increase twice as fast (relative to the slower PC).
When you have code like:
VelocityX += 5f;
You need to keep track of the last gameTime, and get the difference between the frames, and multiply that by your constant. (Some code grabbed from Xna adding gravity to a 2d sprite)
int updateTime = gt.ElapsedGameTime.TotalMilliseconds - oldgt.ElapsedGameTime.TotalMilliseconds;
float timeScalar = updateTime / AVG_FRAME_TIME;
VelocityX += 5f * timeScalar;
Related
I've just started a XNA project and I want to make Asteroids by Atari in Monogame. For the moment, I have the movement of the ship. I've just modified a few things in the code. The problem now is the asteroids. I'm trying to research of how to make them and I'm not having any good results.
My Code:
private Texture2D texture;
private Rectangle destinationRectangle;
private Rectangle sourceRectangle;
private float rotationSpeed;
private Vector2 rotationOrigin;
private float rotationAngle;
private float speed;
private Vector2 velocity;
public Asteroide(Texture2D texture, int x, int y)
{
}
public Asteroide(Texture2D texture, int x, int y, int width, int height, float speed, float rotationSpeed)
{
this.texture = texture;
this.rotationSpeed = rotationSpeed;
destinationRectangle = new Rectangle(x - width / 2, y - height / 2, width, height);
sourceRectangle = new Rectangle(0, 0, width, height);
rotationOrigin = new Vector2(texture.Width * 0.5f, texture.Height * 0.5f);
this.speed = speed;
Random rnd = new Random();
int degree = rnd.Next(-45, 46);
double radian = degree * Math.PI / 180;
ChangeAngle(radian);
}
public void ChangeAngle(double radian)
{
velocity.X = (float)Math.Cos(radian) * speed;
velocity.Y = -1f * (float)Math.Sin(radian) * speed;
}
public void Update(GameTime gameTime)
{
Move(gameTime);
}
private void Move(GameTime gameTime)
{
destinationRectangle.X += (int)(velocity.X * gameTime.ElapsedGameTime.TotalSeconds);
destinationRectangle.Y += (int)(velocity.Y * gameTime.ElapsedGameTime.TotalSeconds);
}
private void Rotation(GameTime gameTime)
{
rotationAngle += rotationSpeed * (float) gameTime.ElapsedGameTime.TotalSeconds;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, destinationRectangle, sourceRectangle, Color.White, rotationAngle, rotationOrigin, SpriteEffects.None, 0f);
}
What I want is an asteroid that constantly moves and to generate asteroids of all sizes. They should cover all the screen in big, medium and small sizes. I know I have to use a Random somewhere, but i don't know where.
I'm working on a game that allows my 2D sprite to jump on a platform but when it lands on the platform, my 2D sprite is not exactly on top of the platform, sometimes its exceeding or the same as the position of the platform.
//here is my code:
Texture2D jumper;
Texture2D tile;
Vector2 position, velocity;
Rectangle top;
Rectangle tile_rectangle;
Rectangle jumper_rectangle;
KeyboardState ks;
bool jump;
//here is my Load Content:
protected override void LoadContent()
{
jump = true;
position.X = 10;
position.Y = 10;
jumper = Content.Load<Texture2D>("character");
tile = Content.Load<Texture2D>("tile");
tile_rectangle = new Rectangle(300, 350, tile.Width, tile.Height);
top = new Rectangle(tile_rectangle.X, tile_rectangle.Y - 16, tile_rectangle.Width, 10);
}
//Here is my update:
protected override void Update(GameTime gameTime)
{
ks = Keyboard.GetState();
position += velocity;
float i = 1;
if (ks.IsKeyDown(Keys.Up) && jump == false)
{
position.Y -= 10f;
velocity.Y = -25f;
jump = true;
}
if (jump == true)
{
velocity.Y += 2f * i;
}
if (position.Y > 400)
{
jump = false;
}
if (jump == false)
{
velocity.Y = 0f;
}
BoundingBox();
if (ks.IsKeyDown(Keys.Right))
{
position.X += 5f;
velocity.X = +0.05f;
if (jumper_rectangle.Left > tile_rectangle.Right)
{
jump = true;
}
}
if (ks.IsKeyDown(Keys.Left))
{
position.X -= 5f;
velocity.X = -0.05f;
if (jumper_rectangle.Right < tile_rectangle.Left)
{
jump = true;
}
}
jumper_rectangle = new Rectangle((int)position.X, (int)position.Y, jumper.Width, jumper.Height);
BoundingBox();
base.Update(gameTime);
}
//here is my draw:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(jumper, jumper_rectangle, Color.White);
spriteBatch.Draw(tile, tile_rectangle, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
//here is my method on landing:
public void BoundingBox()
{
if (jumper_rectangle.Intersects(top))
{
if (jumper_rectangle.Bottom > top.Top)
{
position.Y--;
jump = false;
}
}
}
Where did i go wrong or is there some other way?
I have a sprite called Tool that moves with a speed represented as a float and in a direction represented as a Vector2. When I click the mouse on the screen the sprite change its direction and starts to move towards the mouseclick. In addition to that I rotate the sprite so that it is facing in the direction it is heading. However, when I add a camera that is suppose to follow the sprite so that the sprite is always centered on the screen, the sprite won't move in the given direction and the rotation isn't accurate anymore. This only happens when I add the Camera.View in the spriteBatch.Begin(). I was hoping anyone could maybe shed a light on what I am missing in my code, that would be highly appreciated.
Here is the camera class i use:
public class Camera
{
private const float zoomUpperLimit = 1.5f;
private const float zoomLowerLimit = 0.1f;
private float _zoom;
private Vector2 _pos;
private int ViewportWidth, ViewportHeight;
#region Properties
public float Zoom
{
get { return _zoom; }
set
{
_zoom = value;
if (_zoom < zoomLowerLimit)
_zoom = zoomLowerLimit;
if (_zoom > zoomUpperLimit)
_zoom = zoomUpperLimit;
}
}
public Rectangle Viewport
{
get
{
int width = (int)((ViewportWidth / _zoom));
int height = (int)((ViewportHeight / _zoom));
return new Rectangle((int)(_pos.X - width / 2), (int)(_pos.Y - height / 2), width, height);
}
}
public void Move(Vector2 amount)
{
_pos += amount;
}
public Vector2 Position
{
get { return _pos; }
set { _pos = value; }
}
public Matrix View
{
get
{
return Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
}
}
#endregion
public Camera(Viewport viewport, float initialZoom)
{
_zoom = initialZoom;
_pos = Vector2.Zero;
ViewportWidth = viewport.Width;
ViewportHeight = viewport.Height;
}
}
And here is my Update and Draw-method:
protected override void Update (GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
TouchCollection touchCollection = TouchPanel.GetState ();
foreach (TouchLocation tl in touchCollection) {
if (tl.State == TouchLocationState.Pressed || tl.State == TouchLocationState.Moved) {
//direction the tool shall move towards
direction = touchCollection [0].Position - toolPos;
if (direction != Vector2.Zero) {
direction.Normalize ();
}
//change the direction the tool is moving and find the rotationangle the texture must rotate to point in given direction
toolPos += (direction * speed * elapsed);
RotationAngle = (float)Math.Atan2 (direction.Y, direction.X);
}
}
if (direction != Vector2.Zero) {
direction.Normalize ();
}
//move tool in given direction
toolPos += (direction * speed * elapsed);
//change cameracentre to the tools position
Camera.Position = toolPos;
base.Update (gameTime);
}
protected override void Draw (GameTime gameTime)
{
graphics.GraphicsDevice.Clear (Color.Blue);
spriteBatch.Begin (SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, Camera.View);
spriteBatch.Draw (tool, new Vector2 (toolPos.X, toolPos.Y), null, Color.White, RotationAngle, originOfToolTexture, 1, SpriteEffects.None, 1);
spriteBatch.End ();
base.Draw (gameTime);
}
You need to convert your cursor position into world position:
Vector2 adjustedPosition = Vector2.Transform(touchCollection[0].Position, Matrix.Invert(camera.View));
Then your direction would be:
direction = adjustedPosition - toolPos;
I'm working on a pong game, since i'm new at programming, i don't know how to get acess to another class variable. I have seperate classes, green and blue paddles, a ball, and game1.cs.
I control the ball movement with bool movingUp, movingLeft;
It bounces off the borders of the screen, but i don't know how to make it work with the paddles. Basically, how do i check the position of the paddle, and make so when the ball touches the paddle, it bounces off? I mean, how to detect the collision?
public class Ball
{
ParticleEngine particleEngine;
GraphicsDeviceManager graphics;
Texture2D texture;
Vector2 position;
Boolean movingUp, movingLeft;
Vector2 origin;
public Ball()
{
position = new Vector2(800 / 2, 330);
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("ball");
movingLeft = true;
//Particle Engine
List<Texture2D> textures = new List<Texture2D>();
textures.Add(Content.Load<Texture2D>("pixel"));
particleEngine = new ParticleEngine(textures, new Vector2(400, 240));
}
public void Update(GameTime gameTime)
{
float speed = 2.5f;
//Physics
if (movingUp)
{
position.Y -= 3;
}
if (movingLeft)
{
position.X -= 3;
}
if (!movingUp)
{
position.Y += 3;
}
if (!movingLeft)
{
position.X += 3;
}
if (position.X <= 0 && movingLeft) movingLeft = false;
if (position.Y <= 85 && movingUp) movingUp = false;
if (position.X >= 800 - texture.Width && !movingLeft) movingLeft = true;
if (position.Y >= 500 - texture.Height && !movingUp) movingUp = true;
origin = new Vector2(position.X + texture.Width / 2, position.Y + texture.Height / 2);
//Particles
particleEngine.EmitterLocation = new Vector2(origin.X, origin.Y);
particleEngine.Update();
}
public void Draw(SpriteBatch spriteBatch)
{
particleEngine.Draw(spriteBatch);
spriteBatch.Draw(texture, position, Color.White);
}
}
One of the paddle classes (they look the same exept the name and movement keys):
public class GreenPaddle
{
Texture2D texture;
Vector2 position;
float speed = 2f;
public GreenPaddle()
{
position = new Vector2(10, 230);
}
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("greenpaddle");
}
public void Update(GameTime gameTime)
{
KeyboardState keyState = Keyboard.GetState();
//Check If Keys Are Pressed // Movement
if (keyState.IsKeyDown(Keys.W))
position.Y -= speed;
if (keyState.IsKeyDown(Keys.S))
position.Y += speed;
//Check Border
if (position.Y < 87)
{
position.Y = 87;
}
if (position.Y > 396)
{
position.Y = 396;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Thanks in advance, i really wish to learn things like this :D
Declare the variables you want to access as public, or create get methods.
For public variables you would do:
public Vector2 Position;
And to access it, you would call:
Ball ball;
ball.Position
For get method implement:
public Vector2 getPosition()
{
return Position;
}
And you would call that method to get the position.
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);
}
}