Hi Milos, Thanks for getting back to me this quickly.
Well, this part specifically was more of a curiosity based on Jens’ comment: “If Limb is a Component, then a Spider entity needs eight of them…” I also confess I’m unsure about this… so please don’t bother then. Looking forward to hearing your thoughts on the functions though. Cheers, — A > On Apr 8, 2016, at 10:23 AM, Milos Rankovic <mi...@milos-and-slavica.net> > wrote: > > Hi Adriano, > > I’m glad if you are finding this useful. I’ll get back to you on `add` and > `remove`, but just let me confirm with you: You actually want to allow > multiple, say, `Health` components to be added to your `Character`? Most of > the complication in my suggested code comes from trying to prevent that! > Things would be simpler if this is not your requirement. I just need to > double check that with you, since I can not think of a reason that would be a > good thing. I expressly sketched out the implementation so that you can keep > `Health` and such immutable, so that you can update the character’s state > simply by `add`ing (and therefore replacing) the existing `Health` value. > > milos > > >> On 8 Apr 2016, at 15:12, Adriano Ferreira <adriano.ferre...@me.com >> <mailto:adriano.ferre...@me.com>> wrote: >> >> 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 <mi...@milos-and-slavica.net >>> <mailto:mi...@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@swift.org <mailto:swift-users@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@swift.org <mailto:swift-users@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@swift.org <mailto:swift-users@swift.org> >>>>> https://lists.swift.org/mailman/listinfo/swift-users >>>>> <https://lists.swift.org/mailman/listinfo/swift-users> >>>> >>>> _______________________________________________ >>>> swift-users mailing list >>>> swift-users@swift.org <mailto:swift-users@swift.org> >>>> https://lists.swift.org/mailman/listinfo/swift-users >>>> <https://lists.swift.org/mailman/listinfo/swift-users> >>> >> >
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users