Search code examples
swiftxcodesprite-kitentity-component-system

Entity-Component in Swift


I am trying to build a simple iOS game using entity-component architecture similar to what is described here.

What I would like to achieve in my game is when a user touches the screen, detect where the touch occurred and move all entities of one type towards a specific direction (direction depends on where the user touched, right of screen = up, left of screen = down).

So far, the game is really simple and I am only getting started, but I am stuck in this simple functionality:

My issue is that an SKAction is supposed to run on all entities of a type, but happens at all.

Before I redesigned my game to an ECS approach, this worked fine.

Here is the GKEntity subclass that I declared in Lines.swift:

class Lines: GKEntity {

    override init() {
        super.init()
        let LineSprite = SpriteComponent(color: UIColor.white, size: CGSize(width: 10.0, height: 300))
        addComponent(LineSprite)

        // Set physics body
        if let sprite = component(ofType: SpriteComponent.self)?.node {

            sprite.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: sprite.size.width, height: sprite.size.height))
            sprite.physicsBody?.isDynamic = false
            sprite.physicsBody?.restitution = 1.0
            sprite.physicsBody?.friction = 0.0
            sprite.physicsBody?.linearDamping = 0.0
            sprite.physicsBody?.angularDamping = 0.0
            sprite.physicsBody?.mass = 0.00
            sprite.physicsBody?.affectedByGravity = false
            sprite.physicsBody?.usesPreciseCollisionDetection = true
            sprite.physicsBody?.categoryBitMask = 0b1
            sprite.zPosition = 10
        } 
    }   
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

In TouchesBegan I am calling the function Move(XAxisPoint: t.location(in: self)) which is declared in GameScene and here is what Move() does:

   ///Determines direction of movement based on touch location, calls MoveUpOrDown for movement
    func move(XAxisPoint: CGPoint){
        let Direction: SKAction
        let Key: String

        if XAxisPoint.x >= 0 {
            Direction = SKAction.moveBy(x: 0, y: 3, duration: 0.01)
            Key = "MovingUp"
        } else {
            Direction = SKAction.moveBy(x: 0, y: -3, duration: 0.01)
            Key = "MovingDown"
        }
        moveUpOrDown(ActionDirection: Direction, ActionKey: Key)
    }

    ///Moves sprite on touch
    func moveUpOrDown(ActionDirection: SKAction, ActionKey: String) {
        let Line = Lines()
        if let sprite = Line.component(ofType: SpriteComponent.self)?.node {
            if sprite.action(forKey: ActionKey) == nil {
                stopMoving()
                let repeatAction = SKAction.repeatForever(ActionDirection)
                sprite.run(repeatAction, withKey: ActionKey)
            }
        }
    }

    ///Stops movement
    func stopMoving() {
        let Line = Lines()
        if let sprite = Line.component(ofType: SpriteComponent.self)?.node {
            sprite.removeAllActions()
        }
    }

I am guessing there is some issue with this line of code Line.component(ofType: SpriteComponent.self)?.node but the compiler doesn't throw any errors and I am not sure where my mistake is.

Any help/guidance will be greatly appreciated!


Solution

  • The issue is the following line in MoveUpOrDown and StopMoving

    let Line = Lines()
    

    It's creating a new Lines object then telling it to run an action. Since it's new, it hasn't been added to the scene so it isn't drawn or acted on.

    You should be getting an existing Lines object and modifying that instead of creating a new one.


    As a side note, the common convention for naming methods and variables is to use camelCase which means MoveUpOrDown should be moveUpOrDown. On the other hand SnakeCase is used For classes structs and protocols so SpriteComponent is current. That allows you to know at a glance whether your working with a type or a variable.