Spaceship fires lazer from center of sprite and NOT from the front

I have a strnge problem. When I fire the spaceship lazer it ALWAYS fire from the center of the spaceship. The sprite rotation and directions are all ok. Please help to get the ship to fire from its front.
I create a lazer shot like this:
`if (keyboard.IsKeyDown(Keys.Space) && shoot)
{
shoot = false;
//is.fireInst.Play();
this.fire.Play(.2f, .9f, 0);
lazerX = (float)(spritePosX - (0) * Math.Cos(rotationAngle));
lazerY = (float)(spritePosY - (0) * Math.Sin(rotationAngle));

 Projectile projectile = new Projectile(heroLazer, "heroLazer",
     lazerX, lazerY, rotationAngle);

 Game1.AddProjectile(projectile);

}`

then the projectile is created like this.
`public Projectile(Texture2D lazerSprite, string spriteName,
float posx, float posy, float heading)
{
projectileSprite = lazerSprite;
type = spriteName;
spriteRotOrigin = new Vector2(projectileSprite.Width / 2, projectileSprite.Height / 2);
spriteHeading = heading;
spritePosX = posx; // the x position of the lazer
spritePosY = posy; // the y position of the lazer

spritePos = new Vector2(spritePosX, spritePosY);
drawRectangle = new Rectangle((int)spritePosX, (int)spritePosY,
    projectileSprite.Width / 2, projectileSprite.Height / 2);

}
`
and updated like this

`public void update(GameTime gameTime, KeyboardState keyboard)
{
//projectile active or not?
if (active == true)
{
projectileAge += gameTime.ElapsedGameTime.Milliseconds;

     spritePosX += (float)(Math.Sin(spriteHeading) *
         gameTime.ElapsedGameTime.TotalMilliseconds) * ProjectileMoveAmount;
     spritePosY -= (float)(Math.Cos(spriteHeading) *
         gameTime.ElapsedGameTime.TotalMilliseconds) * ProjectileMoveAmount;

     spritePos = new Vector2(spritePosX, spritePosY);
 }
 if (projectileAge > projectileLife)
 {
     active = false;
 }`

can anyone help? Do you need images and all the code?

That is not how you rotate a 2d vector. newX = x * cos(deg) - y * sin(deg); newY = x * sin(deg) + y * cos(deg);

You need to rotate an offset vector relative to 0,0 (such as 0,1; etc) and add ship sprite’s position to it.

example: var lazerSpawnPt = VectorExt.Rotate(Vector2.UnitY * WorldConst.UnitToPixels, rotationAngle) + shipPos;

1 Like

PSA: Formatting code


When posting source code, please wrap it in triple backticks:

```
Your code here
```

Looks like this:

var x = 5;
Console.WriteLine(sum(x, x));
int sum(int v1, int v2)
{
    return v1 + v2;
}

For inline code you can wrap it in single backticks:

Above I defined the sum method.

Looks like this:
Above I defined the sum method.

You can also use other markdown stuff, like I did with the title and separator at the top:

## PSA: Formatting code
______

For links use [text that links](URL)

2 Likes

Can you please be a bit more specific. I create the lazer shot when I press the space by like this:

if (keyboard.IsKeyDown(Keys.Space) && shoot)
{
    shoot = false;
    //is.fireInst.Play();
    this.fire.Play(.2f, .9f, 0);
    lazerX = (float)(spritePosX - (0) * Math.Cos(rotationAngle));
    lazerY = (float)(spritePosY - (0) * Math.Sin(rotationAngle));
 
    Projectile projectile = new Projectile(heroLazer, "heroLazer",
        lazerX, lazerY, rotationAngle);
 
    Game1.AddProjectile(projectile);
}

Then in the projectile class I create an instance of the projectile with the above info like this:

public Projectile(Texture2D lazerSprite, string spriteName,
    float posx, float posy, float heading)
{
    projectileSprite = lazerSprite;
    type = spriteName;
    spriteRotOrigin = new Vector2(projectileSprite.Width / 2, projectileSprite.Height / 2);
    spriteHeading = heading;
    spritePosX = posx; // the x position of the lazer
    spritePosY = posy; // the y position of the lazer
 
    spritePos = new Vector2(spritePosX, spritePosY);
    drawRectangle = new Rectangle((int)spritePosX, (int)spritePosY,
        projectileSprite.Width / 2, projectileSprite.Height / 2);
 
}

then in the projectile update method like this:

public void update(GameTime gameTime, KeyboardState keyboard)
{
    //projectile active or not?
    if (active == true)
    {
        projectileAge += gameTime.ElapsedGameTime.Milliseconds;
 
        spritePosX += (float)(Math.Sin(spriteHeading) *
            gameTime.ElapsedGameTime.TotalMilliseconds) * ProjectileMoveAmount;
        spritePosY -= (float)(Math.Cos(spriteHeading) *
            gameTime.ElapsedGameTime.TotalMilliseconds) * ProjectileMoveAmount;
 
        spritePos = new Vector2(spritePosX, spritePosY);
    }
    if (projectileAge > projectileLife)
    {
        active = false;
    }
}

then i draw the projectile like this

public void Draw(SpriteBatch spriteBatch)
 {
     //spriteBatch.Draw(projectileSprite, drawRectangle, Color.White);
 
     spriteBatch.Draw(projectileSprite, spritePos, null,
         Color.FromNonPremultiplied(255, 255, 255, 255), spriteHeading,
         spriteRotOrigin, 1.0f, SpriteEffects.None, 0f);
 
 }

Can you please use this code and show me the way. My trignometry is very very rusty. I did not understand your above reply well.

Thank youu very much for showing me the correct way to format. Will use in the future. :slight_smile:

Thank youu very much for showing me the correct way to format. Will use in the future.

Ignore the triple backtick. It’s unreliable. Use 4 spaces instead.

Is it possible for you to drop your project onto github or such?

hoot = false;
//is.fireInst.Play();
this.fire.Play(.2f, .9f, 0);
lazerX = (float)(spritePosX - (0) * Math.Cos(rotationAngle));
lazerY = (float)(spritePosY - (0) * Math.Sin(rotationAngle));

Projectile projectile = new Projectile(heroLazer, "heroLazer",
    lazerX, lazerY, rotationAngle);

That is the block that is outright wrong.

here is the project on bitbucket. All the code and assets are here.
Space Battles

Where’s the code? Went through the repo but didn’t see anything resembling the code you posted.

In the repo on the left side column there is “source”. (right under Overview)
When you click that it opens the folder. Inside that is another folder titled space battles.
Inside that is the Visual Studio 2017 C# code.
There are multiple files. The Code I wrote is in the Game1.cs, Hero.cs and Projectiles.cs.

Is it too late to say, set the laser layer below the ship?

can yu show some code please?

It’s not about code but a coding concept…

I solved the problem by adding the following code

if (keyboard.IsKeyDown(Keys.Space) && shoot)
 {
     shoot = false;
     //is.fireInst.Play();
     this.fire.Play(.2f, .9f, 0);
     float newRotAngle = Game1.DegreesToRadians(rotationAngle);
 
     // the new code
 
     lazerX = spritePosX + (float)Math.Sin(rotationAngle) * HeroSprite.Width / 2;
     lazerY = spritePosY - (float)Math.Cos(rotationAngle) * HeroSprite.Height/2;
     
     //      
     Projectile projectile = new Projectile(heroLazer, "heroLazer",
         lazerX, lazerY, rotationAngle);
 
     Game1.AddProjectile(projectile);
 }

and then this code

public void update(GameTime gameTime, KeyboardState keyboard)
 {
     //projectile active or not?
     if (active == true)
     {
         projectileAge += gameTime.ElapsedGameTime.Milliseconds;
 
         ProjectilePosX += (float)(Math.Sin(spriteHeading) *
             gameTime.ElapsedGameTime.TotalMilliseconds) * ProjectileMoveAmount;
         ProjectilePosY -= (float)(Math.Cos(spriteHeading) *
             gameTime.ElapsedGameTime.TotalMilliseconds) * ProjectileMoveAmount;
 
         spritePos = new Vector2(ProjectilePosX, ProjectilePosY);
     }
     if (projectileAge > projectileLife)
     {
         active = false;
     }
 }

Couple things guy.

You want a ship class.
You want a projectile class.
You want to use vectors instead of two variables it makes things simpler.

You want to separate terms and use simple steps.

Projectile projectile = new Projectile();

// Vector2
ship.Heading = new Vector2( (float)(Math.Sin(ship.BeringInRadians)), (float)(Math.Cos(ship.BeringInRadians)) ) // bering is a float

// Vector2
ship.Velocity = ship.Heading * ship.Speed; // speed is a float

// Vector2
projectile.Position = ship.Position + ship.Heading * ship.Texture.Width * .55;

// Vector2
projectile.Heading = Vector2.Normalize(ship.Velocity);

// Vector2
projectile.Velocity = projectile.Heading * projectile.Speed;

// update
projectile.Position += projectile.Velocity * gameTime.ElapsedGameTime.TotalMilliseconds;

using matrix’s instead of sin cos is recommended and using CreateWorld or create rotation z.

Its not recommended to be using bering in degrees or radians but only calculating that from sin cos. Then only once in a while for output to display the bering to the user. That is done using a function called Math.Atan2(y,x) which has to be fiddled with to get it into monogames coordinate system;

I have a ship class, a projectile class, constants class and a game class and all the code is in the appropriate places. I just copied ans pasted the relevant ones here. Thanks for your idea. I solved the problem yesterday.
:slight_smile:

That’s mostly right (just not robust, as you’re using the equation of a circle - which isn’t quite rotation, but will be good enough if always working with square things). Beware of scale.

Above is the code to find the X and Y position of a point on the circumference of a circle ( which in this case happens to be the point from which the spaceship fires the projectile) and that code is the best way to do it. If there is another way please let me know. I am new to Monogame and C#. Just only 4 months of learning that and to use Visual Studio. :slight_smile:

Matrix’s but this is fine with 2d.

You can take a look at Vector2.Transform(…) and Matrix.CreateRotationZ(…)
Same thing with the caveat that with matrices you learn the 3d stuff at the same time.

I found this great set of tutorials from CodingMadeEasy on Youtube great monogame tutes

am following that to broaden my scope… :slight_smile: