Hi all I am trying to create a game, and right now, I have a balloon class, which I want to currently create an amount of them via an array, and then draw then into the game.
Currently however it seems it is either only creating one instance of balloon or only drawing 1 instance. I'v looked over it multiple times, and from what I understand it should be looping through the entire array size (currently set at 10) and creating that many balloons, then updating and drawing that many.
Are you not able to do what I am currently doing with an array? Would I have to create each object sparately?
Here is the code of the two classes concerned.
GameLevel:
The class that creates the onjects and draws them.
public partial class GameLevel : GameScreen
{
SpriteBatch spriteBatch;
protected Game game;
Texture2D balloonTexture;
Balloon[] balloons = new Balloon[10];
public GameLevel(Game game, SpriteBatch spriteBatch)
: base(game, spriteBatch)
{
this.game = game;
this.spriteBatch = spriteBatch;
}
public void LoadContent()
{
for (int i = 0; i < balloons.Length; i++)
{
int colour;
Random random = new Random();
colour = random.Next(1, 6);
switch (colour)
{
case 1: balloonTexture = Game.Content.Load<Texture2D>("Images/BlueBalloon");
break;
case 2: balloonTexture = Game.Content.Load<Texture2D>("Images/RedBalloon");
break;
case 3: balloonTexture = Game.Content.Load<Texture2D>("Images/YellowBalloon");
break;
case 4: balloonTexture = Game.Content.Load<Texture2D>("Images/GreenBalloon");
break;
case 5: balloonTexture = Game.Content.Load<Texture2D>("Images/PurpleBalloon");
break;
}
balloons[i] = new Balloon(new Rectangle(0, 0, 1152, 648), balloonTexture);
balloons[i].SetStartPosition();
}
}
public void Update()
{
for (int i = 0; i < balloons.Length; i++)
{
balloons[i].Update();
}
}
public override void Draw(GameTime gameTime)
{
for (int i = 0; i < balloons.Length; i++)
{
balloons[i].Draw(spriteBatch);
}
base.Draw(gameTime);
}
}
}
Ballon Class:
public class Balloon
{
Vector2 position;
Vector2 motion;
Rectangle bounds;
Rectangle screenBounds;
public Texture2D texture;
float balloonSpeed = 4;
public Balloon(Rectangle screenBounds, Texture2D texture)
{
this.texture = texture;
this.screenBounds = screenBounds;
}
public Rectangle Bounds
{
get
{
bounds.X = (int)position.X;
bounds.Y = (int)position.Y;
return bounds;
}
}
public void Update()
{
position += motion * balloonSpeed;
}
private void CheckWallColision()
{
if (position.X < 0)
{
position.X = 0;
motion.X *= -1;
}
if (position.X + texture.Width > screenBounds.Width)
{
position.X = screenBounds.Width - texture.Width;
motion.X *= -1;
}
if (position.Y < 0)
{
position.Y = 0;
motion.Y *= -1;
}
if (position.Y + texture.Height > screenBounds.Height)
{
position.Y = screenBounds.Height - texture.Height;
motion.Y *= -1;
}
}
public void SetStartPosition()
{
Random rand = new Random();
motion = new Vector2(rand.Next(2, 6), -rand.Next(2, 6));
motion.Normalize();
position = new Vector2(rand.Next(100, 500), rand.Next(100, 500));
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
}
I believe the reason this is occurring is related to the way the Random object works. When one is constructed, it uses as its seed (from which it will generate all values) the system clock. This means that, if you generate numerous Random instances at the same time, every single one of them will return the same series of values. If you're using these values for positions, every single one of your objects will have the same position, and will be drawn over each other. In your case, because they're all the same size, it looks like only one was ever drawn.
To fix this, create a single instance of Random and just use Next() on that single instance whenever you need a new position.
Personally, I consider this a pretty significant design flaw - it doesn't seem amazingly intuitive that a series of Random objects created at the same time will be "random" in the exact same way. But: this is a good example of the fact that "random" values created by C#, and any other language, will in fact be pseudo-random, and when it comes to pseudo-randomness, implementation is very important.
Related
EDIT: Fixed the problem. I created a new Random for every asteroid so there wasn't enough time between them. But when I stepped trough the code manually it was enough time to not create the same value.
Here's the code. Control with WASD, shoot with space and press "L" to spawn an asteroid.
https://github.com/Geblin/Monogame-Asteroids
The asteroids split into 2-3 smaller asteroids when shot at and it's those smaller ones that have the same values, even though I give them random ones. I've stepped trough the code and it seems like they get different values initially.
Here's the Asteroid class. So I input a scale and a position so I can spawn smaller asteroids on different positions. The angle and speed is randomly selected here.
public Asteroid(Texture2D texture, float scale, Vector2 pos)
{
rand = new Random();
this.texture = texture;
this.scale = scale;
this.pos = pos;
angle = degreesToRadian(rand.Next(0,360));
direction = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
origin = new Vector2(texture.Width / 2, texture.Height / 2);
isVisible = true;
sourceRectangle = new Rectangle(0, 0, texture.Width, texture.Height);
boundingCircle = new BoundingCircle(pos, texture, scale);
speed = (float)rand.NextDouble() * (3 - 1) + 1;
setupRotation();
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, pos, sourceRectangle, Color.White, angle, origin, scale, SpriteEffects.None, 1f);
}
public void Update(GameTime gameTime)
{
boundingCircle.x = pos.X;
boundingCircle.y = pos.Y;
pos += direction * speed;
//Sets the asteroids bounds
if (pos.X > 2120)
pos.X = -200;
else if (pos.X < -200)
pos.X = 2120;
if (pos.Y > 1280)
pos.Y = -200;
else if (pos.Y < -200)
pos.Y = 1280;
angle += (float)rotationDirection;
}
public float degreesToRadian(int degrees)
{
float radian = (float)(Math.PI / 180) * degrees;
return radian;
}
//Sets a random rotation speed and rotation direction.
public void setupRotation()
{
rotationDirection = rand.NextDouble() * (0.01f - 0.005f) + 0.005f;
int x = rand.Next(2);
if (x == 1)
rotationDirection = -rotationDirection;
}
Here's the asteroid spawner class. The SetRandomSpawn method is for the first spawning asteroids. Those that spawn outside of the window and drifts in. In the main class I have the code that checks collisions between the lasers and asteroids and then spawns the smaller ones at the same position.
public AsteroidSpawner(List<Asteroid> asteroidList)
{
rand = new Random();
this.asteroidList = asteroidList;
}
public void LoadContent(ContentManager content)
{
texture = content.Load<Texture2D>("Asteroid");
}
public void Draw(SpriteBatch spriteBatch)
{
foreach (Asteroid asteroid in asteroidList)
asteroid.Draw(spriteBatch);
}
public void Update(GameTime gameTime)
{
UpdateAsteroids(gameTime);
if (Keyboard.GetState().IsKeyDown(Keys.L))
SpawnAsteroid(SetRandomSpawn(), 1f, 1);
}
public void SpawnAsteroid(Vector2 pos, float scale, int amount)
{
for (int i = 1; i <= amount; i++)
{
Asteroid newAsteroid = new Asteroid(texture, scale, pos);
asteroidList.Add(newAsteroid);
}
}
public void UpdateAsteroids(GameTime gameTime)
{
foreach (Asteroid asteroid in asteroidList)
{
asteroid.Update(gameTime);
}
for (int i = 0; i < asteroidList.Count; i++)
{
if (!asteroidList[i].isVisible)
{
asteroidList.RemoveAt(i);
i--;
}
}
}
//Sets a random spawn outside of screen bounds
public Vector2 SetRandomSpawn()
{
int side = rand.Next(4);
//Each number represents a side
switch (side)
{
// Left
case 0:
return new Vector2(2120, rand.Next(0, 1080));
// Top
case 1:
return new Vector2(rand.Next(0, 1920), 1280);
// Right
case 2:
return new Vector2(-200, rand.Next(0, 1080));
//Bottom
case 3:
return new Vector2(rand.Next(0, 1920), -200);
default:
throw new ArgumentException("Incorrect CrystalTypeEnum");
}
}
The seed of the Random object is time based, and because the spawner creates an Asteroid, and hence a Random in a loop, the random numbers generated are the same.
From the docs:
The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers.
You can see this effect with a wee test:
for (var i = 0; i < 10; i++) {
var rand = new Random();
Console.WriteLine(rand.Next());
}
... which outputs:
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
1337050944
Fix this by re-using the same Random (suggest your spawner creates an Asteroid then sets its position).
I am creating a game and need some help handling a bunch of objects, like about 10000, in my game i am generating a random amount of rocks, in random positions around a 1mil by 1mil map, I am adding the objects to a list and updating and drawing them like that but it is running so slow. I think some help in this matter would really help a lot of learners wanting to handle many objects.
Here is my generation code:
public void WorldGeneration()
{
//Random Compatibility
Random rdm = new Random();
//Tile Variables
int tileType;
int tileCount = 0;
Rock nearestRock;
//Initialize Coordinates
Vector2 tileSize = new Vector2(48f, 48f);
Vector2 currentGenVector = new Vector2(48f, 48f);
int worldTiles = 1000000;
//Do tile generation
for(int tile = 1; tile <= worldTiles; tile += 1)
{
//Generate Classes
tileType = rdm.Next(0, 42);
if (tileType == 1)
{
if (rocks.Count != 0)
{
//Check Rock Distance
nearestRock = rocks.FirstOrDefault(x => Vector2.Distance(x.Location, currentGenVector) < 128);
if (nearestRock == null)
{
Rock rock = new Rock(rockSprite, currentGenVector);
rocks.Add(rock);
}
}
if (rocks.Count == 0)
{
Rock rock = new Rock(rockSprite, currentGenVector);
rocks.Add(rock);
}
}
//Move Generation Tile
if (tileCount == worldTiles / 1000)
{
currentGenVector.X = tileSize.X;
currentGenVector.Y += tileSize.Y;
tileCount = 0;
}
else
{
currentGenVector.X += tileSize.X;
}
//Keep Count of Tiles per layer.
tileCount += 1;
}
And here is my rock code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
namespace Game2
{
class Rock
{
//Draw Support
Texture2D sprite;
Rectangle drawRectangle;
//Support
Vector2 location;
bool updating = false;
//Active
bool active = true;
public Rock(Texture2D sprite, Vector2 location)
{
//Initialize Location/Drawing
this.sprite = sprite;
this.location = location;
drawRectangle.Width = sprite.Width;
drawRectangle.Height = sprite.Height;
drawRectangle.X = (int)location.X - sprite.Width / 2;
drawRectangle.Y = (int)location.Y - sprite.Height / 2;
}
public void Update(GameTime gameTime, MouseState mouse)
{
//Mining
if (drawRectangle.Contains(mouse.X, mouse.Y))
{
if (mouse.LeftButton == ButtonState.Pressed)
{
location.X = -800;
location.Y = -800;
}
}
drawRectangle.X = (int)location.X;
drawRectangle.Y = (int)location.Y;
}
public void Draw(SpriteBatch spriteBatch)
{
//Draws The Sprite
spriteBatch.Draw(sprite, drawRectangle, Color.White);
}
//Get Location
public Vector2 Location
{
get { return location; }
}
public bool Updating
{
get { return updating; }
}
public void setUpdating(bool updating)
{
this.updating = updating;
}
public Rectangle DrawRectangle
{
get { return drawRectangle; }
}
}
}
I'm just asking for some tips on how to handle all these objects,
pls help is appreciated
The way I handle many objects is that I create a function which calculates the distance between two vectors and then use it to check if the current object is close enough to be drawn.
//Distance checking code
public float GetDistance(Vector2 v1, Vector2 v2){
float d = Math.Sqrt(Math.Abs((v1.X * v1.X) - (v2.X * v2.X))
+ Math.Abs((v1.Y * v1.Y) - (v2.Y * v2.Y)));
return d;
}
//example of using the Distance Check
if(GetDistance(player.position, rock.position) < 1280){
rock.Update();
}
This is just from the top of my head though, so the code may not work properly, but I think it's enough to get you started. Good luck!
Im having a hardtime how to remove an item in Multidimensional array. I am trying to create a breakout game. The only problem left though is that once the tile is gone i want to start again my game. But i cant figure out if how many are gone in my brick. I plan that when a certain counter reach to zero i will start again but i cant remove a 2d array. Im just setting the visible of each tile to false but not actually removing them..
here is my brick class
public Rectangle Location
{
get { return location; }
}
public int ID { get; set; }
public Brick(Texture2D texture, Rectangle location, int id)
{
this.texture = texture;
this.location = location;
ID = id;
}
public void CheckCollision(Ball ball, int i)
{
if (visible && ball.getBounds().Intersects(location))
{
visible = false;
ball.brickCollision();
}
}
public void Draw(SpriteBatch spriteBatch)
{
if (visible)
{
// gc.checker.Add(ID);
spriteBatch.Draw(texture, location, Color.White);
}
}
my other class related to brick
Brick[,] bricks;
private Texture2D b;
public void loadBricks(Texture2D b, int x, int y)
{
bricks = new Brick[x, y];
this.b = b;
for (int row = 0; row < y; row++)
{
for (int col = 0; col < x; col++)
{
bricks[col, row] = new Brick(b, new Rectangle(row * b.Width, col * b.Height, b.Width - 2, b.Height),row);
}
}
}
public void update(Ball ball)
{
foreach (Brick brick in bricks)
{
brick.CheckCollision(ball, bricks.Length);
}
}
public void drawBrick(SpriteBatch batch)
{
foreach (Brick brick in bricks)
{
//debugconsole("brck",brick);
brick.Draw(batch);
}
}
in my game class i only call the class thats related to brick. Any ideas?? thanks
Here is my ball class
public Ball(Texture2D ball, Vector2 speed, GraphicsDevice g, Rectangle p)
{
this.ball = ball;
ballSpeed = speed;
this.g = g;
this.p = p;
ballRect = new Rectangle((int)ballPosition.X, (int)ballPosition.Y, ball.Width, ball.Height);
}
public void Update(Paddle p)
{
x = p.getBounds().X;
y = p.getBounds().Y;
collidedBrick = false; // prevent removing too many bricks at one collision
ballmove();//move the ball
wallCollision();// check the ball and wall collision
paddCollision(p); // check paddle and ball collision
}
public void Update()
{
throw new NotImplementedException();
}
public void Draw(SpriteBatch batch)
{
batch.Draw(ball, ballRect, Color.White);
}
#region Collisions
public void wallCollision()
{
if (ballPosition.X < 0) //ball collide on left side screen
{
ballSpeed.X *= -1;
ballPosition.X = 0;
}
if (ballPosition.X > getScreenSize().Width - ballRect.Width) // ball collide on right side of screen
{
ballSpeed.X *= -1;
ballRect.X = getScreenSize().Width - ballRect.Width;
}
if (ballPosition.Y < 0)// ball collide on top edge of screen
{
ballSpeed.Y *= -1;
ballRect.Y = 0;
}
if (ballPosition.Y > getScreenSize().Height + ballRect.Height)
{
spacePress = false;
}
}
public void brickCollision()
{
if (!collidedBrick)
{
ballSpeed.Y *= -1;
collidedBrick = true;
counter++;
}
}
public void paddCollision(Paddle p)
{
if (p.getBounds().Intersects(ballRect))
{
ballPosition.Y = p.getBounds().Y - ball.Height;
ballSpeed.Y *= -1;
}
}
}
Why don't you use a dynamic array for that, so you can remove the bricks on the fly? Bricks that are removed from the list won't be drawn/updated and the memory they hold will be released because no other references would remain. I you absolutely must use a pseudo-matrix when loading the bricks, you can do something like:
List<Bricks> bricks;
public void loadBricks(Texture2D b, int x, int y)
{
bricks = new List<Bricks>();
for(int i = 0; i < (x * y); i++)
bricks.Add(new Brick(b, new Rectangle(b.Width * i / x, b.Height * (i % y), b.Width - 2, b.Height), i % y));
}
You could loop through all of your bricks and check their visible property:
bool endGame = true;
for (int row = 0; row < y; row++)
{
for (int col = 0; col < x; col++)
{
if (bricks[col, row].visible)
{
endGame = false;
}
}
}
if (endGame)
{
// End your game here
}
But this means that you will be repeatedly looping over all of your bricks to check if it's time to end the game or not. Not very efficient.
Instead, why not just track a integer _visibleBrickCount, set it to the number of bricks in your game at the start, and reduce it by one every time you call ball.BrickCollision()? Then, when it reaches zero, you know all the bricks are gone.
I'm writing a game and I would like an explosion animation to run whenever a collision occurs. However the approaches I know how to animate are based on keyboard input. What is the best way to code the method so that when called the animation makes a single pass through all frames then stops?
public void Update(GameTime gametime)
{
timer += gametime.ElapsedGameTime.Milliseconds;
if (timer >= msBetweenFrames)
{
timer = 0;
if (CurrentFrame++ == numberOfFrames - 1)
CurrentFrame = 0;
rect.X = CurrentFrame * width;
rect.Y = 0;
}
}
public void Render(SpriteBatch sb, Vector2 position, Color color)
{
sb.Draw(aniTex, position, rect, color, 0, Vector2.Zero, 2.0f, SpriteEffects.None, 0);
}
If the problem is simply the looping issue, you can just remove the bit of code in your update that causes it to loop (the if (CurrentFrame++ == numberOfFrames - 1) CurrentFrame = 0;) All you would need to do to get the animation to play again, is set the current frame back to 0 when you want it to play. (To stop it drawing, just only do the draw call when you want it.)
If you're looking for a way to structure it (which is how I initially interpreted your question!) why not have a Animated class which you set up with whatever objects you want animated. Something along the lines of
class AnimatedObject
{
Texture2D texture;
Rectangle currentRectangle;
Rectangle frameSize;
int frameCount;
int currentFrame;
bool isRunning;
public AnimatedObject(Texture2D lTexture, Rectangle lFrameSize, int lFrameCount)
{
texture = lTexture;
frameSize = lFrameSize;
currentRectangle = lFrameSize;
currentFrame = 0;
}
public void Pause()
{
isRunning = false;
}
public void Resume()
{
isRunning = true;
}
public void Restart()
{
currentFrame = 0;
isRunning = true;
}
public void Update()
{
if(isRunning)
{
++currentFrame;
if(currentFrame == frameCount)
{
currentFrame = 0;
}
currentRectangle.X = frameSize.Width * currentFrame;
}
}
public void Draw(SpriteBatch spriteBatch)
{
if(isRunning)
{
spriteBatch.Draw(texture, currentRectangle, Color.White);
}
}
}
Obviously you can extend this to be more sophisticated (eg using your timers to choose when to move frames etc.
You can stop the animation, for example, by removing the object with the animation from the game when the animation has finished.
Or otherwise, you could set the currentFrame to an illegal value (e.g. -1) when the animation is done, and test for that.
public void Update(GameTime gametime)
{
if (currentFrame >= 0)
{
timer += gametime.ElapsedGameTime.Milliseconds;
if (timer >= msBetweenFrames)
{
timer = 0;
currentFrame++;
if (currentFramr >= numberOfFrames - 1)
currentFrame = -1;
rect.X = CurrentFrame * width;
rect.Y = 0;
}
}
}
public void Render(SpriteBatch sb, Vector2 position, Color color)
{
if (currentFrame >= 0)
sb.Draw(aniTex, position, rect, color, 0, Vector2.Zero, 2.0f, SpriteEffects.None, 0);
}
Firstly, I would like to say sorry for making another thread asking the same question (more or less), but I am desperate for an answer and the other thread went dead.
I am currently working on a project for school in which I am attempting to make a simple 2d shooter. Problem is, I don't know how to implement collision detection between my two lists (being bullets and enemies as stated in title). I am very new to programming and have been using various tutorials as a guide, some tutorials say to use a nested for loop and if statement while I have seen others using an if statement, oh and I'm using the rectangle collision method not the pixel by pixel one I think it was called. Thanks in advance! :)
Here is my code:
Main:
namespace Software_Design_Major_Project
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D ship; // Declaring the sprite
Vector2 shipposition = Vector2.Zero; // Creating a vector for the sprite.
List<bullets> bullets = new List<bullets>(); // a list is created here so that there can be multiple copies of this item at once without writing the extra code.
Texture2D texture;
KeyboardState pastkey;
//bullet sound effect.
SoundEffect effect;
List<enemies> Enemies = new List<enemies>();
Random random2 = new Random();
float spawn = 0;
public enum GameState
{
MainMenu,
Playing,
}
GameState CurrentGameState = GameState.MainMenu;
int screenWidth = 600, screenHeight = 480;
cButton play;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
//changes width of screen to 600px.
graphics.PreferredBackBufferWidth = 600;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
// This statement positions the ship.
ship = Content.Load<Texture2D>("ship"); // Loads the ship into the memory.
shipposition = new Vector2((graphics.GraphicsDevice.Viewport.Width / 2) - (ship.Width / 2), 420);
// loads bullet sprite
texture = Content.Load<Texture2D>("bullet");
graphics.PreferredBackBufferWidth = screenWidth;
graphics.PreferredBackBufferHeight = screenHeight;
graphics.ApplyChanges();
IsMouseVisible = true;
play = new cButton(Content.Load<Texture2D>("play"), graphics.GraphicsDevice);
play.setPosition(new Vector2(225, 220));
effect = Content.Load<SoundEffect>("laser");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
spawn += (float)gameTime.ElapsedGameTime.TotalSeconds;
// spawns enemy every second.
foreach (enemies enemy in Enemies)
enemy.update(graphics.GraphicsDevice);
MouseState mouse = Mouse.GetState();
switch (CurrentGameState)
{
case GameState.MainMenu:
if (play.isClicked == true)
CurrentGameState = GameState.Playing;
play.Update(mouse);
break;
case GameState.Playing:
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.E))
{
Exit();
}
break;
}
// Allows the ship to move left and stops the ship going off the screen.
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Left) && shipposition.X >= 0)
{
shipposition.X -= 7;
}// same as above except for the right direction.
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right) && shipposition.X < ((graphics.GraphicsDevice.Viewport.Width) - (ship.Width)))
{
shipposition.X += 7;
}
// this prevents the player from holding down space to spam bullets.
if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastkey.IsKeyUp(Keys.Space))
{
bullets bullet = new bullets(texture);
// the ships coordinates are gathered from the top left hand corner of the sprites rectangle therefore 'new Vector2(shipposition.X + 32, shipposition.Y)' had to
// be added rather than just = 'shipposition' to avoid having the bullets shoot from the wing.
bullet.position = new Vector2(shipposition.X + 32, shipposition.Y);
bullets.Add(bullet);
effect.Play();
}
pastkey = Keyboard.GetState();
//calls upon the update method from the bullets class.
foreach (bullets bullet in bullets)
bullet.update();
LoadEnemies();
base.Update(gameTime);
}
public void LoadEnemies()
{
int randX = random2.Next(10, 540);
if (spawn <= 1)
{
spawn = 0;
//limits amount of enemies on screen to 5.
if (Enemies.Count() < 5)
Enemies.Add(new enemies(Content.Load<Texture2D>("enemy"), new Vector2(randX, -100)));
}
for (int i = 0; i < Enemies.Count; i++)
{
if (!Enemies[i].enemyVisble)
{
//removes the enemies when they go off screen.
Enemies.RemoveAt(i);
i--;
}
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// calls draw method in bullets class
foreach (bullets bullet in bullets)
{
bullet.Draw(spriteBatch);
}
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
spriteBatch.Draw(ship, shipposition, Color.White); // draws ship sprite
switch (CurrentGameState)
{
case GameState.MainMenu:
play.draw(spriteBatch);
spriteBatch.Draw(Content.Load<Texture2D>("menu"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
break;
case GameState.Playing:
break;
}
foreach (enemies enemy in Enemies)
{
enemy.draw(spriteBatch);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Bullets Class:
namespace Software_Design_Major_Project
{
class bullets // A new class needs to be created to allow for bullets.
{
public Texture2D texture;
public Vector2 position;
public bool isvisible;
public bullets(Texture2D newtexture)
{
texture = newtexture;
isvisible = false;
}
public void update()
{
position.Y -= 3; // velocity of the bullet
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Begin();
spriteBatch.Draw(texture, position, Color.White);
spriteBatch.End();
}
}
}
Enemies Class:
namespace Software_Design_Major_Project
{
public class enemies
{
public Texture2D enemyTexture;
public Vector2 enemyPosition;
public bool enemyVisble = true;
public float enemyMoveSpeed;
public int Value;
Random random = new Random();
int randY;
public enemies (Texture2D newEnemyTexture, Vector2 newEnemyPosition)
{
enemyTexture = newEnemyTexture;
enemyPosition = newEnemyPosition;
randY = random.Next(1, 4);
enemyMoveSpeed = randY;
enemyVisble = true;
Value = 100;
}
public void update(GraphicsDevice graphics)
{
enemyPosition.Y += enemyMoveSpeed;
if (enemyPosition.Y > 500)
enemyVisble = false;
}
public void draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(enemyTexture, enemyPosition, Color.White);
enemyVisble = true;
}
}
}
You have several ways to do it... one of them maybe add a radio property to enemies and bullets....
for (int bi=0; bi<bullets.count; )
{
bool should_destroy_bullet = false;
Bullet b = bullets[bi];
for (int ei=0; ei<enemies.count; )
{
Enemy e = ememies[ei];
if (b.radio + e.radio < Vector2.Distance(b.Pos, e.Pos)) // Check collision
{
e.Died();
enemies[ei] = enemies[enemies.Count-1];
enemies.RemoveAt(enemies.Count-1);
should_destroy_bullet = true; // This lets a bullet kill more than one enemy
} else ei++;
}
if (should_destroy_bullet) {
b.Died();
bullets[bi] = bullets[bullets.count-1];
bullets.RemoveAt(bullets.count-1);
} else bi++;
}
Or you can build a rectangle for each sprite and check if they intersects....
if (b.Bounds.Intersects(e.Bounds)) ....
The Pythagorean theorem could work for you.(A squared plus B squared = C squared)
Make your players and enemies have a radius.Put this in your constructor.
public float radius = 15;
Put the following in a update void/subclass so that it happens every second.
Make a float the X location of your player and subtract the X location of the bullet. Square it.
float XDist = Math.Pow(player1.location.X - bullet.location.X,2);
Make a float the Y location of your player and subtract the Y location of the bullet.Square it.
float YDist = Math.Pow(player1.location.X - bullet.location.X,2);
Make a float to figure out the square root of the sum of Xdist and Ydist.
float actualDist = Math.Sqrt(Xdist + Ydist);
Now if the radius of your player is less than the distance between the player and the bullet, the bullet has hit the player.
if(actualDist < radius)
bullethit == true;