[swift-users] Checking/getting custom objects from a collection

Adriano Ferreira adriano.ferreira at me.com
Fri Apr 8 09:12:19 CDT 2016


Milos,

Thanks for taking a look at it, I appreciate you suggestion.

It’s protocol-oriented, quite different from the idea I was trying to emulate — the one provided by GameplayKit.

Well, I tried it and it works great.


Now, would you implement those methods differently?

mutating func add<T: Component>(component: T) {
    self.components[T.name] = component
}

mutating func remove<T: Component>(_: T.Type) {
    self.components[T.name] = nil
}

Also, since the key to the components dictionary is the name, adding a component of the same type will replace the exiting one.

How would you change that so it would be possible to add some components more than once, as Jens mentioned?

Best,

—A

> On Apr 8, 2016, at 7:12 AM, Milos Rankovic <milos at milos-and-slavica.net> wrote:
> 
> 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 <mailto: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 <https://lists.swift.org/mailman/listinfo/swift-users>
>> 
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org <mailto: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/4083ca85/attachment-0001.html>


More information about the swift-users mailing list