[swift-users] Checking/getting custom objects from a collection
Milos Rankovic
milos at milos-and-slavica.net
Fri Apr 8 06:12:06 CDT 2016
A type-uniquing alternative (see my previous message):
// Swift 2.2
// Entity-Component System (sketch):
protocol Component {
static var name: String { get } // not necessary (see comments below)
}
extension Component {
// can be overridden with `let` by conforming types
static var name: String { return String(self.dynamicType) }
}
protocol Entity {
static func with(_: Component...) -> Self
var components: [String:Component] { get set }
init()
func component<T: Component>(_: T.Type) -> T?
}
extension Entity {
static func with(components: Component...) -> Self {
var d: [String:Component] = [:]
for c in components { d[c.dynamicType.name/* String(c.dynamicType) */] = c }
var entity = self.init()
entity.components = d
return entity
}
func component<T: Component>(_: T.Type) -> T? {
return self.components[T.name/* String(T) */] as? T
}
// TODO: mutating func add<T: Component>(_: T)
// TODO: mutating func remove<T: Component>(_: T.Type)
}
// game:
struct Character: Entity {
var components: [String:Component] = [:]
}
struct Health: Component {
var percent = 100.0
var dead: Bool { return percent <= 0 }
}
struct Attack: Component {
var range = 0, damage = 0
}
// use:
let health = Health()
let attack = Attack()
let character = Character.with(health, attack)
character.component(Health)?.percent // 100
milos
> On 8 Apr 2016, at 11:05, Milos Rankovic via swift-users <swift-users at swift.org> wrote:
>
> This is just a sketch. There may be issues down the line (I’ve indicated some with `TODO`s), but it works and you can try it in the playground:
>
> // Swift 2.2
>
> // utility:
> extension Array {
> func first <T> (_: T.Type) -> T? {
> for e in self where e is T { return e as? T }
> return nil
> }
> }
>
> // Entity-Component System (sketch):
> protocol Component { }
>
> protocol Entity {
> static func with(_: Component...) -> Self
> // TODO: make get only
> // also should be a set-by-type really, but that would
> // force `Component` to be a class (which may be worth it)
> var components: [Component] { get set }
> init()
> func component<T: Component>(_: T.Type) -> T?
> }
>
> extension Entity {
> static func with(components: Component...) -> Self {
> var entity = self.init()
> // TODO: enforce uniquely typed elements
> entity.components = components
> return entity
> }
> func component<T: Component>(_: T.Type) -> T? {
> return self.components.first(T)
> }
> }
>
> // game:
> struct Character: Entity {
> // TODO: make private
> var components: [Component] = []
> }
>
> struct Health: Component {
> var percent = 100.0
> var dead = false
> }
>
> struct Attack: Component {
> var range = 0, damage = 0
> }
>
> // use:
> var health = Health()
> var attack = Attack()
>
> var character = Character.with(health, attack)
>
> character.component(Health)?.percent // 100
>
> Hope this helps,
>
> milos
>
>> On 8 Apr 2016, at 00:47, Adriano Ferreira via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
>>
>> Hi everyone!
>>
>> I’m experimenting with Entity-Component Systems <https://en.wikipedia.org/wiki/Entity_component_system> and I’d appreciate if you could help me working on how to check/get custom objects from a collection.
>>
>> The idea is to verify if an entity contains a particular component and, if so, retrieve it.
>>
>> Here’s the API I’d like work on:
>>
>>
>> // Entity Library
>> class Character: Entity {}
>>
>> // Component Library
>> class HealthComponent: Component {
>> var health = 100.0
>> var isDead = false
>> }
>>
>> class AttackComponent: Component {
>> var range = 0
>> var damage = 0
>> }
>>
>> // Usage
>> var healthComponent = HealthComponent()
>> var attackComponent = AttackComponent()
>>
>> var components: [ComponentType] = [healthComponent, attackComponent]
>> var char = Character(components: components)
>>
>> let hc = char.get(component: HealthComponent)
>> let ac = char.get(component: AttackComponent)
>>
>>
>> So, what are your thoughts on the TODOs below?
>>
>> —
>>
>> import Foundation
>>
>> protocol ComponentType {
>> var entity: EntityType? { get }
>> }
>>
>> protocol EntityType {
>> var components: [ComponentType] { get }
>> func get<T: ComponentType>(component c: T.Type) -> T?
>> func add(component c: ComponentType)
>> func remove(component c: ComponentType)
>> }
>>
>> class Component: ComponentType {
>> var entity: EntityType?
>> }
>>
>> class Entity: EntityType {
>> var components = [ComponentType]()
>>
>> init(components: [ComponentType]) {
>> for component in components {
>> self.add(component: component)
>> }
>> }
>>
>> func get<T: ComponentType>(component c: T.Type) -> T? {
>> // TODO: - not sure how to work the types here
>> // if `self` contains component of given type, return it
>> // otherwise, return nil
>> }
>>
>> func add(component c: ComponentType) {
>> // TODO: - depends on the `get` function
>> // if `self` already contains component, just return
>> // otherwise, self.components += [component]
>> }
>>
>> func remove(component c: ComponentType) {
>> // TODO: - also depends on the `get` function
>> // if `self` contains component, remove it
>> // otherwise, just return
>> }
>> }
>>
>>
>>
>> Best,
>>
>> —A
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org <mailto:swift-users at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-users
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160408/32157049/attachment.html>
More information about the swift-users
mailing list