0
\$\begingroup\$

I'm trying to shoot a bullet from the tip of a gun. This gun is a Sprite object and it is constantly being rotated to point towards the mouse. The issue is that the point to shoot the bullet from is always changing because the sprite rotates. How can I calculate the point to shoot from the tip of the gun when the sprite rotates?

    @Override
    public void render(SpriteBatch batch) {
        super.render(batch);

        Sprite weaponSprite = this.currentWeapon.getSprite();

        Vector3 mv = screen.getBatchCamera().unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
        weaponSprite.setOriginCenter();
        weaponSprite.setRotation(CalcUtils.getAngle(new Vector2(weaponSprite.getX(), weaponSprite.getY()), new Vector2(mv.x, mv.y)));
        weaponSprite.setFlip(this.isFlipped(), false);

        batch.begin();
        if (this.isFlipped()) {
            weaponSprite.setPosition(this.getPosition().x - 3, this.getPosition().y);
        } else {
            weaponSprite.setPosition(this.getPosition().x + 23, this.getPosition().y);
        }
        weaponSprite.draw(batch);
        batch.end();

    }
    @Override
    public void update(float delta) {
        super.update(delta);

        this.shootTime += delta;

        Sprite weaponSprite = this.currentWeapon.getSprite();
        Sprite bulletSprite = this.currentBullet.getSprite();
        if (Gdx.input.isButtonJustPressed(Input.Buttons.LEFT)) {
            this.shootTime = 0;

            Vector2 bulletPosition = new Vector2(weaponSprite.getX(), weaponSprite.getY());  // this is the beginning position of the project, what the bullet will start at
            bulletSprite.setSize(2, 2);
            bulletSprite.setOriginCenter();

            if (weaponSprite.isFlipX()) {
                bulletPosition.add(-3, weaponSprite.getHeight() - 2);
            } else {
                bulletPosition.add(weaponSprite.getWidth() + 1, weaponSprite.getHeight() - 2);
            }

            Vector3 mv = screen.getBatchCamera().unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
            Projectile projectile = Projectile.create();
            projectile.beginning(bulletPosition);
            projectile.ending(new Vector2(mv.x, mv.y));
            projectile.speed(500f);
            projectile.sprite(bulletSprite);
            projectile.start();
        }
    }
\$\endgroup\$
5
  • \$\begingroup\$ What have you tried? \$\endgroup\$
    – Tyyppi_77
    Oct 16 at 18:49
  • \$\begingroup\$ Multiplying width and height by rotation / 180f Changing adding or subtraction of point based on sprite flip. Can't find something on this for Unity either. I figured unity would have something for it and I could steal the math for it \$\endgroup\$ Oct 16 at 18:52
  • \$\begingroup\$ I suggest you edit the question and show us the code you have to position/orient the gun sprite, and a screenshot would help. \$\endgroup\$
    – Vaillancourt
    Oct 16 at 23:53
  • \$\begingroup\$ "Can't find something on this for Unity either" You mean this? We have dozens of Q&A posts talking about the math for solving this or equivalent problems. \$\endgroup\$
    – DMGregory
    Oct 17 at 12:27
  • \$\begingroup\$ @vaillancourt I have uploaded the code as you have requested. DMGregory I guess I've searched for the wrong questions. \$\endgroup\$ Oct 17 at 14:56
1
\$\begingroup\$

libGDXs Vector2 class has the methods you need to calculate this.

By defining a barrelOffset

barrelOffset = new Vector2(1.0f, -0.5f).scl(0.5f); // Relative coordinates to where the barrel is in the sprite

as the relative position of the barrel in the sprite, we can figure out where the rotated barrel is by taking the position of the player and adding the barrelOffset rotated by the angle the player is facing plus the rotation origin.

Vector2d.rotate can do the rotation for you:

    Vector2 direction = (new Vector2(1.0f, 0.0f)).rotateDeg(angle); // unit vector of the direction of the player
    Vector2 origin = new Vector2(0.5f, 0.5f); // rotation origin, rotate around the center of the image. ( 0,0 would have been upper left corner)
    Vector2 offset = (new Vector2(barrelOffset)).rotateDeg(angle).add(origin); // Rotated barrel offset
    Vector2 barrelPosition = (new Vector2(position)).add(offset);

shooter

Full source code for the animation above is:

import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.graphics.glutils.*;
import com.badlogic.gdx.math.*;
import com.badlogic.gdx.utils.*;

public class MyGdxGame extends ApplicationAdapter {

    public static class Bullet
    {
        public Vector2 position = new Vector2();
        public Vector2 direction = new Vector2();

        public Bullet(Vector2 position,  Vector2 direction)
        {
            this.position.set(position);
            this.direction.set(direction);
        }

        public void update(float delta) {
            float speed = 16.0f;
            position.add(direction.x * delta * speed, direction.y * delta * speed);
        }
    }

    OrthographicCamera camera;
    SpriteBatch spriteBatch;
    ShapeRenderer shapeRenderer;
    Texture texture;

    Vector2 position;
    Vector2 barrelOffset;
    float angle;

    Array<Bullet> bullets;

    @Override
    public void create() {
        float aspectRatio = (float)Gdx.graphics.getWidth() / (float)Gdx.graphics.getHeight();
        camera = new OrthographicCamera(10, 10 / aspectRatio);
        spriteBatch = new SpriteBatch();
        shapeRenderer = new ShapeRenderer();
        texture = new Texture("hitman1_gun.png"); // From https://opengameart.org/content/topdown-shooter (Kenney)

        position = new Vector2();
        barrelOffset = new Vector2(1.0f, -0.5f).scl(0.5f); // Relative coordinates to where the barrel is in the sprite

        bullets = new Array<>();
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        camera.update();
        spriteBatch.setProjectionMatrix(camera.combined);
        spriteBatch.begin();

        Vector2 direction = (new Vector2(1.0f, 0.0f)).rotateDeg(angle); // unit vector of the direction of the player
        Vector2 origin = new Vector2(0.5f, 0.5f); // rotation origin, rotate around the center of the image. ( 0,0 would have been upper left corner)
        Vector2 offset = (new Vector2(barrelOffset)).rotateDeg(angle).add(origin); // Rotated barrel offset
        Vector2 barrelPosition = (new Vector2(position)).add(offset);


        float delta = Gdx.graphics.getDeltaTime();
        if (Gdx.input.isKeyPressed(Input.Keys.A))
            angle += delta * 90.0f;
        if (Gdx.input.isKeyPressed(Input.Keys.D))
            angle -= delta * 90.0f;
        if (Gdx.input.isKeyPressed(Input.Keys.W))
            position.add(direction.x * delta * 2.0f, direction.y * delta * 2.0f);
        if (Gdx.input.isKeyPressed(Input.Keys.S))
            position.sub(direction.x * delta * 2.0f, direction.y * delta * 2.0f);
        if (Gdx.input.isKeyPressed(Input.Keys.SPACE))
            bullets.add(new Bullet(barrelPosition, direction));

        for(Bullet bullet : bullets)
            bullet.update(delta);

        spriteBatch.draw(texture,
                position.x, position.y,
                0.5f, 0.5f,
                1, 1,
                1, 1,
                angle,
                0, 0,
                texture.getWidth(), texture.getHeight(),
                false, false);

        spriteBatch.end();

        shapeRenderer.setProjectionMatrix(camera.combined);
        shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);

        shapeRenderer.setColor(Color.RED);

        for(Bullet bullet : bullets)
            shapeRenderer.circle(bullet.position.x, bullet.position.y, 0.1f, 32);

        shapeRenderer.end();
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ Thank you sir. I don't deserve the amount of effort needed to write that code for me. \$\endgroup\$ Oct 17 at 18:31
  • \$\begingroup\$ Nonsense, @AlbertBeaupre, of course you do. \$\endgroup\$
    – bornander
    Oct 17 at 19:49
0
\$\begingroup\$

You could use trigonometry to do this.

enter image description here

Where T is the angle:

sinT = O / H
H * sinT = O

And you can see that O (Opposite) is basically the Y axis. Do the same with cosine, and you'll get A (Adjacent) which is basically the X axis. H would be the distance from the gun's pivot to the muzzle, and T is the angle.

\$\endgroup\$
4
  • \$\begingroup\$ I would love to implement this. I do not understand much about the math, but would you be able to put this in some kind of pseudocode? I'm terrible at math! \$\endgroup\$ Oct 16 at 21:34
  • \$\begingroup\$ I'm even willing to pay someone to write a piece of generic code for something like this. I learn better looking at code \$\endgroup\$ Oct 16 at 23:46
  • \$\begingroup\$ @AlbertBeaupre Basic trigonometry for a game developer is a must-have skill. I suggest you take the time to learn this as this will be useful for your whole life. \$\endgroup\$
    – Vaillancourt
    Oct 16 at 23:50
  • 1
    \$\begingroup\$ Alright, I guess I'll have at it \$\endgroup\$ Oct 17 at 14:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.