Why my MonoGame simple app is lagging? - c#

I wrote my simple game for Android with MonoGame API.
I touch the app was running with quite good performance but for sure I make simple FPS counter and the resoults was 54-60 fps with does not satisfied me, so i move my fps counter to the MonoGame template to see with part of my code was causing laggs and i found that even almost clear app run with the same speed of 54-60 fps. The problem was not comming from GC because there was no garbage to collect. Is there any option to avoid these lags? Here is the app:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace perf_test
{
public class FRAPS
{
float fps_from;
int fps;
public int fps_toshow;
public float in_Secs;
public void add_frame()
{
fps_from += in_Secs;
if (fps_from > 1)
{
fps_toshow = fps;
fps = 0;
fps_from = 0;
}
fps++;
}
}
public class numbers
{
Texture2D[] texture;
int num1, num2;
Vector2 pos1, pos2, origin;
public int number;
public void load(ContentManager content)
{
texture = new Texture2D[10];
for (int i = 0; i < 10; i++)
{
texture[i] = content.Load<Texture2D>(("" + i));
}
num1 = 0;
num2 = 0;
number = 22;
pos1 = new Vector2(250, 50);
pos2 = new Vector2(270, 50);
origin = new Vector2(10, 10);
}
public void update()
{
num1 = 0;
num2 = 0;
int nuu = number;
if (nuu > 10)
{
for (int i = 0; i < 10; i++)
{
if (number >= (i * 10))
{
num1 = i;
}
else break;
}
}
nuu -= num1 * 10;
for (int i = 0; i < 10; i++)
{
if (nuu >= i)
{
num2 = i;
}
else break;
}
}
public void draw()
{
if (number > 9) Game1.spriteBatch.Draw(texture[num1], pos1, origin: origin);
Game1.spriteBatch.Draw(texture[num2], pos2, origin: origin);
}
}
public class Game1 : Game
{
GraphicsDeviceManager graphics;
public static SpriteBatch spriteBatch;
FRAPS fraps;
numbers Numb;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
fraps = new FRAPS();
Numb = new numbers();
graphics.IsFullScreen = true;
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 480;
graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Numb.load(Content);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
fraps.in_Secs = (float)gameTime.ElapsedGameTime.TotalSeconds;
fraps.add_frame();
Numb.number = fraps.fps_toshow;
Numb.update();
Numb.draw();
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Sorry for bad English, I am from Poland.

Set
IsFixedTimeStep = false;
in your Game1 constructor. XNA/Monogame automatically caps you at 60 FPS.

Related

My ball and my rectangle wont collide properly (Monogame)

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;
}
}

Monogame: Creating Draw Function In Class

I am wanting to make a tile class that contains it's own drawing function. Below is what I have so far. The error that is showing when I run the coder is. "System.InvalidOperationException: 'Begin cannot be called again until End has been successfully called." This error message shows up on the spirteBatch.Begin() inside the class.
namespace TileGame.v3
{
class Tile
{
public Texture2D texture { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int sourceX { get; set; }
public int sourceY { get; set; }
public int width { get; set; }
public int height { get; set; }
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Begin();
spriteBatch.Draw(texture, new Vector2(X, Y), new Rectangle(sourceX, sourceY, width, height), Color.White);
spriteBatch.End();
Draw(gameTime, spriteBatch);
}
}
}
namespace TileGame.v3
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D mark;
Texture2D peep1;
Texture2D ocean;
int x1 = 100;
int y1 = 100;
int x2 = 400;
int y2 = 400;
int tempx;
int tempy;
bool win = false;
Tile a = new Tile();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
mark = Content.Load<Texture2D>("mark");
peep1 = Content.Load<Texture2D>("peep1");
ocean = Content.Load<Texture2D>("ocean");
a.texture = ocean;
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (Keyboard.GetState().IsKeyDown(Keys.Enter))
{
tempx = x1;
x1 = x2;
x2 = tempx;
tempy = y1;
y1 = y2;
y2 = tempy;
win = true;
}
a.X = 100;
a.Y = 100;
a.sourceX = 300;
a.sourceY = 300;
a.width = 100;
a.height = 100;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
a.Draw(gameTime, spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
The texture is 1920x1080 and I have tested drawing and cutting it and it has worked fine.
First of all, your code is probably incomplete, but you are never calling the draw method anywhere.
Let say you are calling it, are you sure your texture is bigger than 300x300? And what does that texture contains for (x,y = 300,300 to x,y = 400,400)? Does it have any color data in those positions?
If you answer yes to all of this, we will need more code to be able to help you with that.
Side node: Since this is a tile, you probably are going to render many of them. You don't need to call .Begin() and .End() for all of them. Simply call Begin() before the first tile and End() after the last one and you're good to go. This will make rendering much faster.

XNA - adding items to a list and draw them

So I'm making a Space Invaders clone in XNA. I created the invaders array and added their movement logic. I want to make them shoot bullets. So I've been following a tutorial about it and used only the code I need. But still no bullets are drawn on the screen. Here's my invader class, I removed what is not related to the question from it:
class botInvaders
{
public botInvaders(Texture2D newBulletTex)
{
bulletsList = new List<blasterLasers>();
bulletTex = newBulletTex;
botInvadersHealth = 5;
currentDificultyLevel = 1;
bulletDelay = 40;
isVisible = true;
}
public static Texture2D botInvaderTex, bulletTex;
public static Rectangle botInvaderHitBox;
public static Vector2 botInvaderOrigin;
public int botInvaderCurrentFrame = 1, botInvaderFrameWidth = 52, botInvaderFrameHeight = 90, bulletDelay, botInvadersHealth, currentDificultyLevel, invaderRows = 3, invaderCollumns = 10; // invaderRows = 5 // For 50 invaders
public static Rectangle[,] botInvadersRect;
public bool isVisible;
public List<blasterLasers> bulletsList;
public void LoadContent(ContentManager Content)
{
botInvaderTex = Content.Load<Texture2D>(".\\gameGraphics\\gameSprites\\botInvaders\\normalInvaders\\invaderShip1");
bulletTex = Content.Load<Texture2D>(".\\gameGraphics\\gameSprites\\botInvaders\\normalInvaders\\botInvaderLaser");
botInvadersRect = new Rectangle[invaderRows, invaderCollumns];
}
public void Update(GameTime gameTime)
{
for (int r = 0; r < invaderRows; r++)
{
for (int c = 0; c < invaderCollumns; c++)
{
EnemyShoot();
UpdateBullets();
}
}
}
public void Draw(Texture2D invadersTex, Rectangle[,] invadersDestinationRect, Nullable<Rectangle> invadersSourceRect, Color invadersColor, float invadersRotation, Vector2 invadersOrigin, SpriteEffects invadersEffects, float invadersScale, SpriteBatch spriteBatch)
{
for (int r = 0; r < invaderRows; r++)
{
for (int c = 0; c < invaderCollumns; c++)
{
spriteBatch.Draw(botInvaderTex, botInvadersRect[r, c], botInvaderHitBox, Color.White);
foreach (blasterLasers bulletSpawn in bulletsList)
{
bulletSpawn.Draw(spriteBatch);
}
}
}
}
public void UpdateBullets()
{
foreach (blasterLasers bulletsSpawn in bulletsList)
{
bulletsSpawn.bulletPos.Y = bulletsSpawn.bulletPos.Y + bulletsSpawn.bulletSpeed;
if (bulletsSpawn.bulletPos.Y >= -632)
{
bulletsSpawn.isVisible = false;
}
}
for (int i = 0; i < bulletsList.Count(); i++)
{
if (!bulletsList[i].isVisible)
{
bulletsList.RemoveAt(i);
i--;
}
}
}
public void EnemyShoot()
{
if (bulletDelay >= 0)
{
bulletDelay--;
}
if (bulletDelay <= 0)
{
blasterLasers newBullet = new blasterLasers(bulletTex);
newBullet.bulletPos = new Vector2(botInvaderHitBox.X + botInvaderFrameWidth / 2 - newBullet.bulletTex.Width / 2, botInvaderHitBox.Y + 90);
newBullet.isVisible = true;
if (bulletsList.Count() < 20)
{
bulletsList.Add(newBullet);
}
}
if (bulletDelay == 0)
{
bulletDelay = 40;
}
}
}
I initialize the class in Game1:
// Create a var
botInvaders botInvader;
// Init it
botInvader = new botInvaders(botInvaders.bulletTex);
// Load Content
botInvader.LoadContent(Content);
// Update
botInvader.Update(gameTime);
// Draw Invaders
botInvader.Draw(botInvaders.botInvaderTex, botInvaders.botInvadersRect, botInvaders.botInvaderHitBox, Color.White, 0f, botInvaders.botInvaderOrigin, SpriteEffects.None, 1.0f, spriteBatch);
Could the problem be that I'm not actually drawing the bullets?
Or I'm not adding any bullets to the list?
If I debug I can see:
bulletsList Count = 0
_size 0
_items [0] null [1] null [2] null [3] null
EDIT:
blasterLasers class:
public class blasterLasers
{
public Texture2D bulletTex;
public Vector2 bulletOrigin, bulletPos;
public bool isVisible;
public float bulletSpeed;
public Rectangle boundingBox;
public blasterLasers(Texture2D newBulletTex)
{
bulletSpeed = 10f;
bulletTex = newBulletTex;
isVisible = false;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(bulletTex, bulletPos, Color.White);
}
}
It looks like you are removing the bullets from bulletslist when you call UpdateBullets, so when you go call Draw, it loops through bulletList, which is empty, hence nothing is drawn.

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 - No loading screen or menu

The problem is that it just shows a black screen and the loading mouse. It doesn't show the loading screen or the menu.
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteBatch mBatch;
Texture2D mTheQuantumBros2;
MenuComponent menuComponent;
public static Rectangle screen;
public static string GameState = "Menu";
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferMultiSampling = false;
graphics.IsFullScreen = true;
graphics.PreferredBackBufferWidth = 1366;
graphics.PreferredBackBufferHeight = 768;
graphics.ApplyChanges();
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
mBatch = new SpriteBatch(this.graphics.GraphicsDevice);
ContentManager aLoader = new ContentManager(this.Services);
aLoader.RootDirectory = "Content";
mTheQuantumBros2 = aLoader.Load<Texture2D>("TheQuantumBros2") as Texture2D;
menuComponent.LoadContent(Content);
}
protected override void UnloadContent()
{
}
/// <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)
this.Exit();
switch (GameState)
{
case "Menu":
menuComponent.Update(gameTime);
break;
}
base.Update(gameTime);
}
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
switch (GameState)
{
case "Menu":
menuComponent.Draw(spriteBatch);
break;
}
base.Draw(gameTime);
}
}
Other class:
class MenuComponent
{
KeyboardState keyboard;
KeyboardState prevKeyboard;
SpriteBatch mBatch;
Texture2D mTheQuantumBros2;
GameTime gameTime;
MouseState mouse;
MouseState prevMouse;
SpriteFont spriteFont;
List<string> buttonList = new List<string>();
int selected = 0;
public MenuComponent()
{
buttonList.Add("Campaign");
buttonList.Add("Multiplayer");
buttonList.Add("Zombies");
buttonList.Add("Quit Game");
}
public void LoadContent(ContentManager Content)
{
spriteFont = Content.Load<SpriteFont>("Font");
}
public void Update(GameTime gameTime)
{
keyboard = Keyboard.GetState();
mouse = Mouse.GetState();
if (CheckKeyboard(Keys.Up))
{
if (selected > 0) selected--;
}
if (CheckKeyboard(Keys.Down))
{
if (selected < buttonList.Count - 1) selected++;
}
prevMouse = mouse;
prevKeyboard = keyboard;
}
public bool CheckMouse()
{
return (mouse.LeftButton == ButtonState.Pressed && prevMouse.LeftButton == ButtonState.Released);
}
public bool CheckKeyboard(Keys key)
{
return (keyboard.IsKeyDown(key) && prevKeyboard.IsKeyDown(key));
}
public void Draw(SpriteBatch spriteBatch)
{
Color color;
int linePadding = 3;
spriteBatch.Begin();
mBatch.Begin();
mBatch.Draw(mTheQuantumBros2, new Rectangle(300, 150, mTheQuantumBros2.Width, mTheQuantumBros2.Height), Color.White);
if (gameTime.TotalGameTime.TotalSeconds <= 3)
{
mBatch.End();
for (int i = 0; i < buttonList.Count; i++)
{
color = (i == selected) ? Color.LawnGreen : Color.Gold;
spriteBatch.DrawString(spriteFont, buttonList[i], new Vector2((Game1.screen.Width / 2) - (spriteFont.MeasureString(buttonList[i]).X / 2), (Game1.screen.Height / 2) - (spriteFont.LineSpacing * (buttonList.Count) / 2) + ((spriteFont.LineSpacing + linePadding) * i)), color);
}
spriteBatch.End();
}
}
}
What is the purpose of this statement: (gameTime.TotalGameTime.TotalSeconds <= 3)?
Also, you are never updating the game time in the menu component. So, the aforementioned code would behave unexpectedly.
You are also calling spriteBatch.Begin() twice before end is called... So that should be giving you an error. Check those for issues.
EDIT: Since you are only calling spriteBatch.End() IF less than 3 seconds have passed, it will never be called again after that? I think.
As a potential fix... I would try only calling spriteBatch.Begin() and spriteBatch.End() inside of game1.cs. So:
//In your menu class
public void Draw(SpriteBatch spriteBatch)
{
Color color;
int linePadding = 3;
if (gameTime.TotalGameTime.TotalSeconds <= 3)
{
mBatch.Begin();
mBatch.Draw(mTheQuantumBros2, new Rectangle(300, 150, mTheQuantumBros2.Width, mTheQuantumBros2.Height), Color.White);
mBatch.End();
}
else
{
for (int i = 0; i < buttonList.Count; i++)
{
color = (i == selected) ? Color.LawnGreen : Color.Gold;
spriteBatch.DrawString(spriteFont, buttonList[i], new Vector2((Game1.screen.Width / 2) - (spriteFont.MeasureString(buttonList[i]).X / 2), (Game1.screen.Height / 2) - (spriteFont.LineSpacing * (buttonList.Count) / 2) + ((spriteFont.LineSpacing + linePadding) * i)), color);
}
}
}
And back in game1.cs, call spriteBatch.End() right before base.Draw() is called.
In general, it is best to only use one spriteBatch, I believe it is simply faster than beginning and ending two different batches.
EDIT 2:
Just uhm... copy and paste I guess. It works fine after the adjustments I made (you can read about them at the bottom).
You're refactored code:
game1.cs:
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
MenuComponent menuComponent;
public static Rectangle screen;
public static string GameState = "Menu";
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferMultiSampling = false;
//graphics.IsFullScreen = true;
graphics.PreferredBackBufferWidth = 1366;
graphics.PreferredBackBufferHeight = 768;
graphics.ApplyChanges();
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
menuComponent = new MenuComponent();
menuComponent.LoadContent(Content, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);
}
protected override void UnloadContent()
{
}
/// <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)
this.Exit();
switch (GameState)
{
case "Menu":
menuComponent.Update(gameTime);
break;
}
base.Update(gameTime);
}
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
switch (GameState)
{
case "Menu":
menuComponent.Draw(spriteBatch, gameTime);
break;
}
spriteBatch.End();
base.Draw(gameTime);
}
MenuComponent:
KeyboardState keyboard;
KeyboardState prevKeyboard;
MouseState mouse;
MouseState prevMouse;
GraphicsDevice graphicsDevice;
Texture2D mTheQuantumBros2;
SpriteFont spriteFont;
List<string> buttonList = new List<string>();
int selected = 0;
int screenWidth;
int screenHeight;
public MenuComponent()
{
buttonList.Add("Campaign");
buttonList.Add("Multiplayer");
buttonList.Add("Zombies");
buttonList.Add("Quit Game");
}
public void LoadContent(ContentManager Content, int _screenWidth, int _screenHeight)
{
spriteFont = Content.Load<SpriteFont>("Font");
mTheQuantumBros2 = Content.Load<Texture2D>("TheQuantumBros2");
screenHeight = _screenHeight;
screenWidth = _screenWidth;
}
public void Update(GameTime gameTime)
{
keyboard = Keyboard.GetState();
mouse = Mouse.GetState();
if (CheckKeyboard(Keys.Up))
{
if (selected > 0) selected--;
}
if (CheckKeyboard(Keys.Down))
{
if (selected < buttonList.Count - 1) selected++;
}
prevMouse = mouse;
prevKeyboard = keyboard;
}
public bool CheckMouse()
{
return (mouse.LeftButton == ButtonState.Pressed && prevMouse.LeftButton == ButtonState.Released);
}
public bool CheckKeyboard(Keys key)
{
return (keyboard.IsKeyDown(key) && prevKeyboard.IsKeyDown(key));
}
public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
{
Color color;
int linePadding = 3;
if (gameTime.TotalGameTime.TotalSeconds <= 3)
{
spriteBatch.Draw(mTheQuantumBros2, new Rectangle(300, 150, mTheQuantumBros2.Width, mTheQuantumBros2.Height), Color.White);
}
else
{
for (int i = 0; i < buttonList.Count; i++)
{
color = (i == selected) ? Color.LawnGreen : Color.Gold;
spriteBatch.DrawString(spriteFont, buttonList[i], new Vector2((screenWidth / 2) - (spriteFont.MeasureString(buttonList[i]).X / 2), (screenHeight / 2) - (spriteFont.LineSpacing * (buttonList.Count) / 2) + ((spriteFont.LineSpacing + linePadding) * i)), color);
}
}
}
There were a bunch of little issues. For example, you were setting the menuComp = to a new menu component on every update call, so all the old variables in there would be lost, hence there was no images loading. SpriteBatch.Begin() was being called twice in a row, and then end was being called twice in a row. One spriteBatch (from game1.cs preferrably) should be used to draw. By sending that spritebatch through the method, you do not need to call begin again, and it is simply better not to for performance reasons. Last thing I noticed (that I can think of) was that the graphics device was not being set to anything because you were constantly creating a new version of it. Oh also, you were calling graphicsDevice.Clear() way too early, this only should be called once per draw (at the beginning, so old graphical info is removed from the screen).
I debugged your program/code and there are a few problems:
There is a declaration of MenuComponent menuComponent, but you didn't create an instance in the Game1() constructor. So add: menuComponent = new MenuComponent()
There is a declaration of SpriteBatch mBatch, but you didn't create an instance in the MenuComponent() constructor. So create one. The same for GameTime gameTime variable.
At the moment I don't have SpriteFont and TheQuantumBros2 texture. Is it possible that you upload your project and share it?

Categories