DonMugad DonMugad - 5 months ago 37
Swift Question

Shooting bullets from SKSpriteNode

I try to build 2D - top down game, and I have player (SKSpriteNode) he can move and rotate, and I want to shoot two bullets from him.
I use this code to shoot:

func setBullet(player: Player, bullet: Int)
{
let weaponPosition = scene!.convertPoint(player.weapon.position, fromNode: player)
var xPos, yPos: CGFloat!

let sinus = sin(player.zRotation)
let cosinus = cos(player.zRotation)

if bullet == 1
{
xPos = converted.x - sinus * player.size.height / 2
yPos = converted.y + cosinus * player.size.height / 2
}
else if bullet == 2
{
xPos = weaponPosition.x - sinus * player.size.height / 2
yPos = weaponPosition.y + cosinus * player.size.height / 2
}

position = CGPoint(x: xPos, y: yPos)
physicsBody!.applyImpulse(CGVector(dx: -sinus * normalSpeed, dy: cosinus * normalSpeed))
}


But, i do not know how to correctly set the position...
I try to make something like thisthis
(Green dots - this is a bullets). Can anyone help me please!

Answer

Shooting multiple bullets in the same direction is fairly straightforward. The key is to determine the bullets' initial positions and direction vectors when the character is rotated.

You can calculate a bullet's initial position within the scene by

let point = node.convertPoint(weapon.position, toNode: self)

where node is the character, weapon.position is non-rotated position of a gun, and self is the scene.

Typically, a bullet moves to the right, CGVector(dx:1, dy:0), or up, CGVector (dx:0, dy:1), when the character is not rotated. You can calculate the direction of the impulse to apply to the bullet's physics body by rotating the vector by the character's zRotation with

func rotate(vector:CGVector, angle:CGFloat) -> CGVector {
    let rotatedX = vector.dx * cos(angle) - vector.dy * sin(angle)
    let rotatedY = vector.dx * sin(angle) + vector.dy * cos(angle)
    return CGVector(dx: rotatedX, dy: rotatedY)
}

Here's an example of how to shoot two bullets from a rotated character:

struct Weapon {
    var position:CGPoint
}

class GameScene: SKScene {
    let sprite = SKSpriteNode(imageNamed:"Spaceship")
    let dualGuns = [Weapon(position: CGPoint(x: -15, y: 15)), Weapon(position: CGPoint(x: 15, y: 15))]
    let singleGun = [Weapon(position: CGPoint(x: 0, y: 15))]
    let numGuns = 1
    // If your character faces up where zRotation == 0, offset by pi
    let rotationOffset = CGFloat(M_PI_2)
    override func didMoveToView(view: SKView) {
        scaleMode = .ResizeFill
        sprite.position = view.center
        sprite.size = CGSizeMake(25, 25)
        self.addChild(sprite)
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if let _ = touches.first {
            let action = SKAction.rotateByAngle(CGFloat(M_PI_4/2), duration:1)
            sprite.runAction(action) {
                [weak self] in
                if let scene = self {
                    switch (scene.numGuns) {
                    case 1:
                        for weapon in scene.singleGun {
                            scene.shoot(weapon: weapon, from: scene.sprite)
                        }
                    case 2:
                        for weapon in scene.dualGuns {
                            scene.shoot(weapon: weapon, from: scene.sprite)
                        }
                    default:
                        break
                    }
                }
            }
        }
    }

    func shoot(weapon weapon:Weapon, from node:SKNode) {
        // Convert the position from the character's coordinate system to scene coodinates
        let converted = node.convertPoint(weapon.position, toNode: self)

        // Determine the direction of the bullet based on the character's rotation
        let vector = rotate(CGVector(dx: 0.25, dy: 0), angle:node.zRotation+rotationOffset)

        // Create a bullet with a physics body
        let bullet = SKSpriteNode(color: SKColor.blueColor(), size: CGSizeMake(4,4))
        bullet.physicsBody = SKPhysicsBody(circleOfRadius: 2)
        bullet.physicsBody?.affectedByGravity = false
        bullet.position = CGPointMake(converted.x, converted.y)
        addChild(bullet)
        bullet.physicsBody?.applyImpulse(vector)
    }

    // Rotates a point (or vector) about the z-axis
    func rotate(vector:CGVector, angle:CGFloat) -> CGVector {
        let rotatedX = vector.dx * cos(angle) - vector.dy * sin(angle)
        let rotatedY = vector.dx * sin(angle) + vector.dy * cos(angle)
        return CGVector(dx: rotatedX, dy: rotatedY)
    }
}