From a6b767a9434a026165c43ecf0828ee0cf13b3125 Mon Sep 17 00:00:00 2001 From: BirDt_ Date: Sat, 28 Mar 2026 17:29:24 +0800 Subject: [PATCH 1/7] Rename core interface functions --- README.org | 4 ++-- engine/core.scm | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/README.org b/README.org index e25f77c..762587b 100644 --- a/README.org +++ b/README.org @@ -52,8 +52,8 @@ If the game attempts to load a resource which has already been loaded, it will u * Structure & Modules The ~engine~ folder contains core engine code, organised across the following modules: -- ~(engine core)~ which contains core functionality including starting the window and game loop, functions for adding/removing systems, entities, and event buses. - - This module also re-exports the bindings of SRFI-99, as we require those records for ~component-sets~ and other places. +- ~(engine core)~ which contains core functionality including starting the window and game loop, and functions for adding/removing systems, entities, and event buses to/from the game state. +- ~(engine components)~ which contains methods for creating and accessing components. - ~(engine systems)~ which contains functions for creating new systems. - ~(engine events)~ which contains functions for creating and interacting with event buses. - ~(engine resources)~ which contains functions for loading and using resources. diff --git a/engine/core.scm b/engine/core.scm index 1734423..a2afdbb 100644 --- a/engine/core.scm +++ b/engine/core.scm @@ -1,4 +1,4 @@ -(module (engine core) * +(module (engine core) (add-entity add-named-entity remove-entity) (import scheme (chicken base) ;; raylib @@ -87,18 +87,17 @@ 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) +;; Create an entity in the world and return it's ID +(define (add-named-entity id . components) (queue-add-entity id components) id) ;; Shortcut for anonymous instancing -(define (add-instance . components) - (apply add-instance-named (gensym) components)) +(define (add-entity . components) + (apply add-named-entity (gensym) components)) -;; Remove an instance from the world -(define (remove-instance id) +;; Remove an entity from the world +(define (remove-entity id) (queue-del-entity id) id) - ) From 9be97de885a20c57ef6f7cdb14cd93f7c49aae9d Mon Sep 17 00:00:00 2001 From: BirDt_ Date: Sat, 28 Mar 2026 17:59:46 +0800 Subject: [PATCH 2/7] Type checking for interface functions --- engine/core.scm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/engine/core.scm b/engine/core.scm index a2afdbb..b9202ce 100644 --- a/engine/core.scm +++ b/engine/core.scm @@ -1,7 +1,9 @@ -(module (engine core) (add-entity add-named-entity remove-entity) +(module (engine core) +(add-entity add-named-entity remove-entity) (import scheme (chicken base) ;; raylib + (srfi 1) (srfi 69) (srfi 99) (srfi 113) @@ -89,6 +91,8 @@ ;; Create an entity in the world and return it's ID (define (add-named-entity id . components) + (assert (symbol? id)) + (assert (every record? components)) (queue-add-entity id components) id) @@ -98,6 +102,7 @@ ;; Remove an entity from the world (define (remove-entity id) + (assert (symbol? id)) (queue-del-entity id) id) ) From 04a6555cbd460b5227843ba5d6d967614be21057 Mon Sep 17 00:00:00 2001 From: BirDt_ Date: Sat, 28 Mar 2026 18:52:48 +0800 Subject: [PATCH 3/7] System addition/removal. I'm not doing topo sort (today) --- README.org | 6 +-- engine/core.scm | 119 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 6 deletions(-) diff --git a/README.org b/README.org index 762587b..a882a4b 100644 --- a/README.org +++ b/README.org @@ -23,16 +23,14 @@ Components are SRFI-99 records which store data associated for a particular enti ** Systems Systems are functions which modify state and draw to the screen. -Systems are stored in the ~systems~ list as a record containing a name (symbol), rendering (a symbol), a priority (integer), dependencies (list of symbols), entity criteria (list of symbols), and the function itself. +Systems are stored in the ~systems~ list as a record containing a name (symbol), rendering (a symbol), a priority (integer), entity criteria (list of symbols), and the function itself. Each system specifies the components an entity (the entity criteria) must have for it to be processed by that system. The entities are then selected for the system from the ~component-sets~. Each system is applied to all entities which match its entity criteria. Systems have a priority which defaults to 0. Lower priority systems will be executed before higher priority systems. Systems within the same priority execute in order of addition to the ~systems~ list. -Systems can depend on other systems, which moves them to execute after the system specified. If a system defines a rendering symbol of 3D, it will be wrapped in ~with-mode-3d~. If a system defines a rendering symbol of 2D, it will be wrapped in ~with-mode-2d~. All systems run in render loop, wrapped in ~with-drawing~, and can draw non-2D and non-3D elements arbitrarily. In this way ~with-mode-3d~ and ~with-mode-2d~ can be avoided in system function bodies, and non-3D/2D systems can draw in screen space. The ~systems~ list is sorted on each addition and removal of a system. -Removal of a system which has dependent systems results in an error. -Addition of a system which creates a circular dependency loop results in an error. +Like entities, the addition of systems is queued for the beginning of each frame. This prevents the system list from being sorted multiple times per frame. Systems can access resources via free variables or by being formed as closures. Systems only ever take an entity (a component list) as input. diff --git a/engine/core.scm b/engine/core.scm index b9202ce..3176284 100644 --- a/engine/core.scm +++ b/engine/core.scm @@ -1,7 +1,7 @@ -(module (engine core) -(add-entity add-named-entity remove-entity) +(module (engine core) () (import scheme (chicken base) + (chicken module) ;; raylib (srfi 1) (srfi 69) @@ -89,6 +89,14 @@ del-entity-queue) (set! del-entity-queue '())) +;; Resolve all queued entity changes +(define (resolve-entity-queue) + (remove-queued-entities) + (add-queued-entities)) + +;; Entity creation/removal interface +(export add-named-entity add-entity remove-entity) + ;; Create an entity in the world and return it's ID (define (add-named-entity id . components) (assert (symbol? id)) @@ -105,4 +113,111 @@ (assert (symbol? id)) (queue-del-entity id) id) + +;; System record interface +(export make-system system? system-name system-rendering + system-priority set-system-priority! system-criteria + set-system-criteria! system-process set-system-process!) + +;; The system record +(define-record-type + (internal-make-system name rendering priority criteria process) + system? + (name system-name) + (rendering system-rendering) + (priority system-priority internal-set-system-priority!) + (criteria system-criteria internal-set-system-criteria!) + (process system-process internal-set-system-process!)) + +;; Type-checked system constructor wrapper +(define (make-system name rendering priority criteria process) + (assert (symbol? name)) + (assert (and (symbol? rendering) (member rendering '(3d 2d screen none)))) + (assert (integer? priority)) + (assert (every symbol? criteria)) + (assert (procedure? process)) + (internal-make-system name rendering priority criteria process)) + +;; Type-checked system priority mutator +(define (set-system-priority! system priority) + (assert (system? system)) + (assert (integer? priority)) + (internal-set-system-priority! system priority)) + +;; Type-checked system criteria mutator +(define (set-system-criteria! system criteria) + (assert (system? system)) + (assert (every symbol? criteria)) + (internal-set-system-criteria! system criteria)) + +;; Type-checked system process mutator +(define (set-system-process! system process) + (assert (system? system)) + (assert (procedure? process)) + (internal-set-system-process! system process)) + +;; The systems list +(define systems '()) + +;; Immediately add a new system +(define (add-system-now system) + (set! systems + (append systems (list system)))) + +;; Immediately remove a new system +(define (remove-system-now name) + (set! systems + (delete name systems + (lambda (n el) + (eqv? n (system-name el)))))) + +;; System addition/deletion queues +(define add-system-queue '()) +(define del-system-queue '()) + +;; Add a system to the incoming queue +(define (queue-add-system system) + (set! add-system-queue + (append add-system-queue (list system)))) + +;; Add a system to the deletion queue +(define (queue-del-system name) + (set! del-system-queue + (append del-system-queue (list name)))) + +;; Resolve all new system creations +(define (add-queued-systems) + (for-each + (lambda (system) + (add-system-now system)) + add-system-queue) + (set! add-system-queue '())) + +;; Resolve all queued system deletions +(define (remove-queued-systems) + (for-each + (lambda (system-name) + (remove-system-now system-name)) + del-system-queue) + (set! del-system-queue '())) + +;; Resolve all queued system changes +(define (resolve-system-queue) + (remove-queued-systems) + (add-queued-systems)) + +;; System creation/removal interface +(export add-system remove-system) + +;; Add a system to the state processing and return its name +(define (add-system system) + (assert (system? system)) + (queue-add-system system) + (system-name system)) + +;; Remove a system from process +(define (remove-system name) + (assert (symbol? name)) + (queue-del-system name) + name) ) From f1d63420896949635571c91c46f7ca9bdeeadd7d Mon Sep 17 00:00:00 2001 From: BirDt_ Date: Sat, 28 Mar 2026 19:14:54 +0800 Subject: [PATCH 4/7] Event buses (as hash tables for speed) --- README.org | 4 +-- engine/core.scm | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/README.org b/README.org index a882a4b..97431fa 100644 --- a/README.org +++ b/README.org @@ -35,13 +35,13 @@ Like entities, the addition of systems is queued for the beginning of each frame Systems can access resources via free variables or by being formed as closures. Systems only ever take an entity (a component list) as input. ** Event Buses -An event bus is an association list of symbols and records. They allow for delegating changes sent from other objects. +An event bus is a hash table of symbols and records. They allow for delegating changes sent from other objects. The event record can contain any arbitrary data. The symbol the record is associated by is unique within the association list. Event records stay in the bus until removed by another system. Systems can push and pull events to and from the bus. Systems can choose to either pop the event off the bus (removing it from further processing) or just peek at the event. The symbol an event is associated by is essentially an "action". The event bus can have multiple events of the same type (for example, multiple different key presses can occur in a frame). Only one event of each name (for example, only 1 event can be called "jump", which might correspond to a space key press) is allowed in the bus at any one time. -Custom event buses can be created and stored in the ~event-buses~ association list. System can query a particular event bus within that list for a particular event. +Custom event buses can be created and stored in the ~event-buses~ hash table. Systems can query a particular event bus within that list for a particular event. ** Resources When a resource, such as a font or texture, is loaded from the filesystem, the pointer is stored in an SRFI-69 hash table ~resources~ keyed by the path. diff --git a/engine/core.scm b/engine/core.scm index 3176284..3d5db14 100644 --- a/engine/core.scm +++ b/engine/core.scm @@ -220,4 +220,73 @@ (assert (symbol? name)) (queue-del-system name) name) + +;; System execution +;; TODO: Implement + +;; Event buses hash table +(define event-buses (make-hash-table)) + +;; Event bus interface +(export register-event-bus remove-event-bus fetch-event-bus + push-event peek-event pop-event) + +;; Register a new event bus +(define (register-event-bus name) + (assert (symbol? name)) + (if (hash-table-exists? event-buses name) + #f + (begin + (hash-table-set! event-buses name (make-hash-table)) + name))) + +;; Remove an event bus +(define (remove-event-bus name) + (assert (symbol? name)) + (if (hash-table-exists? event-buses name) + (begin + (hash-table-delete! event-buses name) + name) + #f)) + +;; Fetch an event bus by name, or #f if it doesn't exist +(define (fetch-event-bus name) + (assert (symbol? name)) + (if (hash-table-exists? event-buses name) + (hash-table-ref event-buses name) + #f)) + +;; Push an event to the specified bus, return #f on failure (if the bus doesn't exist +(define (push-event bus action event) + (assert (symbol? bus)) + (assert (symbol? action)) + (assert (record? event)) + (let ((event-bus (fetch-event-bus bus))) + (if event-bus + (begin + (hash-table-set! event-bus action event) + #t) + #f))) + +;; Retrieve an event from the event bus, if it exists. Return false if it doesn't +(define (peek-event bus action) + (assert (symbol? bus)) + (assert (symbol? action)) + (let ((event-bus (fetch-event-bus bus))) + (if (and event-bus + (hash-table-exists? event-bus action)) + (hash-table-ref event-bus action) + #f))) + +;; Retrieve an event from the event bus, if it exists, then delete it. Return false if it doesn't exist. +(define (pop-event bus action) + (assert (symbol? bus)) + (assert (symbol? action)) + (let ((event-bus (fetch-event-bus bus))) + (if (and event-bus + (hash-table-exists? event-bus action)) + (let ((event (hash-table-ref event-bus action))) + (hash-table-delete! event-bus action) + event) + #f))) ) From 71c6ba3ab77c549a1df0d83bd46bc28d56df833c Mon Sep 17 00:00:00 2001 From: BirDt_ Date: Sat, 28 Mar 2026 19:20:00 +0800 Subject: [PATCH 5/7] Frame loop and we need raylib now --- engine/core.scm | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/engine/core.scm b/engine/core.scm index 3d5db14..0e68ebb 100644 --- a/engine/core.scm +++ b/engine/core.scm @@ -2,7 +2,7 @@ (import scheme (chicken base) (chicken module) - ;; raylib + raylib (srfi 1) (srfi 69) (srfi 99) @@ -221,8 +221,16 @@ (queue-del-system name) name) -;; System execution +;; Execute a single system ;; TODO: Implement +(define (execute-system system) + (assert (system? system)) + #t) + +(define (execute-systems) + (for-each + execute-system + systems)) ;; Event buses hash table (define event-buses (make-hash-table)) @@ -289,4 +297,9 @@ (hash-table-delete! event-bus action) event) #f))) + +(define (frame-loop) + (resolve-entity-queue) + (resolve-system-queue) + (execute-systems)) ) From 69f1f584eae99ca7adf08e9bdf4651ab1815d8ad Mon Sep 17 00:00:00 2001 From: BirDt_ Date: Sat, 28 Mar 2026 19:22:11 +0800 Subject: [PATCH 6/7] Move queue resolution outside of drawing --- engine/core.scm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/engine/core.scm b/engine/core.scm index 0e68ebb..49f6ab1 100644 --- a/engine/core.scm +++ b/engine/core.scm @@ -298,8 +298,12 @@ event) #f))) -(define (frame-loop) +;; Frame generation interface +(export make-next-frame) +;; Generate the next frame, for use in the main game loop +(define (make-next-frame) (resolve-entity-queue) (resolve-system-queue) - (execute-systems)) + (with-drawing + (execute-systems))) ) From 700b7a9cdaeff4f1dc89ff92660410715bb4d7be Mon Sep 17 00:00:00 2001 From: BirDt_ Date: Sat, 28 Mar 2026 19:29:47 +0800 Subject: [PATCH 7/7] Sort systems by priority --- engine/core.scm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/engine/core.scm b/engine/core.scm index 49f6ab1..a6af628 100644 --- a/engine/core.scm +++ b/engine/core.scm @@ -2,6 +2,7 @@ (import scheme (chicken base) (chicken module) + (chicken sort) raylib (srfi 1) (srfi 69) @@ -171,6 +172,13 @@ (lambda (n el) (eqv? n (system-name el)))))) +;; Sort the systems list by priority +(define (sort-systems) + (sort! systems + (lambda (x y) + (< (system-priority x) + (system-priority y))))) + ;; System addition/deletion queues (define add-system-queue '()) (define del-system-queue '()) @@ -204,7 +212,8 @@ ;; Resolve all queued system changes (define (resolve-system-queue) (remove-queued-systems) - (add-queued-systems)) + (add-queued-systems) + (sort-systems)) ;; System creation/removal interface (export add-system remove-system)