I started learning c# monogame a few weeks ago and i wanted to start a project.
The project I choose is a brickbreaker clone and everything goes well. But I stumbled on something that I have spent hours looking on google for without a answer.
The problem I have is with collision detection between the ball and the bricks.
Between the paddle and the ball work I have a working solution.
Which is :
// Collision between the ball and player
public void Collision(Player player, Ball ball)
{
MinX = (int)player.PlayerPosition.X - ball.Width;
MaxX = (int)player.PlayerPosition.X + player.Width + ball.Width;
MinY = 0;
MaxY = (int)player.PlayerPosition.Y - ball.Height;
Rectangle BallRectangle = new Rectangle((int)ball.BallPosition.X, (int)ball.BallPosition.Y, ball.Width, ball.Height);
Rectangle PlayerRectangle = new Rectangle((int)player.PlayerPosition.X, (int)player.PlayerPosition.Y, player.Width, player.Height);
if (BallRectangle.Intersects(PlayerRectangle))
{
ball.BallPosition.Y = MathHelper.Clamp(ball.BallPosition.Y, MinY, MaxY);
ball.BallPosition.X = MathHelper.Clamp(ball.BallPosition.X, MinX, MaxX);
ball.BallSpeed.Y *= -1;
float BallMiddlePoint = ball.BallPosition.X + (ball.Width / 2);
float PlayerMiddlePoint = player.PlayerPosition.X + (player.Width / 2);
ball.BallSpeed.X = (BallMiddlePoint - PlayerMiddlePoint) / 10 + ball.ExtraSpeedOverTime;
}
}
Now back to my problem, I use Rectangle.Intersect(Rectangle) to check for collision.
The main problem is: How do I let the ball bounce correctly on the bricks?
I hope I give enough information.
My ball class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace BrickBreakerV2
{
class Ball
{
// The texture of the ball
Texture2D BallTexture;
// The position of the ball
public Vector2 BallPosition;
// The speed of the ball
public Vector2 BallSpeed;
// The speed that gets added over time
public float ExtraSpeedOverTime;
// Time values used in incrementing the speed over time
TimeSpan IncreaseSpeed;
TimeSpan PreviousSpeedIncrease;
// The "active" state of the ball
public bool Active;
// The state of movement of the ball
public bool Moveball;
// The Width of the ball
public int Width
{
get { return BallTexture.Width; }
}
// The Height of the ball
public int Height
{
get { return BallTexture.Height; }
}
// Construct a class for Boundaries
CollisionHandler Collision = new CollisionHandler();
public void Initialize(ContentManager Content, GraphicsDevice graphicsDevice, Player player)
{
BallTexture = Content.Load<Texture2D>("Graphics\\ball.png");
BallPosition = new Vector2(player.PlayerPosition.X + (player.Width / 2) - (Width / 2),
player.PlayerPosition.Y - Height - 5);
BallSpeed = new Vector2(5.0f, -5.0f);
ExtraSpeedOverTime = 1.0f;
IncreaseSpeed = TimeSpan.FromSeconds(12f);
PreviousSpeedIncrease = TimeSpan.Zero;
Active = true;
Moveball = false;
}
public void Update(GraphicsDevice graphicsDevice, GameTime gameTime, Player player)
{
if (Moveball)
{
BallPosition += BallSpeed;
}
else
{
BallPosition = new Vector2(player.PlayerPosition.X + (player.Width / 2) - (Width / 2),
player.PlayerPosition.Y - Height - 5);
}
if (gameTime.TotalGameTime - PreviousSpeedIncrease > IncreaseSpeed)
{
ExtraSpeedOverTime += 0.01f;
BallSpeed.X *= ExtraSpeedOverTime;
BallSpeed.Y *= ExtraSpeedOverTime;
PreviousSpeedIncrease = gameTime.TotalGameTime;
}
// Makes sure that the ball doesn't go to fast
if (BallSpeed.X > 10.50f)
BallSpeed.X = 10.50f;
if (BallSpeed.Y > 10.50f)
BallSpeed.Y = 10.50f;
if (BallSpeed.X < -10.50f)
BallSpeed.X = -10.50f;
if (BallSpeed.Y < -10.50f)
BallSpeed.Y = -10.50f;
// Keep the ball in the boundaries
Collision.GetBoundaries(graphicsDevice, this);
// Detect collision between ball and player
Collision.Collision(player, this);
}
public void Update(Brick brick)
{
// Detect collision between ball and brick
Collision.Collision(this, brick);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(BallTexture, BallPosition, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
}
}
}
My Brick class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace BrickBreakerV2
{
class Brick
{
// The texture of the brick
public Texture2D BrickTexture;
// The position of the bricks
public Vector2 BrickPosition;
// The color tint of the brick
public Color ColorTint;
// The "active" state of the brick
public bool Active;
// The width of the brick
public int Width
{
get { return BrickTexture.Width; }
}
// The height of the brick
public int Height
{
get { return BrickTexture.Height; }
}
// Construct a class for collisionhandler
CollisionHandler Collision;
public void Initialize(ContentManager Content)
{
BrickTexture = Content.Load<Texture2D>("Graphics\\brick.png");
BrickPosition = new Vector2(600, 500);
Active = true;
ColorTint = Color.White;
Collision = new CollisionHandler();
}
public void Update(Ball ball)
{
Collision.Collision(ball, this);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(BrickTexture, BrickPosition, null, ColorTint, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
}
}
}
And my code block that handles the collision between the ball and bricks in CollisionHandler.cs:
// Collision between ball and brick
public void Collision(Ball ball, Brick brick)
{
Rectangle BallRectangle = new Rectangle((int)ball.BallPosition.X, (int)ball.BallPosition.Y, ball.Width, ball.Height);
Rectangle BrickRectangle = new Rectangle((int)brick.BrickPosition.X, (int)brick.BrickPosition.Y, brick.Width, brick.Height);
if (BallRectangle.Intersects(BrickRectangle))
{
int XOverlap;
int YOverlap;
if (BallRectangle.Center.X < BrickRectangle.Center.X)
{
XOverlap = (BallRectangle.X + ball.Width) - BrickRectangle.X;
}
else
{
XOverlap = (BrickRectangle.X + brick.Width) - BallRectangle.X;
}
if (BallRectangle.Center.Y < BrickRectangle.Center.Y)
{
YOverlap = (BallRectangle.Y + ball.Height) - BrickRectangle.Y;
}
else
{
YOverlap = (BrickRectangle.Y + brick.Height) - BallRectangle.Y;
}
if (XOverlap == YOverlap)
{
ball.BallSpeed.X *= -1;
ball.BallSpeed.Y *= -1;
}
else if (XOverlap < YOverlap)
{
ball.BallSpeed.X *= -1;
}
else
{
ball.BallSpeed.Y *= -1;
}
brick.Active = false;
}
}
I want to help you, but I'm not going to debug your code. Fortunately basic 2D collision detection and brick breaker clones have been done many many times before.
A quick google search turned up the following tutorial. I haven't done it myself but if I where you I would start here:
http://xnagpa.net/xna4beginner.php
Good luck.
Related
everyone!
I'm making a game on Unity 2D and I encountered a problem. I need to dig specific tile of snow when player is holding LeftShift and is in the trigger with tag "Snow" (the tilemap does have such a tag). I decided to change the scale, since it's the most understandable for player of variants that i thought (making the sprite darker, destroying it, etc.)
Right now I have this code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class SnowTaking : MonoBehaviour
{ //Tile variables
public Tilemap tilemap;
public ITilemap iTilemap;
public Tile whiteTile;
public Tile redTile;
public Tile greenTile;
public Tile blueTile;
void OnTriggerStay2D(Collider2D other) {
if(other.gameObject.tag == "Snow") {
if(Input.GetKey(KeyCode.LeftShift)) {
//При нажатии LeftShift
float x = gameObject.transform.position.x;
float y = gameObject.transform.position.y;
float z = 0;
Vector3 position = new Vector3(x, y, z);
Vector3Int tilePosition = tilemap.WorldToCell(position);
Tile currentTile = tilemap.GetTile<Tile>(tilePosition);
//Conditions for each type of snow
if(whiteTile == currentTile) {
//Scaling tile here
Debug.Log("White");
} else if(redTile == currentTile) {
//Scaling tile here
Debug.Log("Red");
} else if(greenTile == currentTile) {
//Scaling tile here
Debug.Log("Green");
} else if(blueTile == currentTile) {
//Scaling tile here
Debug.Log("Blue");
} else {
Debug.Log("None");
}
}
}
}
}
What can I use to scale tiles? Thank you in advance!
I tried few things already:
First of all, I searched through the net (especially in the documentation) functions, that do something with the exact tile;
Then I tried to use Matrix4x4 to scale tile, but it didn't work as intended (it didn't work at all, but at least there were no errors);
currentTile.transform = Matrix4x4.Scale(new Vector3(0.5f, 0.5f, 1));
When I was out of options, I tried to do something myself, and used Sprites. Of course, it didn't work;
Sprite currentSprite = currentTile.sprite;
currentSprite.localScale -= new Vector3(0.01f, 0.01f, 0);
Then I searched such a question here, on StackOverflow, but didn't find anything that would help me, so here my quesion is!
You can use tilemap.SetTransformMatrix();
In your case, instead of
currentTile.transform = Matrix4x4.Scale(new Vector3(0.5f, 0.5f, 1));
You can use tilemap.SetTransformMatrix(tilePosition, Matrix4x4.Scale(new Vector3(0.5f, 0.5f, 1)));
If you want to animate it :
void Update() {
if (Input.GetKey(KeyCode.LeftShift)) {
time = 0f;
}
if (time < scaleDuration) {
time += Time.deltaTime;
var scaleValue = _animationCurve.Evaluate(time / scaleDuration);
tilemap.SetTransformMatrix(tilePosition, Matrix4x4.Scale(new Vector3(scaleValue, scaleValue, 1)));
}
I have been working on a C# & SFML remake of one of my LWJGL engines. So far it's going great, but, when I tried to copy/convert over my collision code, things didn't go so well.
Here's my code for the player/entity class, bounding box, and the game code.
Entity:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML.Graphics;
using SFML.System;
using SFML.Window;
namespace FastSrc_CS.Core
{
public class FSEntity
{
public Vector2f Position, Size;
public Color EColor;
public RectangleShape sprite;
public BoundingBox Bounds;
public bool canMove;
public float VelX, VelY;
public FSEntity()
{
}
public virtual void Init(Vector2f pos, Vector2f size, Color color)
{
Position = pos;
Size = size;
EColor = color;
sprite = new RectangleShape();
sprite.FillColor = EColor;
sprite.Position = Position;
sprite.Size = Size;
//sprite.Origin = new Vector2f(size.X / 2, size.Y / 2);
Bounds = new BoundingBox(Position, Size);
}
public void SetVelX(float x)
{
VelX = x;
}
public void SetVelY(float x)
{
VelY = x;
}
public Vector2f GetOrigin()
{
return new Vector2f(Size.X / 2, Size.Y / 2);
}
public virtual void Update()
{
}
public void UpdatePos()
{
Position.X += VelX;
Position.Y += VelY;
sprite.Position = Position;
Bounds.UpdateBounds(Position, Size);
}
public virtual void Render(RenderWindow w)
{
w.Draw(sprite);
}
}
}
Player:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML.Graphics;
using SFML.System;
using SFML.Window;
namespace FastSrc_CS
{
class Player : Core.FSEntity
{
public float speed = 6f;
public override void Init(Vector2f pos, Vector2f size, Color color)
{
canMove = true;
base.Init(pos, size, color);
}
public override void Update()
{
base.Update();
Movement();
Position.X += VelX;
Position.Y += VelY;
sprite.Position = Position;
Bounds.UpdateBounds(Position, Size);
}
public void Movement()
{
if (Keyboard.IsKeyPressed(Keyboard.Key.A) && canMove == true)
{
SetVelX(-speed);
SetVelY(0);
}
else if (Keyboard.IsKeyPressed(Keyboard.Key.D) && canMove == true)
{
SetVelX(speed);
SetVelY(0);
}
else if (Keyboard.IsKeyPressed(Keyboard.Key.W) && canMove == true)
{
SetVelY(-speed);
SetVelX(0);
}
else if (Keyboard.IsKeyPressed(Keyboard.Key.S) && canMove == true)
{
SetVelY(speed);
SetVelX(0);
}
else
{
SetVelX(0);
SetVelY(0);
}
}
public override void Render(RenderWindow w)
{
base.Render(w);
}
}
}
Bounding Box:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML.Graphics;
using SFML.System;
using SFML.Window;
namespace FastSrc_CS.Core
{
public class BoundingBox
{
public FloatRect Rectangle;
public BoundingBox(Vector2f pos, Vector2f size)
{
Rectangle = new FloatRect(pos, size);
}
public bool Collide(BoundingBox b)
{
bool col = false;
if (this.Rectangle.Intersects(b.Rectangle))
{
col = true;
}
else
{
col = false;
}
return col;
}
public void UpdateBounds(Vector2f pos, Vector2f size)
{
Rectangle.Width = size.X;
Rectangle.Height = size.Y;
Rectangle.Left = pos.X;
Rectangle.Top = pos.Y;
}
}
}
Game:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FastSrc_CS.Core;
using SFML.Graphics;
using SFML.System;
using SFML.Window;
namespace FastSrc_CS
{
public class Game : FSGame
{
Player p = new Player();
Wall w = new Wall();
public override void Init()
{
p.Init(new Vector2f(400, 300), new Vector2f(32, 32), Color.Red);
w.Init(new Vector2f(100, 100), new Vector2f(32, 32), Color.Blue);
Entities.Add(p);
Entities.Add(w);
}
public override void Update()
{
Console.WriteLine(p.Position.X);
//COLLISION CODE FOR WALLS
if (p.Bounds.Collide(w.Bounds))
{
//Right Collision
if (p.VelX > 0)
{
Console.WriteLine("Right Collision");
p.canMove = false;
p.Position.X = w.Position.X - 32;
p.SetVelX(0);
}
else if (p.VelX < 0)
{
Console.WriteLine("Left Collision");
p.canMove = false;
p.Position.X = w.Position.X + 32;
p.SetVelX(0);
}
if (p.VelX == 0)
{
p.canMove = true;
}
}
Entities.ForEach(k => k.Update());
}
public override void Render(RenderWindow w)
{
Entities.ForEach(k => k.Render(w));
}
}
}
The issue lies within the "game" class in this region:
//COLLISION CODE FOR WALLS
if (p.Bounds.Collide(w.Bounds))
{
//Right Collision
if (p.VelX > 0)
{
Console.WriteLine("Right Collision");
p.canMove = false;
p.Position.X = w.Position.X - 32;
p.SetVelX(0);
}
else if (p.VelX < 0)
{
Console.WriteLine("Left Collision");
p.canMove = false;
p.Position.X = w.Position.X + 32;
p.SetVelX(0);
}
if (p.VelX == 0)
{
p.canMove = true;
}
}
When I run this, the player will stop moving, but he will be slightly implanted into the wall. I know what you're thinking, "move the if statement that make p.canMove = true outside of the collision's if statement." I have tried this, and it results in the player bouncing back-and-forth with the cube. I have tried different methods to the point where I thought about leaving this code out. I decided to revert back to Stack Overflow to see if someone could help me out. Thanks in advance.
I don't think the problem with your code is your engine at all - given the result and, after scanning the code, it seems to be fine. Since your player clips into the wall, the hard-coded value of 32 for both your player and your wall, chances are, is incorrect. Try this:
if (p.VelX > 0)
{
Console.WriteLine("Right Collision");
p.canMove = false;
//move the right of our player to the left of the wall by setting
//his x to the wall's x minus his width.
p.Position.X = w.Position.X - p.Size.Width;
p.SetVelX(0);
}
else if (p.VelX < 0)
{
Console.WriteLine("Left Collision");
p.canMove = false;
//Move the left of our player to the right of the wall, or
//the wall's x plus the wall's width
p.Position.X = w.Position.X + w.Size.Width;
p.SetVelX(0);
}
I hope this helped.
EDIT
Actually, I think I found another problem. When you change the player’s position after moving his X after collision detection, you forget to call the UpdatePos() method. Thus, you are moving his position but not his actual rectangle, which may be causing an error. Rather, after you move his x, immediately call UpdatePos()
In my Boss class, it says that my List "bulletlist" is null and give me a run time error but I see no errors can someone tell me what I am doing wrong? The games runs fine if I don't update my boss class. I put in my main class, player class, and bullet class, in as well.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 Space_Shooter
{
public class Boss
{
public Texture2D texture, bulletTexture , healthBarTexture;
public Vector2 position;
public float randomPositionX, randomPositionY , bulletDamage, shipDamage , health , MaxBullets;
public int speed, bulletSpeed , bulletDelayTime, bulletDelayTimeReset;
public bool isVisible;
public Rectangle boundingBox , bossHealthBar;
public List<Bullet> bulletList;
Random random = new Random();
Player p = new Player();
public Boss(Texture2D newTexture, Vector2 newPosition, Texture2D newBulletTexture)
{
texture = newTexture;
position = newPosition;
bulletTexture = newBulletTexture;
bulletList = new List<Bullet>();
bulletSpeed = 25;
bulletDamage = 25;
shipDamage = p.health / 2;
health = 2000;
bulletDelayTime = 30;
bulletDelayTimeReset = 30;
MaxBullets = 30;
isVisible = true;
}
public Boss()
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
spriteBatch.Draw(healthBarTexture, bossHealthBar, Color.White);
foreach (Bullet b in bulletList)
{
b.Draw(spriteBatch);
}
}
public void loadContent(ContentManager content)
{
texture = content.Load<Texture2D>("Ship4");
bulletTexture = content.Load<Texture2D>("EnemyBullet");
healthBarTexture = content.Load <Texture2D> ("healthbar");
}
public void update(GameTime gameTime)
{
updateBullets();
Shoot();
checkBossCollison();
// Making bosses health bar
bossHealthBar = new Rectangle((int)position.X, (int)position.Y + 30, (int)health, 25);
// Creating collision box for boss
boundingBox = new Rectangle((int)position.X, (int)position.Y, (int)texture.Width, (int)texture.Height);
randomPositionX = random.Next(50, 750);
randomPositionY = random.Next(50, 400);
// setting boss movement
if (position.Y > randomPositionY)
position.Y -= speed;
if (position.Y < randomPositionY)
position.Y += speed;
if (position.X > randomPositionX)
position.X -= speed;
if (position.X < randomPositionX)
position.X += speed;
}
public void updateBullets()
{
// for each bullet in the bulletList: update the movement and if the bullet hits the bottom of the screen, remove it from the list
foreach (Bullet b in bulletList)
{
//make a Bounding box for every bullet in the bulletList
b.boundingBox = new Rectangle((int)b.position.X, (int)b.position.Y, b.texture.Width, b.texture.Height);
// set movement for the bullets
// if a bullet hits the bottom of the screen, then make visable false
if (b.position.Y >= 850)
b.isVisible = false;
// go through the bulletList and see if any of the bullets are not visible, if they are not then remove that bullet from the bulletList
for (int i = 0; i < bulletList.Count; i++)
{
if (!bulletList[i].isVisible)
{
bulletList.RemoveAt(i);
i--;
}
}
}
}
public void checkBossCollison()
{
// if boss ship comes in bcontact with player ship player is damaged
if (boundingBox.Intersects(p.boundingBox))
p.health -= shipDamage;
// if player bullets hit boss then boss is damaged and player bullets go invisible
for(int i = 0; i < p.bulletList.Count; i++)
{
if (boundingBox.Intersects(p.bulletList[i].boundingBox))
{
health -= p.bulletDamage;
p.bulletList[i].isVisible = false;
if (health == 0)
isVisible = false;
}
}
// if boss shoots player player is damaged and boss bullets go invisible
for(int i = 0; i < bulletList.Count; i++)
{
if (p.boundingBox.Intersects(bulletList[i].boundingBox))
{
p.health -= bulletDamage;
bulletList[i].isVisible = false;
}
}
}
public void Shoot()
{
// shoot only if our bullet delay resets
if (bulletDelayTime >= 0)
bulletDelayTime--;
// If bulletDelay is at 0, create a new bullet at enemy position, make it visible on the screen, then add that bullet to bulletList
if (bulletDelayTime <= 0)
{
// create new bullet and center it front and center of enemy ship
Bullet newBullet = new Bullet(bulletTexture);
newBullet.position = new Vector2(position.X + texture.Width / 2 - newBullet.texture.Width / 2, position.Y + 30);
newBullet.isVisible = true;
if (bulletList.Count() < MaxBullets)
bulletList.Add(newBullet);
}
// Reset bullet delay
if (bulletDelayTime == 0)
bulletDelayTime = bulletDelayTimeReset;
}
}
}
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 Space_Shooter
{
// Main
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
// variabls
SpriteBatch spriteBatch;
Random random = new Random();
Random randomNumberOfAsteroids = new Random();
int maxNumberOfAsteroids;
int numbersOfInvisibleEnemies;
// Lists
List<Asteroid> asteroidList = new List<Asteroid>();
List<Enemy> enemyList = new List<Enemy>();
// making player and starfield objects
Player P = new Player();
StarField starfield = new StarField();
Enemy E = new Enemy();
Boss boss = new Boss();
// Construtor
public Game1()
{
graphics = new GraphicsDeviceManager(this);
// setting full scren to off and setting screen measurments
graphics.IsFullScreen = false;
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 850;
maxNumberOfAsteroids = 5; // Set the max number of asteroids that will be on the screen at one time ( randomly 0 to Max number)
numbersOfInvisibleEnemies = 0;
// Setting Title of screen
this.Window.Title = "Star Voyage";
Content.RootDirectory = "Content";
}
// Initialize
protected override void Initialize()
{
base.Initialize();
}
// Load content
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// Call Load content function from Player.cs
P.LoadContent(Content);
starfield.LoadContent(Content);
boss.loadContent(Content);
}
// unload content
protected override void UnloadContent()
{
}
// update game screen
protected override void Update(GameTime gameTime)
{
// updating enemies and checking collision of thier ships to player ship
foreach (Enemy e in enemyList)
{
if (e.boundingBox.Intersects(P.boundingBox))
{
P.health -= e.enemyShipDamage;
e.isVisible = false;
}
// check enemy bullet collision with player ship
for (int i = 0; i < e.bulletList.Count; i++)
{
if (P.boundingBox.Intersects(e.bulletList[i].boundingBox))
{
P.health -= e.enemyBulletDamage;
e.bulletList[i].isVisible = false;
}
}
// check player bullet collision with enemy ships
for (int i = 0; i < P.bulletList.Count; i++)
{
if (e.boundingBox.Intersects(P.bulletList[i].boundingBox))
{
// when bullet hits enemy ship they disapear
P.bulletList[i].isVisible = false;
e.health -= P.bulletDamage;
if (e.health == 0)
e.isVisible = false;
}
}
e.Update(gameTime);
}
// for each asteroid in the asteroid list call the update function from Asteroid.cs
foreach (Asteroid a in asteroidList)
{
//Check to see if any of the arteroids are colliding with player ship
if (a.boundingBox.Intersects(P.boundingBox))
{
P.health -= a.asteroidDamage; // taking 20 off of player health bar each time the play shit is hit by an asteroid
a.isVisible = false;
}
// going through bullet list to see if any bullets come in contact with asteroids if they do set both the bullet and the asteroid to not visible
for (int i = 0; i < P.bulletList.Count; i++)
{
if (a.boundingBox.Intersects(P.bulletList[i].boundingBox))
{
a.isVisible = false;
P.bulletList.ElementAt(i).isVisible = false;
}
}
a.Update(gameTime);
}
loadAsteroids();
loadEnemyShips();
// Call fucntion Update from Player,cs
P.Update(gameTime);
// Call function update from StarField.cs
starfield.Update(gameTime);
boss.update(gameTime);
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
// Draw to game screen
protected override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
starfield.Draw(spriteBatch);
foreach (Asteroid a in asteroidList)
{
a.Draw(spriteBatch);
}
foreach (Enemy e in enemyList)
{
e.Draw(spriteBatch);
}
// Backgound color
GraphicsDevice.Clear(Color.CornflowerBlue);
// Call Draw fuction from Player.cs
P.Draw(spriteBatch);
// boss.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
// Load Asteroids function
public void loadAsteroids()
{
// creating random variabls for X and Y positions of asteroids
int random_x = random.Next(0, 750), random_y = random.Next(-600, -50);
// if the number of Asteroids on the screen is less than the variable (numberOfAsteroids), create more untill it is not
if (asteroidList.Count() < randomNumberOfAsteroids.Next(0, maxNumberOfAsteroids))
{
asteroidList.Add(new Asteroid(Content.Load<Texture2D>("asteroid"), new Vector2(random_x, random_y)));
}
// if any of the asteroids from the list are destroyed (not visible) then remove them from the list
for (int i = 0; i < asteroidList.Count; i++)
{
if (!asteroidList[i].isVisible)
{
asteroidList.RemoveAt(i);
i--;
}
}
}
public void loadEnemyShips()
{
// creating random variabls for X and Y positions of asteroids
int random_x = random.Next(0, 750), random_y = random.Next(-600, -50);
// if the number of enemies on the screen is less than the variable (numberOfEnemies), create more untill it is not
if (enemyList.Count() < 3 && numbersOfInvisibleEnemies <= 9)
{
enemyList.Add(new Enemy(Content.Load<Texture2D>("enemyship"), new Vector2(random_x, random_y), Content.Load<Texture2D>("EnemyBullet")));
}
// keeping count of the number of destroied enemies
for (int i = 0; i < enemyList.Count; i++)
{
if (!enemyList[i].isVisible)
numbersOfInvisibleEnemies += 1;
// if any of the enemies from the list are destroyed (not visible) or if they go passed the bottom of the screen, then remove them from the list
if (!enemyList[i].isVisible || enemyList[i].position.Y >= 840)
{
enemyList.RemoveAt(i);
--i;
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 Space_Shooter
{
// main
public class Player
{
// Variables
public Texture2D texture , bulletTexture , healthTexture;
public Vector2 position , healthBarPosition;
public int speed;
public float health , bulletDamage , bulletDelay , bulletDelayReset;
double bulletCount;
// Lists
public List<Bullet> bulletList;
// Collision variables
public bool isColliding;
public Rectangle boundingBox , healthRectangle;
// Constructor
public Player()
{
bulletList = new List<Bullet>();
bulletDelay = 1; // for faster fire rate reduce number
bulletDelayReset = 5; // bullet delay reset has to be the same number as bullet delay
bulletCount = 1000; // amount of bullets alowed on the screen at a time
texture = null;
health = 200;
bulletDamage = 3;
healthBarPosition = new Vector2(50, 50);
position = new Vector2 (300, 300) ;
speed = 10;
isColliding = false;
}
// Load content
public void LoadContent(ContentManager Content)
{
texture = Content.Load<Texture2D>("player01");
bulletTexture = Content.Load<Texture2D>("playerbullet");
healthTexture = Content.Load<Texture2D>("healthbar");
}
// Draw
public void Draw(SpriteBatch spritebatch)
{
spritebatch.Draw(texture, position, Color.White);
spritebatch.Draw(healthTexture, healthRectangle, Color.White);
// For each Bullet b (bullet) in our bullet list, draw the bullet
foreach (Bullet b in bulletList)
{
b.Draw(spritebatch);
}
}
// Update
public void Update(GameTime gametime)
{
// Checking for keyboard input every frame
KeyboardState keystate = Keyboard.GetState();
// setting collision box for player ship
boundingBox = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
//set rectangle for healthbar (where to print on the screen and the height and width (25) is height (health is width
healthRectangle = new Rectangle((int) healthBarPosition.X, (int) healthBarPosition.Y, (int)health, 25);
if (keystate.IsKeyDown(Keys.Space))
{
shoot();
}
updateBullets();
// ship controls
if (keystate.IsKeyDown(Keys.W))
position.Y = position.Y - speed;
if (keystate.IsKeyDown(Keys.S))
position.Y = position.Y + speed;
if (keystate.IsKeyDown(Keys.A))
position.X = position.X - speed;
if (keystate.IsKeyDown(Keys.D))
position.X = position.X + speed;
// Keep ship in screen bounds
if (position.X <= 0)
position.X = 0;
if (position.X >= 800 - texture.Width)
position.X = 800 - texture.Width;
if (position.Y <= 0)
position.Y = 0;
if (position.Y >= 850 - texture.Height)
position.Y = 850 - texture.Height;
}
// Shoot Function, used to set the starting position of the players bullet
public void shoot()
{
// Shoot only if the bullet delay resets
if (bulletDelay >= 0)
bulletDelay--;
// If bulletDelay is at 0, create a new bullet at player position, make it visible on the scrren, then add that bullet to bulletList
if (bulletDelay <= 0)
{
Bullet newBullet1 = new Bullet(bulletTexture);
newBullet1.position = new Vector2(position.X - newBullet1.texture.Width / 2, position.Y + 30);
newBullet1.isVisible = true;
Bullet newBullet2 = new Bullet(bulletTexture);
newBullet2.position = new Vector2(position.X + 64 - newBullet2.texture.Width / 2, position.Y + 30);
newBullet2.isVisible = true;
// control the amount of bullets on the screen by increasing number
if (bulletList.Count() < bulletCount)
bulletList.Add(newBullet1);
bulletList.Add(newBullet2);
}
// Reset bullet dleay
if (bulletDelay == 0)
bulletDelay = bulletDelayReset;
}
public void updateBullets()
{
// for each bullet in the bulletList: update the movement and if the bullet hits the top of the screen, remove it from the list
foreach (Bullet b in bulletList)
{
// set movement for the bullets
b.position.Y = b.position.Y - b.speed;
//make a Bounding box for every bullet in the bullet list
b.boundingBox = new Rectangle((int)b.position.X, (int)b.position.Y, b.texture.Width, b.texture.Height);
// if a bullet hits the top of the screen, then make visable false
if (b.position.Y <= 0)
b.isVisible = false;
}
// go through the bulletList and see if any of the bullets are not visible, if they are not then remove that bullet from the bulletList
for (int i = 0; i < bulletList.Count; i++)
{
if (!bulletList[i].isVisible)
{
bulletList.RemoveAt(i);
i--;
}
}
}
}
}
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 Space_Shooter
{
public class Bullet
{
public Rectangle boundingBox;
public Texture2D texture;
public Vector2 position , origin;
public float speed;
public bool isVisible;
public Bullet(Texture2D newTexture)
{
speed = 25;
texture = newTexture;
isVisible = false;
}
public void Draw(SpriteBatch spritebatch)
{
spritebatch.Draw(texture, position, Color.White);
}
}
}
You initialize the list in the constructor:
public Boss(Texture2D newTexture, Vector2 newPosition, Texture2D newBulletTexture)
But, you don't call this constructor. You call Boss boss = new Boss();
Thus the constructor which initializes the list is not called.
You should initialize the list in all constructors:
public Boss()
{
bulletList = new List<Bullet>();
}
Better is too make the default constructor set all the default values, and if you need to set other values in another constructor, is to call the default constructor from the "second" constructor using : this():
public Boss()
{
bulletList = new List<Bullet>();
bulletSpeed = 25;
bulletDamage = 25;
shipDamage = p.health / 2;
health = 2000;
bulletDelayTime = 30;
bulletDelayTimeReset = 30;
MaxBullets = 30;
isVisible = true;
}
public Boss(Texture2D newTexture, Vector2 newPosition, Texture2D newBulletTexture)
: this() //Call default constructor
{
texture = newTexture;
position = newPosition;
bulletTexture = newBulletTexture;
}
The problem that I am having is wrapping my brain around how I could use a single png called Test Map.png:
This has a black border around the screen and smaller stepping blocks for the player to test the collision. I have the gravity working by using a player class and the main class Game1.cs to draw and update the game. I use this ball:
This is my sprite that I move around the screen.
Here is the player.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Gravity_Test_V2
{
class Player
{
public Texture2D Texture;
public Vector2 Velocity;
public Vector2 Position;
public float ground;
private float Speed;
private Rectangle screenBound;
public bool isJumping; //are we jumping or not
public bool goingUp; //if going up or not
public float initialVelocity; //initial velocity
private float jumpU; //How high the player can jump
private float g; //gravity
public float t; //time
private KeyboardState prevKB;
public Player(Texture2D Texture, Vector2 Position, float Speed, Rectangle screenBound)
{
this.Texture = Texture;
this.Position = Position;
ground = Position.Y;
this.Speed = Speed;
this.screenBound = screenBound;
Velocity = Vector2.Zero;
isJumping = goingUp = true;
jumpU = 2.5f;
g = -9.8f;
t = 0;
}
public void Update(GameTime gameTime)
{
Position.X += (Velocity.X * Speed);
//Set the Y position to be subtracted so that the upward movement would be done by decreasing the Y value
Position.Y -= (Velocity.Y * Speed);
goingUp = (Velocity.Y > 0);
// TODO: Add your update logic here
if (isJumping == true)
{
//motion equation using velocity: v = u + at
Velocity.Y = (float)(initialVelocity + (g * t));
//Increase the timer
t += (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (isJumping == true && Position.Y > screenBound.Height - Texture.Height)
{
Position.Y = ground = screenBound.Height - Texture.Height;
Velocity.Y = 0;
isJumping = false;
t = 0;
}
if (Position.X < 0)
{
//if Texture touches left side of the screen, set the position to zero and the velocity to zero.
Position.X = 0;
Velocity.X = 0;
}
else if (Position.X + Texture.Width > screenBound.Width)
{
//if Texture touches left side of the screen, set the position to zero and the velocity to zero.
Position.X = screenBound.Width - Texture.Width;
Velocity.X = 0;
}
if (Position.Y < 0)
{
//if the Texture touches the top of the screen, reset the timer and set the initial velocity to zero.
Position.Y = 0;
t = 0;
initialVelocity = 0;
}
}
public void Input(KeyboardState keyState)
{
if (keyState.IsKeyDown(Keys.Space) && (isJumping == false || Position.Y == ground))
{
isJumping = true;
initialVelocity = jumpU;
}
if (keyState.IsKeyDown(Keys.Left) && !keyState.IsKeyDown(Keys.Right))
{
if (Velocity.X > -1.0f)
{
Velocity.X -= (1.0f / 10);
}
else
{
Velocity.X = -1.0f;
}
}
else if (!keyState.IsKeyDown(Keys.Left) && keyState.IsKeyDown(Keys.Right))
{
if (Velocity.X < 1.0f)
{
Velocity.X += (1.0f / 10);
}
else
{
Velocity.X = 1.0f;
}
}
else
{
if (Velocity.X > 0.05 || Velocity.X < -0.05)
Velocity.X *= 0.70f;
else
Velocity.X = 0;
}
prevKB = keyState;
}
public void Fall()
{
t = 0;
initialVelocity = 0;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Texture, new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height), Color.White);
}
}
}
Is there some simple way to make it so the player can collide with the Test Map.png while its inside the Test Map's texture?
EDIT: 1/21/2014 9 AM 'ish'
Level One:
EDIT: 1/21/2014 10:27
I have used a pixle based system to test to see if the player colides with an object but I try to sepreate the object from the play into classes and it will stop working. I mixed both my movment and collision projects together to try and make it work. I took player.cs (witch I have not changed) and added the pixel based collision into the Game1.cs I need to know how to make the player, witch is being controlled by the player.cs class, be seen by the Game1.cs class and used while being called upon by the player.cs class.
Note* I have also changed it so that the game would be using the falling triangles supplied by the pixel based system. I will add the test image when I am able to make this work.
At the moment The player can move and jump but is not reconsidered as colliding.
EDIT: 1/21/2014 10:34
I use 2 projects:
Collision:
http://xbox.create.msdn.com/en-US/education/catalog/tutorial/collision_2d_perpixel
Movment System:
http://gamepopper.co.uk/academic-projects/2012-2/jumping-platformer-example/
I have mixed them up and used pices of them to try and make my own platform.
Game1.cs:
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 Collision_Test
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
KeyboardState prevKB;
Player player;
SpriteFont font;
Texture2D personTexture;
Texture2D blockTexture;
// The color data for the images; used for per pixel collision
Color[] personTextureData;
Color[] blockTextureData;
Vector2 personPosition;
const int PersonMoveSpeed = 5;
public static int screenWidth = 800;
public static int screenHeight = 500;
// Blocks
List<Vector2> blockPositions = new List<Vector2>();
float BlockSpawnProbability = 0.01f;
const int BlockFallSpeed = 1;
Random random = new Random();
// For when a collision is detected
bool personHit = false;
// The sub-rectangle of the drawable area which should be visible on all TVs
Rectangle safeBounds;
// Percentage of the screen on every side is the safe area
const float SafeAreaPortion = 0.05f;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
this.graphics.PreferredBackBufferWidth = screenWidth;
this.graphics.PreferredBackBufferHeight = screenHeight;
this.graphics.ApplyChanges();
}
protected override void Initialize()
{
base.Initialize();
// Calculate safe bounds based on current resolution
Viewport viewport = graphics.GraphicsDevice.Viewport;
safeBounds = new Rectangle(
(int)(viewport.Width * SafeAreaPortion),
(int)(viewport.Height * SafeAreaPortion),
(int)(viewport.Width * (1 - 2 * SafeAreaPortion)),
(int)(viewport.Height * (1 - 2 * SafeAreaPortion)));
// Start the player in the center along the bottom of the screen
personPosition.X = (safeBounds.Width - personTexture.Width) / 2;
personPosition.Y = safeBounds.Height - personTexture.Height;
}
/// <summary>
/// Load your graphics content.
/// </summary>
protected override void LoadContent()
{
blockTexture = Content.Load<Texture2D>("Block");
personTexture = Content.Load<Texture2D>("Person");
font = Content.Load<SpriteFont>("Font");
player = new Player(personTexture, Vector2.Zero, 6.0f, new Rectangle(0, 0,
this.graphics.PreferredBackBufferWidth,
this.graphics.PreferredBackBufferHeight));
// Extract collision data
blockTextureData =
new Color[blockTexture.Width * blockTexture.Height];
blockTexture.GetData(blockTextureData);
personTextureData =
new Color[personTexture.Width * personTexture.Height];
personTexture.GetData(personTextureData);
// Create a sprite batch to draw those textures
spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
}
void HandleInput(KeyboardState keyState)
{
player.Input(keyState);
if (prevKB.IsKeyUp(Keys.F) && keyState.IsKeyDown(Keys.F))
{
this.graphics.ToggleFullScreen();
this.graphics.ApplyChanges();
}
}
protected override void Update(GameTime gameTime)
{
// Get input
KeyboardState keyboard = Keyboard.GetState();
GamePadState gamePad = GamePad.GetState(PlayerIndex.One);
HandleInput(Keyboard.GetState());
player.Update(gameTime);
prevKB = Keyboard.GetState();
// Allows the game to exit
if (gamePad.Buttons.Back == ButtonState.Pressed ||
keyboard.IsKeyDown(Keys.Escape))
{
this.Exit();
}
// Spawn new falling blocks
if (random.NextDouble() < BlockSpawnProbability)
{
float x = (float)random.NextDouble() *
(Window.ClientBounds.Width - blockTexture.Width);
blockPositions.Add(new Vector2(x, -blockTexture.Height));
}
// Get the bounding rectangle of the person
Rectangle personRectangle =
new Rectangle((int)personPosition.X, (int)personPosition.Y,
personTexture.Width, personTexture.Height);
// Update each block
personHit = false;
for (int i = 0; i < blockPositions.Count; i++)
{
// Animate this block falling
blockPositions[i] =
new Vector2(blockPositions[i].X,
blockPositions[i].Y + BlockFallSpeed);
// Get the bounding rectangle of this block
Rectangle blockRectangle =
new Rectangle((int)blockPositions[i].X, (int)blockPositions[i].Y,
blockTexture.Width, blockTexture.Height);
// Check collision with person
if (IntersectPixels(personRectangle, personTextureData,
blockRectangle, blockTextureData))
{
personHit = true;
}
// Remove this block if it have fallen off the screen
if (blockPositions[i].Y > Window.ClientBounds.Height)
{
blockPositions.RemoveAt(i);
// When removing a block, the next block will have the same index
// as the current block. Decrement i to prevent skipping a block.
i--;
}
}
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 device = graphics.GraphicsDevice;
// Change the background to red when the person was hit by a block
if (personHit)
{
device.Clear(Color.Red);
}
else
{
device.Clear(Color.CornflowerBlue);
}
spriteBatch.Begin();
player.Draw(spriteBatch);
// Draw blocks
foreach (Vector2 blockPosition in blockPositions)
spriteBatch.Draw(blockTexture, blockPosition, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
/// <summary>
/// Determines if there is overlap of the non-transparent pixels
/// between two sprites.
/// </summary>
/// <param name="rectangleA">Bounding rectangle of the first sprite</param>
/// <param name="dataA">Pixel data of the first sprite</param>
/// <param name="rectangleB">Bouding rectangle of the second sprite</param>
/// <param name="dataB">Pixel data of the second sprite</param>
/// <returns>True if non-transparent pixels overlap; false otherwise</returns>
static bool IntersectPixels(Rectangle rectangleA, Color[] dataA,
Rectangle rectangleB, Color[] dataB)
{
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) +
(y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return true;
}
}
}
// No intersection found
return false;
}
}
}
Provided the background of the texture is transparent, you could use Per-Pixel Collision detection.
Essentially it checks the pixels rather than a rectangular box to determine if a collision has occurred. Given your "player" is a ball, it's probably a good idea to use this anyway.
Considering that your map is only black & White, you could process it before starting the game and obtain coords of every Rectangle of black areas, and then use it to use simple collision detection by just checking intersection between the ball bounding box and rectangles.
For example, in pseudocode:
You have a list:
List<Rectangle> rects = new List<Rectangle>();
void LoadMap()
{
Texture2D map = Content.Load<Texture2D>(#"TexturePath");
//Get a 1D array with image's pixels
Color[] map_pixels = new Color[map.Width * map.Height];
map.GetData(map_pixels);
//Convert it in a 2D array
Color[,] map_pixels_2D = new Color[map.Width, map.Height];
for (int x = 0; x < map.Width; x++)
for (int y = 0; y < map.Height; y++)
map_pixels_2D[x, y] = map_pixels[x + y * map.Width];
//**NOTE THAT**: From here it is just an example, probably not working good,
//I wrote it just to share the idea
//Here goes the code to trace rectangles in the map
Rectangle r = Rectangle.Empty;
bool NWvertex_done = false, NEvertex_done = false, SWvertex_done = false;
for (int x = 0; x < map.Width; x++)
{
if (!SWvertex_done)
{
if (map_pixels_2D[x, y+1] == Color.White); //last bottom vertex
{
r.Height = r.Y + y;
SWvertex_done = true;
rects.Add(r);
NWvertex_done = false;
NEvertex_done = false;
r = Rectangle.Empty;
}
}
for (int y = 0; y < map.Height; y++)
{
if (map_pixels_2D[x, y] != Color.White
{
if (!NWvertex_done)
{
SWvertex_done = false;
r.X = x;
r.Y = y;
NWvertex_done = true;
}
else if(!NEvertex_done)
{
if (map_pixels_2D[x, y+1] == Color.White); //last right vertex
{
r.Width = r.X + x;
NEvertex_done = true;
}
}
}
}
}
}
public override void Update(GameTime gametime)
{
//maybe other things
//
foreach (Rectangle rect in rects)
{
//Better with Distance of ball-center and rect
if (ballRect.Intersect(rect))
{
//there is a collision!
//Do something
}
break;
}
//maybe other things
//
}
Im using Xna and C#.
Im trying to have specific objects in my list doing different things.
The way ive written it out at the moment it selects all the textures in my list and all of them do the same thing, if i try and select a certain texture all of them still do the same thing:
if (planet.Load("planet0")) { if (planet.Bounds.Contains((int)tl.Position.X, (int)tl.Position.Y)) { changeScreenDelegate(ScreenState.Menu); } }
Im basically trying to make each selection go to a different screen.
Heres the rest of my class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Input.Touch;
using Microsoft.Xna.Framework.Media;
namespace PlanetDrill2
{
class StarSystemUrsa : Screen
{
Texture2D starSystemTexture;
List<Planet> planets;
Texture2D star;
Vector2 position;
Texture2D previousButton;
public StarSystemUrsa(Game game, SpriteBatch spriteBatch, ChangeScreen changeScreen)
: base(game, batch, changeScreen)
{
position = new Vector2((480 - 295) / 2, (800 - 295) / 2);
planets = new List<Planet>();
Planet planet = new Planet(content, spriteBatch);
planet.Load("planet0");
planet.velocity = 0.04f;
planet.radius = 80;
planet.angle = MathHelper.ToRadians(90);
planets.Add(planet);
planet = new Planet(content, spriteBatch);
planet.Load("planet4");
planet.velocity = 0.02f;
planet.radius = 135;
planet.angle = MathHelper.ToRadians(120);
planets.Add(planet);
planet = new Planet(content, spriteBatch);
planet.Load("planet2");
planet.velocity = 0.009f;
planet.radius = 180;
planet.angle = MathHelper.ToRadians(160);
planets.Add(planet);
}
protected override void SetupInputs()
{
base.SetupInputs();
}
public override void Activate()
{
base.Activate();
}
protected override void LoadScreenContent(ContentManager content)
{
starSystemTexture = content.Load<Texture2D>("levelSelectMenu");
star = content.Load<Texture2D>("ursaeMajorisStar");
previousButton = content.Load<Texture2D>("previousButton2");
base.LoadScreenContent(content);
}
protected override void UpdateScreen(GameTime gameTime, DisplayOrientation screenOrientation)
{
TouchCollection touchCollection = TouchPanel.GetState();
foreach(TouchLocation tl in touchCollection)
{
if(tl.State == TouchLocationState.Pressed) // Moved? Is that right?
{
foreach(Planet planet in planets)
{
// Alternately: if(GetPlanetRectangle(planet).Contains(...))
if(planet.Bounds.Contains((int)tl.Position.X, (int)tl.Position.Y))
{
changeScreenDelegate(ScreenState.Menu);
}
}
}
TouchPanel.EnabledGestures = GestureType.DoubleTap | GestureType.VerticalDrag;
while (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
switch (gesture.GestureType)
{
case GestureType.DoubleTap:
changeScreenDelegate(ScreenState.launchScreen);
break;
case GestureType.VerticalDrag:
break;
default:
break;
}
}
}
foreach (Planet planet in planets)
{
planet.angle += planet.velocity;
float orbitx = (float)(Math.Cos(planet.angle) * planet.radius);
float orbity = (float)(Math.Sin(planet.angle) * planet.radius);
float x = (game.GraphicsDevice.Viewport.Width - planet.image.Width) / 2 + orbitx;
float y = (game.GraphicsDevice.Viewport.Height - planet.image.Height) / 2 + orbity;
planet.position = new Vector2(x, y);
}
base.UpdateScreen(gameTime, screenOrientation);
}
protected override void DrawScreen(SpriteBatch batch, DisplayOrientation screenOrientation)
{
batch.Draw(starSystemTexture, Vector2.Zero, Color.White);
foreach (Planet planet in planets)
{
planet.Draw();
}
batch.Draw(star,position, Color.White);
batch.Draw(previousButton, new Vector2(240, 750), Color.White);
base.DrawScreen(batch, screenOrientation);
}
protected override void SaveScreenState()
{
base.SaveScreenState();
}
}
}
Give your planet class another property called ID, then give each planet a different ID when initialising them. Then in your foreach planet in planets loop, you can say
if(planet.ID == 0)
{ if (planet.Bounds.Contains((int)tl.Position.X, (int)tl.Position.Y)) { changeScreenDelegate(ScreenState.Menu); } }
Do this for each possible ID number, and change the screenstate to whatever screen state you want it to switch to.
Plus you could enumerate the ID numbers to make it clear as to which planet is being referenced.
Attach a Menuscreen as a property of the Planet objects. Give those objects a method to tell the screenmanager to activate their screen. Call that method on the touched planet inside your (if Planet.Bounds.Conains) logic block.