I have just started making a game that is going to be somewhat like space invaders.
I'm a complete novice when it comes to programming and have little experience (I'm only attempting this as I need to have a software design project due at the end of next week).
Anyways, I have been following a tutorial on how to fire bullets. and it doesn't seem to be working. I have copied almost every aspect of this tutorial except for the 'velocity' variable in the 'bullets' class (which I don't think I need as I'm only using side to side movement not forward/back).
This is the code below. Thanks in advance. :)
Main
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 Software_Design_Major_Project
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D ship; // Declaring the sprite
Vector2 shipposition = Vector2.Zero;
List<bullets> bullets = new List<bullets>();
KeyboardState pastkey;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 600;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
ship = Content.Load<Texture2D>("ship"); // Loads the ship into the memory.
shipposition = new Vector2((graphics.GraphicsDevice.Viewport.Width / 2) -
(ship.Width / 2), 420);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Left) && shipposition.X
>= 0)
{
shipposition.X -= 6;
}
if(Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right) && shipposition.X <
((graphics.GraphicsDevice.Viewport.Width) - (ship.Width)))
{
shipposition.X += 6;
}
if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastkey.IsKeyUp(Keys.Space))
{
shoot();
}
pastkey = Keyboard.GetState();
updatebullets();
base.Update(gameTime);
}
public void updatebullets()
{
foreach(bullets bullet in bullets)
{
if (Vector2.Distance(bullet.position, shipposition) < 0)
bullet.isvisible = false;
}
for (int i = 0; i < bullets.Count; i++)
{
if (!bullets[i].isvisible)
bullets.RemoveAt(i);
i--;
}
}
public void shoot()
{
bullets newbullet = new bullets(Content.Load<Texture2D>("bullet"));
newbullet.position = shipposition;
newbullet.isvisible = true;
if (bullets.Count < 20)
bullets.Add(newbullet);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
spriteBatch.Draw(ship, shipposition, Color.White);
spriteBatch.End();
foreach (bullets bullet in bullets)
bullet.Draw(spriteBatch);
base.Draw(gameTime);
}
}
}
Bullets
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Software_Design_Major_Project
{
class bullets // A new class needs to be created to allow for bullets.
{
public Texture2D texture;
public Vector2 position;
public Vector2 origin;
public bool isvisible;
public bullets(Texture2D newtexture)
{
texture = newtexture;
isvisible = false;
}
public void Draw(SpriteBatch spritebatch)
{
spritebatch.Draw(texture, position, null, Color.White, 0f, origin, 1f,
SpriteEffects.None, 0);
}
}
}
P.S. Sorry for the long post.
I don't see any code that changes your bullets position, Your going to need a velocity variable, and update the position based on the velocity each frame.
And you could get the angle from a = Math.Atan(Y,X)
Looks like you probably removed the part that calculates position, as you thought you didn't need the velocity stuff. I suggest you try adding it back to see if it works, and then removing parts you don't need.
Surprised nobody spotted this sooner.
You're ending your SpriteBatch before the bullets have been drawn.
Calls to SpriteBatch.Draw must occur between the Begin and End methods because of all the work that goes on behind the scenes to make drawing as fast as possible.
All you need to do is move spriteBatch.End() further down, like so:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
spriteBatch.Draw(ship, shipposition, Color.White);
foreach (bullets bullet in bullets)
bullet.Draw(spriteBatch);
spriteBatch.End(); //Move to here instead
base.Draw(gameTime);
}
Extra Trivia:
Basically what goes on behind the scenes is that the sprite batch actually batches up the textures using the settings described by begin (yes, these can be changed) and then when end is called, it figures out which bits fall outside the screen and makes note not to draw them, it depth sorts the textures if told to and it does all sorts of other optimisations before drawing them to the back buffer and then finally when all drawing is over, the back buffer gets presented to the screen and the old one is taken and reused for the next draw call. It sounds like a lot of work, but with the way modern computers work, the optimisations tend to create a big improvement.
you could check this sample right here. I've coded this stuff a long time ago, I think in v2.0 of XNA, can't rembember now.
http://gozoomin.com/media/p/69699.aspx
The logic in there is quit simple :)
Starting making a 'classic' is always a good way to start.
Edit - You can get it here as well: http://www.sendspace.com/file/r4s4um
Edit2 - I just checked the code now, it's with some comments documenting most of things, probably you will get some stuff written in portuguese.
PS - Don't copy past the code! Try to learn the basics around the sample.
Related
The classes look like this:
Game
has-a Player
Player
has-a SpriteInstance
SpriteInstance
has-a List<SpriteInstance>
Each render step, Game calls Draw() on Player. Player calls draw() on SpriteInstance. And draw() looks like this:
public void draw(SpriteBatch spriteBatch, Vector2 offset = default(Vector2), float rotation = 0f)
{
spriteBatch.Draw(texture, offset + pos, null, Color.White, rot+rotation, sprite.origin, 1f, SpriteEffects.None, z);
foreach (var child in children)
{
child.draw(spriteBatch, offset + pos, rotation + rot);
}
}
My expected output is being able to see both the SpriteInstance on the screen, and each texture from each child of SpriteInstance, but my actual output is just the SpriteInstance and none of the children. I have tried using a debugger, but it shows that the child's draw() function is definitely called. And since spriteBatch is a magical black box that's as far as I can go...
Is there something wrong about passing spriteBatch around? Am I passing it by value somehow when it should be passed by reference?
edit: here are all the draw functions
Game
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();// sortMode: SpriteSortMode.FrontToBack);
player.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
Player
public void Draw(SpriteBatch spriteBatch)
{
sprite.draw(spriteBatch);
}
edit2:
Bringing the spriteBatch.draw() calls out into the foreach loop does make it display, but I don't know what the difference is... it is also not a proper fix.
Try this and let me know if it works.
public void draw(SpriteBatch spriteBatch, Vector2 offset = default(Vector2), float rotation = 0f)
{
spriteBatch.Begin(); //Starts the drawing loop
spriteBatch.Draw(texture, offset + pos, null, Color.White, rot+rotation, sprite.origin, 1f, SpriteEffects.None, z);
foreach (var child in children)
{
child.draw(spriteBatch, offset + pos, rotation + rot);
}
spriteBatch.End(); // This is for ending the drawing loop.
}
If that doesn't work I would like to see your main class, and a copy of the output you are getting when you run the application. Please also list any errors that occur.
Is it possible to set the position of a sprite to the exact same position of another sprite which is being moved.
So I want to set the "sprite.position" to a the same position that my class Character is in:
Character.cs:
class Character
{
Texture2D texture;
public Vector2 position;
Vector2 velocity;
public Character(Texture2D newTexture, Vector2 newPosition)
{
texture = newTexture;
position = newPosition;
}
public void Update(GameTime gameTime)
{
position += velocity;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Game1.cs:
public class Game1 : Microsoft.Xna.Framework.Game
{
Bullet bullet;
Character player;
protected override void Initialize()
{
allSprites = new List<ISprite>();
allSpriteObstakels = new List<ISprite>();
bullet.position = Character.position; // not working
base.Initialize();
}
}
As the comments have suggested, when you say "it's not working" you need to be clear about what "not working" actually means. For example, are you getting a compile error? Are you getting a runtime exception? Is the game running but it isn't doing what you expect (logical error)?
That said, here's my best guess as to what might be going on:
I don't know if the code above is complete but the bullet and player are not instantiated anywhere. You need to "new" the instances before you use them.
You are using the "bullet.position" where bullet is an instance, but then you're using "Character.position" where Character is a class. Did you intend to use "player.position" instead?
This code will only run once, which means the bullet will be set to the same position as the character. If you intend for the bullet position to always be the same as the character, then you need to continually re-assign the bullet.position value every frame.
But the most important thing is to learn to ask questions so that the community here can help you out.
I am creating a game in which asteroids spawn and move down the screen. In the update method of the game, i am using a random number to spawn the asteroids sporatically. When i start it up, it begins to lag within the first 5 seconds. I can see this because the score counter(which goes up every tick) starts going in intervals of 30. Also, the images of the asteroid do not even show up.
Here is the gameObject 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.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace thedodger
{
public abstract class gameObject
{
public static Texture2D texture;
public Rectangle rectangle;
public abstract void Draw(SpriteBatch spriteBatch);
public abstract void Update(GameTime gameTime);
}
}
here is the asteroid 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.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace thedodger
{
public class Asteroid : gameObject
{
Random rand = new Random(1);
int yPos = -10;
public override void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Begin();
spriteBatch.Draw(texture, new Rectangle(rand.Next(32,400), yPos,32,32),Color.White);
spriteBatch.End();
}
public override void Update(GameTime gameTime)
{
yPos--;
}
}
}
and here is the game1 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;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace thedodger
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
int scorevalue = 0;
SpriteFont font;
player player1 = new player();
List<gameObject> objectList = new List<gameObject>();
Random rand = new Random(1);
Asteroid asteroid = new Asteroid();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <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);
font = Content.Load<SpriteFont>("font");
//player1.image = Content.Load<Texture2D>("EnemyShip005.png");
gameObject.texture = Content.Load<Texture2D>("asteroid");
// TODO: use this.Content to load your game content here
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
scorevalue++;
if (rand.Next(0, 8) == 2)
{
for (int i = 0; i < 30; i++)
{
objectList.Add(asteroid);
}
}
foreach (Asteroid asteroid in objectList)
{
asteroid.Update(gameTime);
asteroid.Draw(spriteBatch);
}
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
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.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
spriteBatch.DrawString(font, "Score: " + scorevalue, new Vector2(5, 5), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
All help would be greatly appreciated.
sorry about the code. I am having difficult setting it up. Help on that too please.
As Tobias said, you probably should have put this on the Game Dev site and you appear to only have one Asteroid instantiated. In the Game1 object, you declare and instantiate an Asteroid object. Then in the Update method you add it repeatedly to the objectList. To get what I think you want, you should change
Asteroid asteroid = new Asteroid();
to
Asteroid asteroid;
Then change
for (int i = 0; i < 30; i++)
{
objectList.Add(asteroid);
}
to
for (int i = 0; i < 30; i++)
{
asteroid = new Asteroid();
objectList.Add(asteroid);
}
In your original code you declare and instantiate asteroid as a specific Asteroid but then never change it. So, throughout the whole program asteroid is pointed to one specific instance of an Asteroid. Then you repeatedly add asteroid to the objectList. So after each frame, 30 new references to the same asteroid object are being added to the objectList and the Update() and Draw() methods are being called on asteroid for every reference to it in objectList. So after 30 frames, one second if running at 30FPS, up to 900 references to the same exact asteroid object are in objectList and on that 30th frame asteroid is having its Update() and Draw() methods called up to 900 times. I'm pretty sure this is the source of your lag. Doing the corrections given above will result in objectList being populated with up to 900 different Asteroids, but will certainly experience lag as well. What you need to do as well is add a limit to the amount of asteroids on screen at any given time (the length of objectList can only be x amount) and/or lower the amount of asteroids created each time. I would suggest something like
for (int i = 0; i < 5; i++)
{
if (objectList.Count < 50) // Maximum asteroids on screen
{
asteroid = new Asteroid();
objectList.Add(asteroid);
}
}
will result in only five new asteroids for time and a maximum of 50 at any given time. If you add in functionality to destroy asteroids though, you'll have to remember to remove them from the objectList.
EDIT- As Neomex has said, your drawing is also a problem. I would suggest checking out the GDC 2008 talk on the XNA Framework performance here: http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=6082
It very briefly covers some drawing and calculation performances and what you should/shouldn't do.
EDIT2- Actually, because of your random probability, it would be up to 900 object references and calls, not a full 900.
Try to make as least begin-end calls as possible, they often slow down game a lot.
( Asteroid class )
You are displaying graphics in your update function which is really bad thing.
If these fail, try to download newest drivers.
Reasuming:
Change in your asteroid class
public override void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Begin();
spriteBatch.Draw(texture, new Rectangle(rand.Next(32,400), yPos,32,32),Color.White);
spriteBatch.End();
}
to
public override void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, new Rectangle(rand.Next(32,400), yPos,32,32),Color.White);
}
Now in your update function
foreach (Asteroid asteroid in objectList)
{
asteroid.Update(gameTime);
asteroid.Draw(spriteBatch);
}
to
foreach (Asteroid asteroid in objectList)
{
asteroid.Update(gameTime);
}
And add this in draw function:
foreach (Asteroid asteroid in objectList)
{
asteroid.Draw(spriteBatch);
}
As Tobias has already pointed out, you are using the same asteriod object every time you want to spawn a new asteriod. You need to do add a new Asteriod() to the object list instead of using the same one.
Also, this code is mostly likely the reason you are suffering performance wise.
if (rand.Next(0, 8) == 2)
{
for (int i = 0; i < 30; i++)
{
objectList.Add(asteroid);
}
}
You are adding 30 instances of the same object to the collection on every update call (with is around 60 times a second). I realize you are using a random number, but it sill happens to about 12.5% of the update calls.
So within a 5-10 seconds, you now have thousands of these objects and are drawing the same image thousands and thousands of times.
I am having some issues with my mouse coordinates in XNA - the 0x0 is arbitrarily near (but not in) the top left corner of my screen.
I am running the game in a windowed mode right now, but the coordinates are based off the screen, not the game window (even though the XNA documentation tells me it should be otherwise)
Thanks in advance!
Here's the code:
namespace TheGame
{
class Mousey
{
static public Vector2 pos;
static private Texture2D tex;
static public MouseState mouseState;
static public MouseState previousState;
//static public Mousey()
//{
//}
static public void Update()
{
previousState = mouseState;
mouseState = Mouse.GetState(); //Needed to find the most current mouse states.
pos.X = mouseState.X; //Change x pos to mouseX
pos.Y = mouseState.Y; //Change y pos to mouseY
}
//Drawing function to be called in the main Draw function.
static public void LoadContent(ContentManager thecontent)
{
tex = thecontent.Load<Texture2D>("mousey");
}
static public void Draw(SpriteBatch batch) //SpriteBatch to use.
{
batch.Draw(tex, pos, Color.White); //Draw it using the batch.
}
static public bool LBP()
{
if (mouseState.LeftButton == ButtonState.Pressed && previousState.LeftButton == ButtonState.Released)
{
return true;
}
else
{
return false;
}
}
}
}
In game.cs:
//sets the windows mouse handle to client bounds handle
Mouse.WindowHandle = Window.Handle;
private IntPtr intPtr;
public MouseControle(int w, int h, IntPtr intPtr)
{
screenwidth = w;
screenheight = h;
this.intPtr = intPtr;
Mouse.WindowHandle = intPtr;
}
This works for me ;)
To use this, I add this to my game-component using that class:
mouse = new MouseControle(((Game1)Game).setscreen.width,
((Game1)Game).setscreen.height,
((Game1)Game).Window.Handle);
Hope this helps sombody :D
Did you try something simpler like this?
protected override void Draw( GameTime gameTime )
{
graphics.GraphicsDevice.Clear( Color.CornflowerBlue );
base.Draw( gameTime );
MouseState current_mouse = Mouse.GetState();
Vector2 pos = new Vector2(current_mouse.X, current_mouse.Y);
batch.Draw(tex, pos, Color.White);
}
There may be some time between draw and update, due to the way timing works in XNA, maybe is this the cause of the perceived pixel offset?
And... are you sure you "configured" your sprite batch correctly? Coordinates are relative to game window, so the documentation say.
Another thing: Why are you using static fields? I really don't like this choice, an anti-pattern. Use class fields, not static fields.
Also... i guess you are drawing a mouse icon, right? consider that XNA start to draw the texture from the specified point, are you sure the texture is well shaped with the top-left point as your mouse arrow end?
I found a nice example here you may like: http://azerdark.wordpress.com/2009/07/08/displaying-cursor-xna/
Consider also that you can enable and disable the normal windows OS mouse cursor with IsMouseVisible = true;
Your draw call is not offsetting the texture at all. If the "pointer" part of your image isn't in the 0,0 position (top left) of your Texture, the positioning will seem off.
Add a Console.WriteLine(pos); to your update to see the position it is drawing to. Remember to remove this after your debugging because writeline will kill your performance.
Try one of the overloaded SpriteBatch.Draw() calls which factor in an "origin" which lets you decide which point of the texture should be drawn at the position. In the following code tweak the Vector 2 based upon how your texture is drawn.
batch.Draw(tex, pos, null, Color.White, 0.0f, new Vector2(10, 10), SpriteEffects.None, 0.0f);
I'm a c++ programmer trying out c#. I've done a lot with box2d in c++, but this is my first time with c#. So, I'm trying to make a simple game with farseer physics engine. When I try to compile my code (I'm using visual studio c# 2010 express and xna game studio 4.0), it stops in body.cs at IBroadPhase broadPhase = World.ContactManager.BroadPhase; With this error: nullreferenceexception was unhandled. I believe the problem is in my Player class, so here's the code for that:
public class Player : Entity
{
Vector2 position;
SpriteBatch spriteBatch;
Texture2D texture;
Rectangle rectangle;
Body body;
CircleShape shape;
Fixture fixture;
public Player()
{
// TODO: Construct any child components here
}
///
/// Allows the game component to perform any initialization it needs to before starting
/// to run. This is where it can query for any required services and load content.
///
public override void Initialize(World world, SpriteBatch spriteBatch, Texture2D texture)
{
// TODO: Add your initialization code here
this.spriteBatch = spriteBatch;
this.texture = texture;
rectangle = new Rectangle(0, 0, 11, 14);
body = BodyFactory.CreateBody(world);
body.BodyType = BodyType.Dynamic;
body.Position = new Vector2(0, 0);
shape = new CircleShape(1.0f, 1.0f);
fixture = body.CreateFixture(shape);
base.Initialize(world, spriteBatch, texture);
}
///
/// Allows the game component to update itself.
///
/// <param name="gameTime" />Provides a snapshot of timing values.
public override void Update(GameTime gameTime)
{
// TODO: Add your update code here
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
spriteBatch.Draw(texture, new Vector2(body.WorldCenter.X * 10, body.WorldCenter.Y * 10), rectangle, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
The farseer testbed runs fine, so I'm pretty sure my code is the problem, and not farseer. Let me know if you need to see more of my code. I've also posted this in the farseer forums, so If I get an answer there, I'll let you guys know. Thanks in advance.
Someone asked me to show the code of Game1.cs, and found the problem. The problem was that I had never constructed the world before initializing my player. It was fixed by adding world = new World(Vector2.Zero); before I initialized the player.