rrbox / ecs-swift

Entity Component System for swift
MIT License
3 stars 0 forks source link

Sparse set 専用 entity のための commands API #68

Closed rrbox closed 4 months ago

rrbox commented 4 months ago

sparse set の導入により、entity 生成方法が変わります。それまでは引数を取らないイニシャライザで簡単に生成できましたが、今後は world の entities から空きスロットに対応する entity を生成しなければなりません。

この変化に伴い、これまでの commands の entity spawn 処理および、entity commands の作成がうまく機能しなくなります。とくに、entity spawn 処理は world へのアクセスを要求するため、遅延実行されることになります。従って、続く entity commands は entity のデータをプロパティに格納することができないことになります。

そこで entity commands の再定義と spawn, despawn の処理内容の調整を行うべきとしました。

rrbox commented 4 months ago
class EntityCommand {
    func runCommand(in world: World, forEntity entity: Entity, entityRecord: EntityRecordRef)) {

    }
}

class EntityCommands {
    var commandQueue: [EntityCommand]
    func runCommand(in world: World, forEntity entity: Entity, entityRecord: EntityRecordRef)) {
        for command in self.commandQueue {
            command.run(in: world, forEntity: entity, entityRecord: entityRecord)
        }
    }
}

class SpawnCommand: Command {
    let entityCommands: EntityCommands

    func pushCommand(_ command: EntityCommand) {
        self.commandQueue.append(command)
    }

    func id() -> Entity {
        // ???
        // この関数を実装するなら、やはり即時的に entity を生成すべきか?
    }

    func runCommand(in world: World) {
        let (entity, record) = world.spawn()
        self.entityCommands.run(in: world, forEntity: entity, entityRecord: record)
    }
}
rrbox commented 4 months ago
  1. フレームスタート
  2. あるタイミングで spawn メソッド実行
  3. entity が生成される(entity generator を使用, インクリメント)
  4. entity record ref が作成される
  5. entity spawn command がどこかに追加される
  6. 続く entity command が command queue に追加される
  7. フレーム終了
  8. entity spawn / despawn command が実行される(world に entity 追加)
  9. command queue が実行される

  1. フレームスタート
  2. あるタイミングで despawn メソッド実行
  3. 削除する entity が指定される(entity generator に stack)
  4. entity despawn command がどこかに追加される
  5. フレーム終了
  6. entity spawn / despawn command が実行される(world から entity 削除)
  7. command queue が実行される
rrbox commented 4 months ago

entity 生成のルール(slot のインクリメント)の責任を Commands に負担させる場合の spawn メソッドです。

class Commands {
    var generator = EntityGenerator()

    func spawn() -> EntityCommands {
        let entity = self.generator.generate()
        let record = EntityRecordRef()

        record.map.body[ObjectIdentifier(Entity.self)] = ImmutableRef(value: entity)

        self.generator.pop()

        self.__entityQueue__.append(SpawnCommand(id: entity, entityRecord: record))
        return EntityCommands(entity: entity, commands: self)
    }
}

class SpawnCommand {
    let id: Entity
    let entityRecord: EntityRecordRef

    override func runCommand(in world: World) {
        world.push(entity: self.entity, entityRecord: self.entityRecord)
    }
}

extension World {
    func push(entity: Entity, entityRecord: EntityRecordRef) {
        if entity.generation == 0 {
            self.entities.allocate() // entities: SparseSet<EntityRecordRef>
        }

        self.entities.insert(entity: entity, entityRecord: entityRecord)
        self.worldStorage
            .chunkStorage
            .push(entity: entity, entityRecord: entityRecord)

        self.worldStorage
            .eventStorage
            .commandsEventWriter(eventOfType: DidSpawnEvent.self)!
            .send(value: DidSpawnEvent(spawnedEntity: entity))
    }
}
rrbox commented 4 months ago
rrbox commented 4 months ago

70 #63 にて達成