I am trying to design a simple game engine for fun and educational purposes. I have a Game
protocol that represents my game and Entity
protocol that represents an entity (like the player or opponent). Finally, I have an EntityComponent
protocol which implementations update an Entity
. It looks like this in Swift:
protocol Game {
var entities: [Entity] { get }
}
protocol Entity {
var components: [EntityComponent] { get }
}
protocol EntityComponent {
func update(_ entity: Entity, deltaTime seconds: TimeInterval)
}
I want my entity components to be generalized using entity they update. In Swift, I can use associatedtype
:
protocol EntityComponent {
associatedtype EntityType: Entity
func update(_ entity: EntityType, deltaTime seconds: TimeInterval)
}
However, this would produce a compilation error for Entity
protocol:
protocol Entity {
var components: [EntityComponent] { get } // ERROR!
}
Protocol 'EntityComponent' can only be used as a generic constraint because it has Self or associated type requirements
This issue could be solved by defining type-erasure for EntityComponent
protocol, and updating Entity
like this:
protocol Entity {
var components: [AnyEntityComponent<Self>] { get }
}
final class AnyEntityComponent<EntityType: Entity>: EntityComponent {
init<T: EntityComponent>(_ component: T) where T.EntityType == EntityType {
self.update = component.update
}
func update(_ entity: EntityType, deltaTime seconds: TimeInterval) {
update(entity, seconds)
}
private let update: (EntityType, TimeInterval) -> Void
}
Unfortunately, that change in the Entity
protocol produces another issue. This time in Game
protocol:
protocol Game {
var entities: [Entity] { get } // ERROR!
}
Protocol 'Entity' can only be used as a generic constraint because it has Self or associated type requirements
I am not sure how to fix this one, as I can't do it by defining type-erasure (as in case of EntityComponent
).
I will appreciate any hints and ideas!