I am trying to make bullet holes to appear in the background once I fire the gun.
So far the game is working like this:
1. Load gun sprite
2. Click left mouse button load gunFlame sprite and play sounds
3. Release left mouse button load gun sprite (without the flame)
The next step I want to implement is to have some bullet holes on the background at a relative distance from the gun.
class Gun
{
Texture2D gun, gunFlame, gunObject, bulletHole, hole;
Vector2 position, bulletHolePosition;
SoundEffect shotSound, fallSound;
MouseState currentMouseState, previousMouseState;
public Gun(ContentManager Content)
{
bulletHole = Content.Load<Texture2D>("bullethole");
bulletHolePosition = new Vector2(position.X + 3, position.Y + 3);
gun = Content.Load<Texture2D>("Gun");
position = new Vector2(10, 10);
gunFlame = Content.Load<Texture2D>("gunFlame");
shotSound = Content.Load<SoundEffect>("gunshot");
fallSound = Content.Load<SoundEffect>("bullet-fall");
gunObject = gun;
}
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Draw(gunObject, position, Color.White);
}
public void Update(GameTime gameTime)
{
// Keep track of the previous state to only play the effect on new clicks and not when the button is held down
previousMouseState = currentMouseState;
currentMouseState = Mouse.GetState();
if (currentMouseState.LeftButton == ButtonState.Pressed && previousMouseState.LeftButton != ButtonState.Pressed)
{
gunObject = gunFlame;
hole = bulletHole;
shotSound.Play();
fallSound.Play();
}
else if(currentMouseState.LeftButton == ButtonState.Released)
{
gunObject = gun;
}
}
I see some problems in your code, which makes me doubt you can even execute it, for example in your constructor you have:
bulletHolePosition = new Vector2(position.X + 3, position.Y + 3);
gun = Content.Load<Texture2D>("Gun");
position = new Vector2(10, 10);
You are using the position object before initializing it, is that intended?
Anyway, what you could do in order to create bullet holes is to have a list (or array or whatever you like best) containing the positions where the holes should be in your background.
You add holes to the collection inside the if (currentMouseState.LeftButton == ButtonState.Pressed && previousMouseState.LeftButton != ButtonState.Pressed) statement.
After that, on the Draw method, just iterate through the collection and draw the bulletHole texture on each position.
So basically replace Vector2 bulletHolePosition with IList<Vector2> bulletHolePositions.
Example:
Vector2 position;
IList<Vector2> bulletHolePositions;
In the constructor:
bulletHolePositions = new List<Vector2>;
In the Update method:
if (currentMouseState.LeftButton == ButtonState.Pressed && previousMouseState.LeftButton != ButtonState.Pressed)
{
bulletHolePositions.Add(new Vector2(currentMouseState.X, currentMouseState.Y));
//...
}
//...
And finally, in the Draw method:
spriteBatch.Draw(gunObject, position, Color.White);
foreach(var holePosition in bulletHolePositions)
spriteBatch.Draw(bulletHole , position, Color.White);
Keep in mind that if you have MANY of these on the screen, your game performance may drop.
If you need more help, please give us more details about where you are having problems instead.
Related
I have six or more sprites that are hidden, alpha set to 0. I move the sprites to a starting position at the top of the screen before showing them. Once in the new position I show them and the moving them back to their original positions.
My issue is that the sprites are show just for a couple of milliseconds before they are moved to the starting point. Even though the order of the code is move first then show.
I tried to find a position moved callback to detect when the position change is complete before showing but I don't this it is possible.
void Start() {
int i = 0;
foreach (Transform point in drawingPoints.transform)
{
//Record points original postion
Vector3 currentPosition = point.transform.position;
//Move to new starting position
point.transform.position = stepOne.transform.position;
//Now show point
var color = point.gameObject.GetComponent<SpriteRenderer>().color;
color.a = 1;
point.gameObject.GetComponent<SpriteRenderer>().color = color;
//Move point back to original postion
point.transform.DOMove(currentPosition, 1f).SetDelay(UnityEngine.Random.Range(0f, 0.3f));
i += 1;
}
}
Consider disabling the sprite renderer till the transform is at the start point.
void Start()
{
int i = 0;
foreach (Transform point in drawingPoints.transform)
{
SpriteRenderer spriteRenderer = point.gameObject.GetComponent<SpriteRenderer>();
if(spriteRenderer == null)
continue;
// Disable the renderer.
spriteRenderer.enabled = false;
//Record points original postion
Vector3 currentPosition = point.transform.position;
//Move to new starting position
point.transform.position = stepOne.transform.position;
// Now you're at start point, enable it back.
spriteRenderer.enabled = true;
//Move point back to original postion
point.transform.DOMove(currentPosition, 1f).SetDelay(UnityEngine.Random.Range(0f, 0.3f));
i += 1;
}
}
If for whatever reason or weird behaviour of unity you wanna get a callback when something is at a position, here's a hacky way
transformToMove.DoMove(destination, 0).OnComplete(()=>
{
// Now you're at the point.
});
I'm new to this so not completely sure whether I am posting this correctly, but I have been having a few issues when creating my game. My main goal is to create a topdown shooter styled game, using movement where the 'player' rotates based on the current position of the mouse and can press 'w' to move towards it at a set speed.
The main issue is, when the game loads, the movement works exactly how I want it to, but the texture itself is not moving, but only the drawRectangle.
Game1.cs:
player = new Player(Content, #"graphics\Player1", 500, 500, spritePosition);
spritePosition = new Vector2(player.CollisionRectangle.X, player.CollisionRectangle.Y);
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
KeyboardState keyboard = Keyboard.GetState();
MouseState mouse = Mouse.GetState();
IsMouseVisible = true;
distance.X = mouse.X - spritePosition.X;
distance.Y = mouse.Y - spritePosition.Y;
//Works out the rotation depending on how far away mouse is from sprite
rotation = (float)Math.Atan2(distance.Y, distance.X);
// TODO: Add your update logic here
spritePosition = spriteVelocity + spritePosition;
spriteOrigin = new Vector2(player.DrawRectangle.X / 2, player.DrawRectangle.Y / 2);
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
}
else if(spriteVelocity != Vector2.Zero)
{
Vector2 i = spriteVelocity;
spriteVelocity = i -= friction * i;
}
This is the main movement code from the Update function as well as where the new player has been created.
Player.cs:
class Player
{
Texture2D sprite;
Rectangle drawRectangle;
int health = 100;
public Player(ContentManager contentManager, string spriteName, int x , int y, Vector2 velocity)
{
LoadContent(contentManager, spriteName, x, y, velocity);
}
public Rectangle CollisionRectangle
{
get { return drawRectangle; }
}
public Rectangle DrawRectangle
{
get { return drawRectangle; }
set { drawRectangle = value; }
}
public int Health
{
get { return health; }
set {
health = value;
if (health <= 0)
health = 0;
if (health > 100)
health = 100;
}
}
public Vector2 Velocity
{
get { return Velocity; }
set { Velocity = value; }
}
public void Update(GameTime gameTime, KeyboardState keyboard, MouseState mouse)
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(sprite, drawRectangle, Color.White);
}
private void LoadContent(ContentManager contentManager, string spriteName, int x, int y, Vector2 velocity)
{
sprite = contentManager.Load<Texture2D>(spriteName);
drawRectangle = new Rectangle(x - sprite.Width / 2, y - sprite.Height / 2, sprite.Width, sprite.Height);
}
}
I didn't know what to include in the Update function of the player.cs, whether the code for movement should go in there or the main Game1.cs.
Hopefully this is enough code for you guys to be able to help. Sorry for there being quite a lot of code, but I'm just unsure where the error is occurring.
Thanks in advance
For the rotation you would want to use 'another' kind of spriteBatch.Draw, because the draw function can have more parameters than your currently using.
The full draw function is as followed:
SpriteBatch.Draw(Texture2D texture, Vector2 position, Rectangle sourceRectangle, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerdepht)
As you can see, now we have a parameter for rotation that can be used.
So your code will look something like this:
spriteBatch.Draw(sprite, drawRectangle, null, Color.White, rotation, Vector2.Zero, 1, SpriteEffects.None, 0);
As for your question for where your code should go. It is good to learn yourself to put the code where it belongs, in this case the player. Because when your programs become bigger, it would be very messy to do it this way.
To call the update function in your player class, you can just simply call player.Update(gameTime, keyboard, mouse) in the Update of Game1.
Hello there wonderful people!
Let's just cut to the chase.
I've made a tile engine that draws my map relative to my camera (The tiles that are drawn are the ones visible in the camera window), and i've made a sprite (my character) that is centered within the camera.
Whenever i move the camera my character follows accordingly, the only problem is when i reach the borders of my map. Programing the way i did has constrained my camera from moving beyond the borders, resulting in limiting my character from moving closer to the borders(since it's always centered within the camera).
How do i free my camera from the restraints of my evil map?
p.s. I've made a picture to illustrate what i want to do.
And here is the guide i followed.
Here's my code where i draw the tiles and place the camera:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
Vector2 firstSquare = new Vector2(Camera.Location.X / Tile.TileWidth, Camera.Location.Y / Tile.TileHeight);
int firstX = (int)firstSquare.X;
int firstY = (int)firstSquare.Y;
Vector2 squareOffset = new Vector2(Camera.Location.X % Tile.TileWidth, Camera.Location.Y % Tile.TileHeight);
int offsetX = (int)squareOffset.X;
int offsetY = (int)squareOffset.Y;
for (int y = 0; y < squaresDown; y++)
{
for (int x = 0; x < squaresAcross; x++)
{
foreach (int tileID in myMap.Rows[y + firstY].Columns[x + firstX].BaseTiles)
{
spriteBatch.Draw(
Tile.TileSetTexture,
new Rectangle(
(x * Tile.TileWidth) - offsetX, (y * Tile.TileHeight) - offsetY,
Tile.TileWidth, Tile.TileHeight),
Tile.GetSourceRectangle(tileID),
Color.White);
}
}
}
spriteBatch.End();
// TODO: Add your drawing code here
base.Draw(gameTime);
}
And here is the code where i move the camera:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
IsMouseVisible = true;
KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.A))
{
Camera.Location.X = MathHelper.Clamp(Camera.Location.X - 2, 0, (myMap.MapWidth - squaresAcross) * Tile.TileWidth);
}
if (ks.IsKeyDown(Keys.D))
{
Camera.Location.X = MathHelper.Clamp(Camera.Location.X + 2, 0, (myMap.MapWidth - squaresAcross) * Tile.TileWidth);
}
if (ks.IsKeyDown(Keys.W))
{
Camera.Location.Y = MathHelper.Clamp(Camera.Location.Y - 2, 0, (myMap.MapHeight - squaresDown) * Tile.TileHeight);
}
if (ks.IsKeyDown(Keys.S))
{
Camera.Location.Y = MathHelper.Clamp(Camera.Location.Y + 2, 0, (myMap.MapHeight - squaresDown) * Tile.TileHeight);
}
// TODO: Add your update logic here
base.Update(gameTime);
}
Instead of making your player follow the camera, you need to make your camera follow the player. That way you can set restrictions on the camera, instead of attempting to hack the camera system to make the character do things.
On every update, you would have something like:
Player.Update(gametime);
Camera.Update(Player.Position);
I'm pretty new to XNA|C# and what I want to do is simply move a sprite between two points and have it move back and forth continuously.
Let's say I want the sprite to move between the y-coordinate 100 and 0.
How would I accomplish this?
Your question has nothing to do with XNA itself. You are asking how to move an object in a straight line and that is something that is usually learnt in first year geometry.
I'll assume you are drawing your texture like this:
SpriteTexture sprite;
Vector2 position;
...
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(sprite, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
A straight line is an extremely simple path - it is easily defined by two points. Let the points be P1 and P2. The straight line is then defined as the function (1 - t) * P1 + t * P2 where 0 <= t <= 1. To move the sprite, start from t = 0 and increment t in each update cycle. Computing the function with the given t gives you the position of the sprite. When t >= 1 you've reached P2, this means you should start decrementing t back to 0 and so on and so forth. Here's how to use that fact to move the sprite:
SpriteTexture sprite;
Vector2 position;
Vector2 p1 = new Vector2(0, 100),
p2 = new Vector2(0, 0);
double currentTime = 0, timestep = 0.01;
...
protected override void Update(GameTime gameTime)
{
position = currentTime * p1 + (1 - currentTime) * p2;
currentTime += timestep;
if (currentTime >= 1 || currentTime <= 0)
{
timestep *= -1;
}
}
Here is how XNA works, every frame it calls the methods update and draw in your game's main page. We need to keep track of which direction your sprite is moving and its position so lets add to your main game file:
public Vector2 rectanglePosition = new Vector2(0,0);
public bool moveRight = true;
Now what you want to do is every frame update the position, and use it to draw an object. So in the update method you would have something like
if (moveRight)
rectanglePosition.Y += 10;
else
rectanglePosition.Y -= 10;
if(rectanglePosition.Y>100 || rectanglePosition.Y<0)
moveRight = !moveright;
Then in the draw method just draw the sprite based on the position (you can start by just drawing a rectangle), which you can look up how to do easily.
I can further help you if you don't get the code.
In XNA 4.0 how do I get a sprite to move to the mouses coordinates. I know that this would be possible to do like this:
if (ms.LeftButton == ButtonState.Pressed)
{
Vector2 shipPos = new Vector2(ms.X,ms.Y);
}
but because I'm using a camera that follows the ship this does not work properly. The reason for this is that the position of the mouse is relative to the screen and if the ship has been moved to let say (500,500) when I click in the top left corner of the window the ship goes back to (0,0), even tough I want the ship to move from the ships position up towards the corner. Here's the code for my matrix:
class Camera
{
public Matrix transform;
Viewport view;
Vector2 centre;
public Camera(Viewport newView)
{
view = newView;
}
public void Update(GameTime gameTime, Game1 ship)
{
int w = Game1.width;
int h = Game1.height;
centre = new Vector2(ship.FSpos.X - (w / 2 - 189/2),
ship.FSpos.Y - (h / 2-128/2));
transform = Matrix.CreateScale(new Vector3(1, 1, 0)) *
Matrix.CreateTranslation(new Vector3(-centre.X, -centre.Y, 0));
}
}
You could do something like this:
if (ms.LeftButton == ButtonState.Pressed)
{
Vector2 shipPos = new Vector2(
ms.X-screenWidth/2 + previousShipPosition.X,
ms.Y-screenHeight/2 + previousShipPosition.Y
);
}