diff --git a/README.org b/README.org index f665aa2..e25f77c 100644 --- a/README.org +++ b/README.org @@ -8,8 +8,8 @@ Imugi is an ECS engine. ** Entities Entities are game objects stored in an SRFI-69 hash table. A hash table is used for O(1) lookup. Entity keys within the hash table are symbols, either set intentionally or automatically generated via gensym. -Entities are identified by their hash, and are each a list of components. -Entities are queued for addition and removal to/form the hash table ~world~. +Entities are identified by their key, and are each a list of components. +Entities are queued for addition and removal to/from the hash table ~world~. Entity removal and addition is performed at the beginning of each frame, with removal occuring first. There exists a hash map of SRFI-113 sets, ~component-sets~. diff --git a/engine/core.scm b/engine/core.scm new file mode 100644 index 0000000..2ba8620 --- /dev/null +++ b/engine/core.scm @@ -0,0 +1,104 @@ +(module (engine core) * +(import scheme + (chicken base) + raylib + (srfi 69) + (srfi 99) + (srfi 113) + (srfi 128)) + +;; The world hash table +(define world (make-hash-table)) +;; The component-sets hash table +(define component-sets (make-hash-table)) + +;; Insert an entity into component-sets, either creating +;; a new set or updating an existing one for the component +;; type provided. +(define (classify-entity-by id component) + (let ((component-type (rtd-name (record-rtd component)))) + (if (hash-table-exists? component-sets component-type) + (let ((component-set (hash-table-ref component-sets component-type))) + ;; TODO: this could be nicer with set-adjoin! but I'm not sure if hash-table-ref is locative + (hash-table-set! component-sets + component-type + (set-adjoin component-set + id))) + (hash-table-set! component-sets + component-type + (set (make-eq-comparator) id))))) + +;; Create an entity in the world immediately, +;; and add it to the requisite component-sets +(define (create-entity id components) + (hash-table-set! world id components) + (for-each + (lambda (component) + (classify-entity-by id component)) + components)) + +;; Remove a single matching item from a set +(define (set-remove! set element) + (set-search! set element + (lambda (insert ignore) + (ignore #f)) + (lambda (old update remove) + (remove old)))) + +;; Remove an entity from the world immediately, +;; as well as from all component sets. +(define (remove-entity id) + (hash-table-delete! world id) + (for-each + (lambda (set) + (set-remove! set id)) + (hash-table-values component-sets))) + +;; Queues for entity creation and deletion +(define add-entity-queue '()) +(define del-entity-queue '()) + +;; Add an entity to the incoming queue +;; TODO: append! doesn't work here and IDK why +(define (queue-add-entity id components-lst) + (set! add-entity-queue + (append add-entity-queue (list (cons id components-lst))))) + +;; Add an entity to the deletion queue +(define (queue-del-entity id) + (set! del-entity-queue + (append del-entity-queue (list id)))) + +;; Resolve all new entity creations +(define (add-queued-entities) + (for-each + (lambda (entity) + (let ((id (car entity)) + (components (cdr entity))) + (create-entity id components))) + add-entity-queue) + (set! add-entity-queue '())) + +;; Resolve all queued entity deletions +(define (remove-queued-entities) + (for-each + (lambda (id) + (remove-entity id)) + del-entity-queue) + (set! del-entity-queue '())) + +;; Create an instance of an entity in the world and return it's ID +(define (add-instance-named id . components) + (queue-add-entity id components) + id) + +;; Shortcut for anonymous instancing +(define (add-instance . components) + (apply add-instance-named (gensym) components)) + +;; Remove an instance from the world +(define (remove-instance id) + (queue-del-entity id) + id) + +)