I am trying to make a simple game: Space ship on the bottom of the screen shooting asteroids "falling" from the top of the screen.
I am learning ECS and GameplayKit, and have been trying to turn shields into a component. I've heavily relied on Apple's DemoBots sample app, and have lifted the PhysicsComponent
, ColliderType
, and ContactNotifiableType
from the sample code.
A shield needs to render the assets assoicated with it (one for full shields and one for half shields), a different physics body from the ship because it's radius is noticeably larger than the ship, and to keep track of it's state. To do this I wrote:
final class ShieldComponent: GKComponent {
enum ShieldLevel: Int {
case full = 0, half, none
}
var currentShieldLevel: ShieldLevel = .full {
didSet {
switch currentShieldLevel {
case .full:
node.isHidden = false
node.texture = SKTexture(image: #imageLiteral(resourceName: "shield"))
case .half:
node.isHidden = false
node.texture = SKTexture(image: #imageLiteral(resourceName: "damagedShield"))
case .none:
node.isHidden = true
}
}
}
let node: SKSpriteNode
override init() {
node = SKSpriteNode(imageNamed: "shield")
super.init()
node.physicsBody = {
let physicsBody = SKPhysicsBody(circleOfRadius: node.frame.size.width / 2)
physicsBody.pinned = true
physicsBody.allowsRotation = false
physicsBody.affectedByGravity = false
ColliderType.definedCollisions[.shield] = [
.obstacle,
.powerUp
]
physicsBody.categoryBitMask = ColliderType.shield.rawValue
physicsBody.contactTestBitMask = ColliderType.obstacle.rawValue
physicsBody.collisionBitMask = ColliderType.obstacle.rawValue
return physicsBody
}()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func loseShields() {
if let newShieldLevel = ShieldLevel(rawValue: self.currentShieldLevel.rawValue + 1) {
self.currentShieldLevel = newShieldLevel
}
}
func restoreShields() {
self.currentShieldLevel = .full
}
}
And in my Ship
initializer I do this:
let shieldComponent = ShieldComponent()
renderComponent.node.addChild(shieldComponent.node)
It would great if I could reuse the RenderComponent
, and PhysicsComponent
from DemoBots have I have with my ship and asteroid GKEntity
subclasses, but components cannot have components. I had made ShieldComponent
a ContactNotifiableType
, but because the shield node does not actually belong to the ship entity.
I know I'm clearly coming at this wrong, and I'm at a loss of how to correct this. I'm hoping to get an example of how to make a shield component.