My ball and my rectangle wont collide properly (Monogame) - c#

I am currently coding an arkanoid type game for my school project and just started out on monogame. I encountered a collision problem on the big red rectangle and the ball. I just cant figure out what is wrong with my code I appreciate all of your help in advance.
Collision Video: https://youtu.be/HOuUS8bUKn4
Game1.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
namespace TSA3
{
public class Game1 : Game
{
private GraphicsDeviceManager graphics;
private SpriteBatch spriteBatch;
// Platform
Platform platform;
Texture2D platformTexture;
Rectangle platformRectangle;
Color platformColor;
// Ball
Ball ball;
Texture2D ballTexture;
Rectangle ballRectangle;
Color ballColor;
bool ballDirectionX = true, ballDirectionY = true;
// Enemy
Enemy enemy;
Texture2D enemyTexture;
Rectangle enemyRectangle;
Color enemyColor;
Random random = new Random();
public const int ScreenW = 1200, ScreenH = 720;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
graphics.PreferredBackBufferWidth = ScreenW;
graphics.PreferredBackBufferHeight = ScreenH;
graphics.ApplyChanges();
Window.AllowUserResizing = false;
Window.AllowAltF4 = true;
Window.Title = "Arkanoid";
// Platform
platformTexture = Content.Load<Texture2D>("platform");
platformRectangle = new Rectangle(0, Window.ClientBounds.Height - 50, 100, 30);
platformColor = Color.White;
// Ball
ballTexture = Content.Load<Texture2D>("ball");
ballRectangle = new Rectangle(0, 0, 20, 20);
ballColor = Color.DarkBlue;
// Enemy
enemyTexture = Content.Load<Texture2D>("enemyPiece");
enemyRectangle = new Rectangle(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2, 200, 200);
enemyColor = Color.White;
base.Initialize();
}
protected override void LoadContent()
{
// Player
platform = new Platform(platformTexture, platformRectangle, platformColor, Window.ClientBounds.Width - 100);
// Ball
ball = new Ball(ballTexture, ballRectangle, ballColor, Window.ClientBounds.Width - 20, Window.ClientBounds.Height - 20, ballDirectionX, ballDirectionY);
// Enemy
enemy = new Enemy(enemyTexture, enemyRectangle, enemyColor);
spriteBatch = new SpriteBatch(GraphicsDevice);
}
float spawn = 0;
protected override void Update(GameTime gameTime)
{
spawn += (float)gameTime.ElapsedGameTime.TotalSeconds;
ball.ballBounce(platform.PlatformRectangle);
Keys[] k = Keyboard.GetState().GetPressedKeys();
foreach (Keys key in k)
{
platform.platformMovement(key);
break;
}
if (Keyboard.GetState().IsKeyDown(Keys.Space) && !ball.StartGame)
ball.StartGame = true;
ball.ballCollision(platform.PlatformRectangle);
ball.enemyCollision(enemy.enemyRectangle);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(ball.BallTexture, ball.BallRectangle, ball.BallColor);
spriteBatch.Draw(platform.PlatformTexture, platform.PlatformRectangle, platform.PlatformColor);
spriteBatch.Draw(enemy.enemyTexture, enemy.enemyRectangle, enemy.enemyColor);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Ball.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Text;
namespace TSA3
{
public class Ball
{
Texture2D ballTexture;
Rectangle ballRectangle;
Color ballColor;
int boundaryX, boundaryY;
bool ballDirectionX, ballDirectionY;
bool startGame;
public const int BALL_SPEED = 7;
public Ball(Texture2D ballTexture, Rectangle ballRectangle, Color ballColor, int boundaryX, int boundaryY, bool ballDirectionX, bool ballDirectionY)
{
this.ballTexture = ballTexture;
this.ballRectangle = ballRectangle;
this.ballColor = ballColor;
this.boundaryX = boundaryX;
this.boundaryY = boundaryY;
this.ballDirectionX = ballDirectionX;
this.ballDirectionY = ballDirectionY;
startGame = false;
}
public Texture2D BallTexture { get => ballTexture; }
public Rectangle BallRectangle { get => ballRectangle; }
public Color BallColor { get => ballColor; }
public bool StartGame { get => startGame; set => startGame = value; }
public void ballBounce(Rectangle platformRectangle)
{
if (startGame)
{
if (ballRectangle.X <= 0)
ballDirectionX = true;
else if (ballRectangle.X >= boundaryX)
ballDirectionX = false;
if (ballRectangle.Y <= 0)
{
ballDirectionY = true;
}
else if (ballRectangle.Y >= boundaryY)
{
startGame = false;
}
if (ballDirectionX)
ballRectangle.X += BALL_SPEED;
else
ballRectangle.X -= BALL_SPEED;
if (ballDirectionY)
ballRectangle.Y += BALL_SPEED;
else
ballRectangle.Y -= BALL_SPEED;
}
else
{
ballRectangle.Location = new Point(platformRectangle.X + (platformRectangle.Width / 2) - 10, platformRectangle.Y - (ballRectangle.Height - 5));
}
}
public void ballCollision(Rectangle platform)
{
if (ballRectangle.Intersects(platform))
ballDirectionY = false;
}
public void enemyCollision(Rectangle enemyRectangle)
{
if (ballRectangle.Intersects(enemyRectangle))
ballDirectionY = false;
}
}
}
Enemy.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Text;
namespace TSA3
{
public class Enemy
{
public Texture2D enemyTexture;
public Rectangle enemyRectangle;
public Color enemyColor;
public bool isVisible = true;
Random random = new Random();
public Enemy(Texture2D enemyTexture, Rectangle enemyRectangle, Color enemyColor)
{
this.enemyTexture = enemyTexture;
this.enemyRectangle = enemyRectangle;
this.enemyColor = enemyColor;
}
public Texture2D EnemyTexture { get => enemyTexture; }
public Rectangle EnemyRectangle { get => enemyRectangle; }
public Color EnemyColor { get => enemyColor; }
}
}
Platform.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Text;
namespace TSA3
{
public class Platform
{
Texture2D platformTexture;
Rectangle platformRectangle;
Color platformColor;
int boundaryX;
public const int PLATFORM_SPEED = 10;
public Platform(Texture2D platformTexture, Rectangle platformRectangle, Color platformColor, int boundaryX)
{
this.platformTexture = platformTexture;
this.platformRectangle = platformRectangle;
this.platformColor = platformColor;
this.boundaryX = boundaryX;
}
public Texture2D PlatformTexture { get => platformTexture; }
public Rectangle PlatformRectangle { get => platformRectangle; }
public Color PlatformColor { get => platformColor; }
public void platformMovement(Keys controls)
{
if (controls == Keys.A && platformRectangle.X > 0)
platformRectangle.X -= PLATFORM_SPEED;
if (controls == Keys.D && platformRectangle.X < boundaryX)
platformRectangle.X += PLATFORM_SPEED;
}
}
}
Thank you in advance to anyone who will help!

This method is missing the necessary code to function properly to approach the block from any side:
public void enemyCollision(Rectangle enemyRectangle)
{
if (ballRectangle.Intersects(enemyRectangle))
ballDirectionY = false;
}
Currently it only works the same as your platform does: set the Y direction upwards on collision. This works fine for the platform, as it's thin and close to the edge of the screen, so it doesn't need other collision checks.
Try improving this method similair with what you've done with the ball collisions on the edges of the screen.
What would be important here, is knowing the positions of the corners of the red rectangle, so you can calculate at which position the ball is hitting the rectangle.
As far I know, you cannot have the exact borders, but you can measure the same with calculating the positions of the corners. you could for example take the EnemyRectangle and get their x/y position, that would be it's top-left, than you can add the rectangle's width, and you'll have the top-right (same also works with the height for the bottom corners). If you calculate the balls position along with the rectangle corners, you'll know at which side the ball is colliding with the screen.
An example of a collision on top:
public void enemyCollision(Rectangle enemyRectangle)
{
if (ballRectangle.Intersects(enemyRectangle))
{
if (ballRectangle.x > enemyRectangle.x &&
ballRectangle.x < enemyRectangle.x + enemyRectangle.Width &&
ballRectangle.y > enemyRectangle.y)
ballDirectionY = false;
}
}

Related

How to move my sprite in MonoGame using C#

First off, i'm fairly new to programming, about 2 months in, i dabbled a bit in Console Application, WinForms, and still using the ugly console to get better at algorithms in general. But now, I wanna start digging into game programming, because that's the reason i wanted to learn programming. I stumbled upon MonoGame, and while it's harder than say Unity, I got an immense sense of achievement after creating something by just using code. I already made a Space Invaders and Pong but nothing related to sprite animation, using spritesheets and moving a player. So 2 days ago, I started a platformer, divided my spritesheet, got some animation down, and now that it's time to move my player, I'm completely lost. I tried reading some tutorials on vectors, but it doesn't help in my case. Maybe you can shed some light on the matter.
So, without further ado, here's the code:
Game.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MafiaJohnny
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
private JohnnyPlayer johnnyPlayer;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Texture2D texture = Content.Load<Texture2D>("JohnnyDone");
johnnyPlayer = new JohnnyPlayer(texture, 2, 4);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
johnnyPlayer.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.White);
johnnyPlayer.Draw(spriteBatch, new Vector2(200, 200));
base.Draw(gameTime);
}
}
}
JohnnyPlayer.cs
using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
namespace MafiaJohnny
{
class JohnnyPlayer
{
public Texture2D Texture { get; set; }
public int Rows { get; set; }
public int Columns { get; set; }
private int currentFrame;
private int totalFrames;
//Slow down frame animation
private int timeSinceLastFrame = 0;
private int millisecondsPerFrame = 400;
public JohnnyPlayer(Texture2D texture, int rows, int columns)
{
Texture = texture;
Rows = rows;
Columns = columns;
currentFrame = 0;
totalFrames = Rows * Columns;
}
public void Update (GameTime gameTime)
{
timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
if (timeSinceLastFrame > millisecondsPerFrame)
{
timeSinceLastFrame -= millisecondsPerFrame;
KeyboardState keystate = Keyboard.GetState();
//Idle animation
if (keystate.GetPressedKeys().Length == 0)
currentFrame++;
timeSinceLastFrame = 0;
if (currentFrame == 2)
currentFrame = 0;
//Walking Animation
if (keystate.IsKeyDown(Keys.Left))
{
}
}
}
public void Draw (SpriteBatch spriteBatch, Vector2 location)
{
int width = Texture.Width/Columns;
int height = Texture.Height / Rows;
int row = (int) ((float) currentFrame/Columns);
int column = currentFrame % Columns;
Rectangle sourceRectangle = new Rectangle(width * column, height * row, width, height);
Rectangle destinationRectangle = new Rectangle((int)location.X, (int)location.Y, width, height);
spriteBatch.Begin();
spriteBatch.Draw(Texture, destinationRectangle, sourceRectangle, Color.White);
spriteBatch.End();
}
}
}
So here's my code, find me an answer minions! Thank you is what I mean :)
You just need to change "location" so the sprite moves left/right/up/down. Also I recommend moving this code from JohnnyPlayer to another "controller" class.
Here:
http://www.gamefromscratch.com/post/2015/06/15/MonoGame-Tutorial-Creating-an-Application.aspx
They make a sprite and move it from left to right. In your case the texture on sprite changes in time (animation) but the movement is still the same.

all menu item's become selectable

I am trying to create a simple menu, the string that is selected changes colur as it is instructed to do, I just can't seem to space out each item in the string list on the Y axis, currently they are all positioned in the middle but at the top of the screen overlapping each other. I know this is probably a very simple fix but I am a novice at XNA. Any help would be very appreciated. Thanks in advance.
MenuManagement Class
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Game2
{
class MenuManagement
{
KeyboardState keyboard;
KeyboardState prevKey;
MouseState mouse;
Vector2 position;
List<String> buttonList = new List<string>();
SpriteFont spriteFont;
int selected = 0;
public MenuManagement ()
{
buttonList.Add("Play");
buttonList.Add("Options");
buttonList.Add("instructions");
buttonList.Add("Exit");
}
private void MeasureMenu()
{
height = 0;
width = 0;
foreach (string item in buttonList)
{
Vector2 size = spriteFont.MeasureString(item);
height += spriteFont.LineSpacing + 5;
}
}
public void LoadContent (ContentManager Content )
{
spriteFont = Content.Load<SpriteFont>("spriteFont");
}
public void Update (GameTime theGameTime)
{
keyboard = Keyboard.GetState();
if (checkKeyBoard(Keys.Up))
{
if (selected > 0)
{
selected--;
}
}
if (checkKeyBoard(Keys.Down))
{
if (selected < buttonList.Count - 1)
{
selected++;
}
}
prevKey = keyboard;
}
public bool checkKeyBoard (Keys key)
{
return (keyboard.IsKeyDown(key) && prevKey.IsKeyDown(key));
}
public void Draw (SpriteBatch theSpriteBatch)
{
theSpriteBatch.Begin();
Color color;
for (int i = 0; i < buttonList.Count; i++)
{
Vector2 location = position;
if (i == selected)
{
color = Color.Yellow;
}
else
{
color = Color.Blue;
}
location.Y += spriteFont.LineSpacing + 5;
}
theSpriteBatch.DrawString(spriteFont, buttonList[0], new Vector2 (300, 100), color);
theSpriteBatch.DrawString(spriteFont, buttonList[1], new Vector2(300, 150), color);
theSpriteBatch.DrawString(spriteFont, buttonList[2], new Vector2(300, 200), color);
theSpriteBatch.DrawString(spriteFont, buttonList[3], new Vector2(300, 250), color);
theSpriteBatch.End();
}
}
}
Game1
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game2
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch theSpriteBatch;
public static Rectangle screen;
public static string GameState = "Menu";
MenuManagement menuManagement;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
menuManagement = new MenuManagement();
screen = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
base.Initialize();
}
protected override void LoadContent()
{
theSpriteBatch = new SpriteBatch(GraphicsDevice);
menuManagement.LoadContent(Content);
// TODO: use this.Content to load your game content here
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
switch (GameState)
{
case "Menu":
menuManagement.Update(gameTime);
break;
}
base.Update(gameTime);
}
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
switch (GameState)
{
case "Menu":
menuManagement.Draw(theSpriteBatch);
break;
}
base.Draw(gameTime);
}
}
}
You can calculate the length of the strings and place the next item where you want. You should look to SpriteFont.MeasureString().
https://msdn.microsoft.com/en-us/library/bb464128(v=xnagamestudio.30).aspx
To be clear, the reason they are overlapping is because you are putting them all in the same position:
Vector2 location = position;
and then:
new Vector2 (300, location.Y)
is where you are drawing the entire batch. You need to change the position of each of the menu items. The simplest fix is to increment the Y value of the location for each item. That will move the next menu item toward the bottom. Increment X to move right.

XNA soundEffect is null in when loaded in main class and called in another class

I have loaded a sound effect file into the main class in xna, but when I try to run it in another class I am given this error
{"Object reference not set to an instance of an object."}
I am new to XNA classes so I do not really understand them. Any help as soon as possible is greatly appreciated.
this is part of the main class
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace BreakingOut
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Ball ball;
Paddle paddle;
Rectangle screenRectangle;
bool is1P = true;
int lives = 3;
Texture2D startButtonTexture;
Vector2 buttonVec;
Texture2D exitButtonTexture;
Vector2 button2Vec;
int bricksWide = 10;
int bricksHigh = 7;
Texture2D brickImage;
Brick[,] bricks;
//rec for menu
Texture2D menuTexture;
Rectangle menuRec = new Rectangle(0, 0, 960, 640);
//rec for pause
Texture2D pauseTexture;
Rectangle pauseRec = new Rectangle(0, 0, 960, 640);
//lose
Texture2D loseTexture;
Rectangle loseRec = new Rectangle(0, 0, 960, 640);
Texture2D winTexture;
Rectangle winRec = new Rectangle(0, 0, 960, 640);
//sound effects
public SoundEffect BallHitSE;
SoundEffect WallHitSE;
SoundEffect StartSE;
//BGM
Song menuMusic;
Song gameMusic;
bool isGameMusicPlaying = false;
bool isMenuMusicPlaying = false;
float pauseTimer;
float exitTimer;
float muteTimer;
float SEmuteTimer;
//public int brickCount = 70;
SpriteFont font;
Vector2 mousePos;
enum gameStates
{
MENU,
GAME1P,
LOSE,
PAUSE,
WIN,
}
gameStates currentState = gameStates.MENU;
gameStates prevState = gameStates.MENU;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
graphics.PreferredBackBufferWidth = 960;
graphics.PreferredBackBufferHeight = 640;
screenRectangle = new Rectangle(
0,
0,
graphics.PreferredBackBufferWidth,
graphics.PreferredBackBufferHeight);
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
Texture2D tempTexture = Content.Load<Texture2D>("paddle");
paddle = new Paddle(tempTexture, screenRectangle);
BallHitSE = Content.Load<SoundEffect>("BallHit");
WallHitSE = Content.Load<SoundEffect>("WallHit2");
StartSE = Content.Load<SoundEffect>("Start");
gameMusic = Content.Load<Song>("gameMusic");
menuMusic = Content.Load<Song>("menuMusic");
This is the Ball class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace BreakingOut
{
class Ball
{
Vector2 motion;
Vector2 position;
Rectangle bounds;
bool collided;
public int brickCount = 70;
const float ballStartSpeed = 6.4f;
public float ballSpeed;
Texture2D texture;
Rectangle screenBounds;
SoundEffect BallHitSE;
//BallHitSE = new SoundEffect
public Rectangle Bounds
{
get
{
bounds.X = (int)position.X;
bounds.Y = (int)position.Y;
return bounds;
}
}
public Ball(Texture2D texture, Rectangle screenBounds)
{
bounds = new Rectangle(0, 0, texture.Width, texture.Height);
this.texture = texture;
this.screenBounds = screenBounds;
//Different things we tried
//BallHitSE = Content.Load<SoundEffect>("BallHit");
//BallHitSE = new soundeffect(what goes in here?);
//BallHitSE = Content.Manager.Load("path")
}
public void Update()
{
collided = false;
position += motion * ballSpeed;
ballSpeed += 0.001f;
CheckWallCollision();
}
public void CheckWallCollision()
{
if (position.X < 0)
{
position.X = 0;
motion.X *= -1;
//if (BallHitSE != null)
//{
BallHitSE.Play();
//}
}
if (position.X + texture.Width > screenBounds.Width)
{
position.X = screenBounds.Width - texture.Width;
motion.X *= -1;
//if (BallHitSE != null)
//{
BallHitSE.Play();
//}
}
if (position.Y < 0)
{
position.Y = 0;
motion.Y *= -1;
//if (BallHitSE != null)
//{
BallHitSE.Play();
//}
}
}
public void SetInStartPosition(Rectangle paddleLocation)
{
Random rand = new Random();
motion = new Vector2(rand.Next(2, 6), -rand.Next(2, 6));
motion.Normalize();
ballSpeed = ballStartSpeed;
position.Y = paddleLocation.Y - texture.Height;
position.X = paddleLocation.X + (paddleLocation.Width - texture.Width) / 2;
}
public bool OffBottom()
{
if (position.Y > screenBounds.Height)
return true;
return false;
}
public void PaddleCollision(Rectangle paddleLocation)
{
Rectangle ballLocation = new Rectangle(
(int)position.X,
(int)position.Y,
texture.Width,
texture.Height);
if (paddleLocation.Intersects(ballLocation))
{
position.Y = paddleLocation.Y - texture.Height;
motion.Y *= -1;
}
}
public void Deflection(Brick brick)
{
if (!collided)
{
motion.Y *= -1;
collided = true;
brickCount -= 1;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
for (int i = 1; i < 10; i++)
{
var drawPosition = position - (i * motion * 3);
var colour = Color.Lerp(Color.White, Color.Transparent, i * (20 / 100f));
spriteBatch.Draw(texture, drawPosition, colour);
}
}
}
}
XNA classes are no different than a regular class, don't let them fool you!
It seems you just need to set the two pieces equal to eachother.
In the ball class:
public Ball(Texture2D texture, Rectangle screenBounds, SoundEffect ballHit/*NEW*/)
{
this.BallHitSE = ballHit;// NEW
bounds = new Rectangle(0, 0, texture.Width, texture.Height);
this.texture = texture;
this.screenBounds = screenBounds;
//Different things we tried
//BallHitSE = Content.Load<SoundEffect>("BallHit");
//BallHitSE = new soundeffect(what goes in here?);
//BallHitSE = Content.Manager.Load("path")
}
Then just add the sound effect to the constructor:
Ball ball = new Ball(texture, bounds, BallHitSE);
If you use those SoundEffect in your Ball class you shoud load them in the LoadContent of your Ball class, not in the main class.
That's why you receive that error when you try to run one of it, they are initialized in another class and are still null.
Of course if you have to load something in Ball class you need to pass the ContentManager, or make that Ball class inherits from GameComponent or DrawableGameComponent, in order to load your sound effects in this way:
BallHitSE = Game.Content.Load<SoundEffect>("BallHit");
WallHitSE = Game.Content.Load<SoundEffect>("WallHit2");
EDIT
Usually I manage audio in this way:
public class AudioComponent : GameComponent
{
public enum LevelEffect { BadCollision, GoodCollision, PopUp }
public enum GameMusic { GameWin, GameLose, GameStart }
private Song winSound, loseSound, startSound;
private SoundEffect badCollSound, goodCollSound, popUp;
public AudioComponent()
{
}
public override void Initialize()
{
base.Initialize();
}
public void loadAudio(
Song winSound,
Song loseSound,
Song startSound,
SoundEffect badCollSound,
SoundEffect goodCollSound,
SoundEffect popUp
)
{
this.winSound = winSound;
this.loseSound = loseSound;
this.startSound = startSound;
this.badCollSound = badCollSound;
this.goodCollSound = goodCollSound;
this.popUp = popUp;
}
public void PlayGameMusic(GameMusic effType)
{
switch (effType)
{
case GameMusic.GameWin:
PlayMusic(winSound);
break;
case GameMusic.GameLose:
PlayMusic(loseSound);
break;
case GameMusic.GameStart:
PlayMusicRepeat(startSound);
break;
}
}
public void PlayLevelEffect(LevelEffect effType)
{
switch (effType)
{
case GameMusic.BadCollision:
PlayEffect(badCollSound);
break;
case GameMusic.GoodCollision:
PlayEffect(goodCollSound);
break;
case GameMusic.PopUp:
PlayEffect(popUp);
break;
}
}
public void PlayEffect(SoundEffect sound)
{
sound.Play();
}
public bool CheckAlreadyPlayingMusic()
{
return MediaPlayer.State == MediaState.Playing;
}
public void PlayMusic(Song song)
{
MediaPlayer.Play(song);
MediaPlayer.IsRepeating = false;
}
public void PlayMusicRepeat(Song song)
{
MediaPlayer.Play(song);
MediaPlayer.IsRepeating = true;
}
public void StopMusic()
{
MediaPlayer.Stop();
}
public void PauseMusic()
{
MediaPlayer.Pause();
}
public void ResumeMusic()
{
MediaPlayer.Resume();
}
public void ChangeVolume(float volume)
{
MediaPlayer.Volume = volume;
}
}
user Kai Hartmann solved this question with an easy and simple fix
Make sure, Ball is instantiated before LoadContent().
Then swap this line
BallHitSE = Content.Load("BallHit"); with this
Ball.BallHitSE = Content.Load("BallHit"); and change the
variable in your Ball class to this
public static SoundEffect BallHitSE;
https://gamedev.stackexchange.com/a/66184/36332

xna model turning on its side, camera related

I have 3 classes: a game class, a camera class and a model class. The project builds and runs,
the model appears, when i press w and make it go forward the camera follows it, but when i restart the project and rotate the model to face any other ways it seems to do a nose dive, and not go stright, what im trying to achieve is a camera which follows the model,
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 test1
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
//Visual components
Ship ship = new Ship();
Camera _camera;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// this.graphics.ToggleFullScreen();
this._camera = new Camera(graphics.GraphicsDevice.Viewport);
this._camera.LookAt = new Vector3(0.0f, 0.0f, 0.0f);
this._camera.Position = new Vector3(0.0f, -5000.0f, 1000.0f);
base.Initialize();
}
protected override void LoadContent()
{
ship.Model = Content.Load<Model>("Models/p1_wedge");
ship.Transforms = _camera.SetupEffectDefaults(ship.Model);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
// Get some input.
UpdateInput();
base.Update(gameTime);
}
protected void UpdateInput()
{
// Get the game pad state.
GamePadState currentState = GamePad.GetState(PlayerIndex.One);
KeyboardState currentKeyState = Keyboard.GetState();
ship.Update(currentState);
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
//camera
this._camera.Update();
_camera.LookAt = ship.Position;
Matrix shipTransformMatrix = ship.RotationMatrix
* Matrix.CreateTranslation(ship.Position);
DrawModel(ship.Model, shipTransformMatrix, ship.Transforms);
base.Draw(gameTime);
}
public void DrawModel(Model model, Matrix modelTransform,
Matrix[] absoluteBoneTransforms)
{
//Draw the model, a model can have multiple meshes, so loop
foreach (ModelMesh mesh in model.Meshes)
{
//This is where the mesh orientation is set
foreach (BasicEffect effect in mesh.Effects)
{
effect.World =
absoluteBoneTransforms[mesh.ParentBone.Index] *
modelTransform;
effect.Projection = _camera.ProjectionMatrix;
effect.View = _camera.ViewMatrix;
}
//Draw the mesh, will use the effects set above.
mesh.Draw();
}
}
}
}
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 test1
{
public class Camera
{
private Vector3 _position;
private Vector3 _lookAt;
private Matrix _viewMatrix;
private Matrix _projectionMatrix;
private float _aspectRatio;
public Camera(Viewport viewport)
{
this._aspectRatio = ((float)viewport.Width) / ((float)viewport.Height);
this._projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(40.0f),
this._aspectRatio,
1.0f,
10000.0f);
}
public Matrix[] SetupEffectDefaults(Model myModel)
{
Matrix[] absoluteTransforms = new Matrix[myModel.Bones.Count];
myModel.CopyAbsoluteBoneTransformsTo(absoluteTransforms);
foreach (ModelMesh mesh in myModel.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.Projection = ProjectionMatrix;
effect.View = ViewMatrix;
}
}
return absoluteTransforms;
}
public Vector3 Position
{
get { return this._position; }
set { this._position = value; }
}
public Vector3 LookAt //= Vector3.Zero;
{
get { return this._lookAt; }
set { this._lookAt = value; }
}
public Matrix ViewMatrix
{
get { return this._viewMatrix; }
}
public Matrix ProjectionMatrix
{
get { return this._projectionMatrix; }
}
public void Update()
{
this._viewMatrix =
Matrix.CreateLookAt(this._position, this._lookAt, Vector3.Up);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace test1
{
class Ship
{
public Model Model;
public Matrix[] Transforms;
//Position of the model in world space
public Vector3 Position = Vector3.Zero;
//Velocity of the model, applied each frame to the model's position
public Vector3 Velocity = Vector3.Zero;
private const float VelocityScale = 5.0f;
public Matrix RotationMatrix =
Matrix.CreateRotationX(MathHelper.PiOver2);
private float rotation;
public float Rotation
{
get { return rotation; }
set
{
float newVal = value;
while (newVal >= MathHelper.TwoPi)
{
newVal -= MathHelper.TwoPi;
}
while (newVal < 0)
{
newVal += MathHelper.TwoPi;
}
if (rotation != value)
{
rotation = value;
RotationMatrix =
Matrix.CreateRotationX(MathHelper.PiOver2) *
Matrix.CreateRotationZ(rotation);
}
}
}
public void Update(GamePadState controllerState)
{
KeyboardState currentKeyState = Keyboard.GetState();
if (currentKeyState.IsKeyDown(Keys.A))
Rotation += 0.10f;
else
// Rotate the model using the left thumbstick, and scale it down.
Rotation -= controllerState.ThumbSticks.Left.X * 0.10f;
if (currentKeyState.IsKeyDown(Keys.D))
Rotation -= 0.10f;
if (currentKeyState.IsKeyDown(Keys.W))
Velocity += RotationMatrix.Forward * VelocityScale;
else
// Finally, add this vector to our velocity.
Velocity += RotationMatrix.Forward * VelocityScale *
controllerState.Triggers.Right;
// In case you get lost, press A to warp back to the center.
if (currentKeyState.IsKeyDown(Keys.Enter))
{
Position = Vector3.Zero;
Velocity = Vector3.Zero;
Rotation = 0.0f;
}
Position += Velocity;
Velocity *= 0.95f;
}
}
}
I'd do it this way:
I'm showing it in a plane to easy understanding, but it's not needed to do the calcs.
You only need a forward vector for the camera, a forward vector for the ship, a distance from the camera to the ship and an elevation vector for the camera.
this way when ship moves would do something similar to this:
Camera.Forward = Vector3.Lerp( Ship.Forward, Camera.Fordward, 0.05f);
Camera.Forward.Normalize();
Camera.Forward*=Camera.Distance;
Camera.Target = Ship.Target;
Camera.Source = Ship.Target - Camera.Forward;
Camera.Position = Camera.Source + Camera.Elevation;
I hope this will be useful.

XNA Respawning "enemies" randomly

I am trying to make a game and I want "enemies" or meteors to spawn from the right side and going to the left side. I am working on some code and it seems to be working pretty good but the respawning fails. They end up spawning one and one REALLY slow and then after a while they don't spawn at all. All help would be really appreciated.
Here's my code:
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 WindowsGame2
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
List<Enemies> enemies = new List<Enemies>();
Random random = new Random();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void UnloadContent()
{
}
float spawn = 0;
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
spawn += (float)gameTime.ElapsedGameTime.TotalSeconds;
foreach (Enemies enemy in enemies)
{
enemy.Update(graphics.GraphicsDevice);
}
LoadEnemies();
base.Update(gameTime);
}
public void LoadEnemies()
{
int randY = random.Next(100, 400);
if (spawn > 1)
{
spawn = 0;
if (enemies.Count() < 10)
enemies.Add(new Enemies(Content.Load<Texture2D>("meteor"), new Vector2(1110, randY)));
}
for (int i = 0; i < enemies.Count; i++)
{
if (!enemies[i].isVisible)
{
enemies.RemoveAt(i);
i--;
}
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
foreach (Enemies enemy in enemies)
{
enemy.Draw(spriteBatch);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
and here's my class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace WindowsGame2
{
class Enemies
{
public Texture2D texture;
public Vector2 position;
public Vector2 velocity;
public bool isVisible = true;
Random random = new Random();
int randX, randY;
public Enemies(Texture2D newTexture, Vector2 newPosition)
{
texture = newTexture;
position = newPosition;
randX = random.Next(-4, 4);
randY = random.Next(-4, -1);
velocity = new Vector2(randX, randY);
}
public void Update(GraphicsDevice graphics)
{
position += velocity;
if (position.Y <= 0 || position.Y >= graphics.Viewport.Height - texture.Height)
{
velocity.Y = -velocity.Y;
}
if (position.X < 0 - texture.Width)
{
isVisible = false;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
}
Your problem lies here. Some of your meteors are moving right and some are not moving at all.
randX = random.Next(-4, 4);
Try using
randX = random.Next(-4, -1);
Your enemies/meteors sometimes had a velocity on the X that was between 0 and 4, so they moved right.
I can see you changed the Y to this, maybe you got them mixed up?

Categories