Jump to content
  • Advertisement
Sign in to follow this  
ukdeveloper

Asteroids - make bullets come from same point in craft each time

This topic is 3720 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I'm still working on my Asteroids clone in XNA and I've hit another brick wall. How would I ensure that the bullets spawn from the same point on the craft each time (i.e. the front) and ensure that they travel in the direction the craft is facing? I've got the origin part right (I think, well at least the bullets all start in the same place) and got the bullets kind of fanning out, but the angles are wrong. When the craft is facing directly up i.e. has completed a 0° turn, the bullet goes straight up which seems correct. When the craft is at 90°, it works fine. When the craft is at 180°, the bullet goes up as at 0°, and when facing 270° the bullet goes out in the correct direction. The rest of the time, the bullet appears to be 45° more or less than the current direction e.g. the craft is pointing south-east and the bullet travels north-east. I tried setting the bullet's direction to be the same as the craft... nothing. I tried setting the bullet's rotation value to be the same as the craft... nada. What then happens is things go screwy if you do multiple rotations and the craft has travelled through something like 1223° or if you do multiple anti-clockwise rotations and it's magically done -1412°. I tried everything else... zip. The bullets and craft are sprites of type Texture2D, not raw pixels or fancy particle effects. I don't think I know exactly how to do this, if any of you have written Asteroids could you possibly help me out?

Share this post


Link to post
Share on other sites
Advertisement
Here's my class representing the bullet:


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Asteroids
{
class Bullet
{
private Texture2D bulletTex;
private Vector2 bulletOrigin; // The bullet's origin is the same for all bullets, they must spawn from the same part of the spacecraft
private Vector2 bulletPosition;

private Vector2 bulletDirection;

private Vector2 bulletVelocity;

private double dFVx;
private double dFVy;

public Bullet(Game game, SpaceShip ship)
{
bulletTex = game.Content.Load<Texture2D>("bullet");
bulletOrigin = new Vector2((ship.shipPosition().X), (ship.shipPosition().Y));

bulletDirection = new Vector2((float)Math.Sin(ship.rotation().Z), (float)(Math.Cos(ship.rotation().Z)));

bulletVelocity = bulletDirection * 5.0f;

//dFVx = Math.Cos(bulletOrigin.X);
//dFVy = Math.Sin(bulletOrigin.X);

bulletPosition = bulletOrigin;
}


// Set the bullet's velocity
public void setVelocity(float t)
{
bulletOrigin *= bulletOrigin * t;
}


// Return the texture we're using for drawing purposes
public Texture2D returnTexture()
{
return (bulletTex);
}


// Return the vector representing the position
public Vector2 returnPosition()
{
return (bulletPosition);
}


// Move the bullet
public void moveBullet()
{
bulletPosition += bulletVelocity;
}
}
}



Here's the class representing the spacecraft:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Asteroids
{
class SpaceShip
{
private Texture2D shipTex;

public Vector2 shipPos;
private Vector2 rotationOrigin;
private Vector3 shipRotation;
private Vector3 shipAccel;

public Vector2 shipVelocity;

private Vector3 shipDirection;

private int screenWidth;
private int screenHeight;

private bool currentlyBoosting;

// Constructor
public SpaceShip(Game game)
{
shipTex = game.Content.Load<Texture2D>("sp_2");

screenWidth = game.GraphicsDevice.Viewport.Width;
screenHeight = game.GraphicsDevice.Viewport.Height;

shipPos = new Vector2(screenWidth / 2, screenHeight / 2);

rotationOrigin = new Vector2(shipTex.Width / 2, shipTex.Height / 2);
shipRotation = new Vector3(MathHelper.ToRadians(90), 0, 0);

shipAccel = new Vector3(0.0f, 0.0f, 0.0f);

shipVelocity = new Vector2(0.0f, 0.0f);

shipDirection = new Vector3((float)(Math.Sin(shipRotation.Z)), (float)(Math.Cos(shipRotation.Z)), 0);
currentlyBoosting = false;
}


// Resets the craft to its original position
public void reset()
{
shipPos = new Vector2(screenWidth / 2, screenHeight / 2);

rotationOrigin = new Vector2(shipTex.Width / 2, shipTex.Height / 2);
shipRotation = new Vector3(MathHelper.ToRadians(90), 0, 0);

shipAccel = new Vector3(0.0f, 0.0f, 0.0f);

shipVelocity = new Vector2(0.0f, 0.0f);

shipDirection = new Vector3((float)(Math.Sin(shipRotation.Z)), (float)(Math.Cos(shipRotation.Z)), 0);
currentlyBoosting = false;
}


// Moves the spacecraft to a given position
public void moveTo(float x, float y)
{
if (currentlyBoosting)
{
shipPos.X += (x * 2);
shipPos.Y -= (y * 2);
}
else
{
shipPos.X += x;
shipPos.Y -= y;
}
}


// Tells us if the ship is boosting or not
public bool isBoosting()
{
return (currentlyBoosting);
}


// Rotates the ship based on the right thumbstick
public void rotateShip(float x, float y)
{
shipRotation.Z += (float)(Math.Atan2(x, y)) / 10;
}


// Performs a hyperspace jump by simply respawning
//public void doHyperJump()
//{
// Random newPos = new Random();

// float newX = newPos.Next(50, screenWidth);
// float newY = newPos.Next(250, screenHeight);

// Vector2 hyperJumpPosition = new Vector2(newX, newY);
// shipPos = hyperJumpPosition;

// moveTo(newX, newY);
//}


// The function for turning the ship's boost on
// Boosting causes the ship to move as much faster, in the way it's facing, as the left trigger is held down
public void boostOn()
{
currentlyBoosting = true;
}


// Turn the boost off when we're done
// Returns the spaceship to normal speed again
public void boostOff()
{
currentlyBoosting = false;
}


// Return the ship's texture
// Used for drawing it
public Texture2D shipTexture()
{
return (shipTex);
}


// Return the current ship position vector
// Used as the destination rectangle
public Vector2 shipPosition()
{
return (shipPos);
}


// Return the current x coordinate for the ship
public float curX()
{
return (shipPos.X);
}


// Return the current y coordinate for the ship
public float curY()
{
return (shipPos.Y);
}


//// Rotate the ship according to the right thumbstick
//public void rotateShip(float degree)
//{
// shipRotation.Z =
//}


// Return the current rotation vector for the ship
// Also used in terms of drawing it
public Vector3 rotation()
{
return (shipRotation);
}


// Return the ship's rotation origin
public Vector2 getRotationOrigin()
{
return (rotationOrigin);
}


// Return the ship's acceleration vector
public Vector3 getAcceleration()
{
return (shipAccel);
}

}
}



Here's where we create new bullets and push them into a List<Bullet>. "test" is the instance of the spaceShip object.

if (GamePad.GetState(PlayerIndex.One).IsButtonDown(Buttons.RightTrigger))
{
// We only want to allow three bullets a second
if (currentTime - lastBulletTime > 300)
{
Bullet local = new Bullet(this, test);
local.setVelocity(t);
firePower.Add(local);
lastBulletTime = currentTime;
}
}

// snip...
// This is the code for drawing the bullets

foreach (Bullet bullet in firePower)
{
bullet.moveBullet();
spriteBatch.Draw(bullet.returnTexture(), bullet.returnPosition(), Color.White);
}




There's a lot of clutter and junk in there, the codebase really is a mess I'm afraid to say :S. I hope what I've given you is sufficient.

Share this post


Link to post
Share on other sites
I don’t understand this function of Bullet:

/ Set the bullet's velocity
public void setVelocity(float t)
{
bulletOrigin *= bulletOrigin * t;
}



Isn’t a setVelocity function supposed to set a velocity? Why you use a vector for a rotation angle that is a scalar?

A design note: I think the ship and the bullets shouldn’t know about the texture used to display it. I also think is the system that should set the position of the ship and not the ship itself. What if you want to add a multiplayer mode? You have to create two ships in different positions, but in the SpaceShip constructor you set the position in the center of the screen and the only way to change the position is using the moveTo function.

Share this post


Link to post
Share on other sites
I don't really understand what you mean in terms of a scalar rotation angle? I've changed the rotation to a float from a Vector2 but I don't see how or why it makes a difference.

I've changed the design of my game entirely now, purely because of this problem. The spacecraft is locked to the bottom of the screen and shoots at objects coming down, it's kind of like Space Invaders and Breakout. I've got the spacecraft so it can rotate 60° to left or right, and I'd like it to be able to fire off in those directions depending on where it's pointing.

If only I could get this stuff with the bullets working properly. What happens now is, well, nothing. The bullets don't even move at all.

I think I might have to junk the bullet class and start over, something's not right at all. What do you think, or do you have any suggestions before I do so?

I just don't understand what I'm supposed to be doing. I've thought about it in detail but I really don't have a clue. You'd think it would be as simple as setting the direction of the bullet to the direction the ship's facing... fuck it, I don't understand.

Share this post


Link to post
Share on other sites
There are two advantages in using a scalar instead of a vector for angles:
1. You use less memory.
2. The code is easier to understand (if you use a vector it isn’t clear the purpose of the others value).

A bullet is spawn in front of the ship (something like shipOrigin + shipOrientation*distance) and then the movement is controlled by the following formula:
bulletPosition = bulletOrigin + bulletVelocity*t

Your Bullet class have several problems (like the setVelocity class that set the origin).

Share this post


Link to post
Share on other sites
I'm going to hose the bullet class at some point and rewrite it, definitely. It's got into such a mess that it's my only real option.

Share this post


Link to post
Share on other sites
Here's some psuedo code to get you started.

"""Overview: bullet spawning:
b = Bullet()
vel = ship.normal_foreward()
vel *= SPEED_BULLET_INITIAL; # use your initial bullet speed here
vel += ship.vel # if you want to add ship vel to initial vel
b.vel = vel
b.loc = ship.loc + ship.offset_loc()
spawn( b )
"""


# psuedo code:
class Entity():
"""base physics entity(). any object that uses location, velocity, and
acceleration will derive from this class."""

Vector3 loc; # location
Vector3 vel; # velocity
Vector3 accel; # acceleration
float rotation; #rotation of ship in radians ( or you can convert before sin)

def update(self):
"""physics update"""
vel += accel
loc += vel
accel = Vector2(0,0) # reset accel every frame.

def draw(self):
# virtual; to be implemented in derived class.

def accelerate(self, force):
"""add force / accelerate. add mass into the calculation if needed."""
self.accel += force;
def rotate(self, rotation): self.rotation += rotation;
def normal_foreward(self):
"""get the normal_foreward vector."""
normal = Vector2()
normal.x = cos( self.rotation );
normal.y = sin( self.rotation )
normal.normalize()
return normal

class Bullet(Entity):
"""bullet class"""
def draw(self):
# do bullet draw

class Ship(Entity):
"""player ship. inherits all of Entity()-ies members."""

def draw(self):
"""do ship draw"""

def fire(self):
"""fire, and spawn bullet."""
b = Bullet()
vel = Vector2()

"""calculate the bullet vel.
vel = bullet_initial + ship.vel [ in the direction ship is moving]"""

vel = self.normal_foreward();
vel *= SPEED_BULLET_INITIAL; # use your initial bullet speed here
vel += self.vel # if you want to add ship vel to initial vel
b.vel = vel

"""calc bullet loc
loc = ship.loc + spawn offset"""

b.loc = self.loc + self.offset_loc();

"""then depending on how you handle your objects, spawn here, or maybe
return the new Bullet()."""

game.spawn( bullet )

def offset_loc(self):
"""get the offset to spawn bullet.
SHIP_LENGTH = dist from ship center to ship spawn location"""

return self.normal_foreward() * SHIP_LENGTH



Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!