2 Playing a Game
dxtr edited this page 2026-10-19 08:16:58 +02:00

Playing a Game

The system pyssel/play plays a saved scene as a game in your Lisp, as Pyssel's editor plays one: in an engine of its own, with its own render thread, GPU device and job pool, and a session of its own, while your REPL goes on. The game loads its code from an ASDF system, so put the arena's definitions of Saving Scenes, from defpackage to cheer, in arena.lisp, beside arena.asd:

(defsystem "arena"
  :depends-on ("pyssel/scene-2d")
  :components ((:file "arena")))

Then, with arena.scene saved as that page saves it:

(asdf:load-system :pyssel/play)
(asdf:load-system :arena)

(defvar *play* (pyssel/play:play :scene "arena.scene" :system :arena :title "Arena"))
;; Playing arena.scene in this Lisp.

The arena opens in a window of its own. In a project, (pyssel/play:play) plays its main scene, with its settings.

  • The game's objects are yours: play-tree is its scene tree, whose nodes you reach with call-in-tree or send-to-tree, and code you compile redefines the game's, as it plays.
  • Its threads' bindings: play's :bindings, as ((symbol value) ...), are more variables the game's threads bind, as the editor binds the hook its debugger takes their errors with; the play's own, its session and output streams, win over them.
  • Each play starts afresh: play loads the game's system again, so the files you changed are compiled, and gives the game play-session, a session of its own, which its scene is loaded in and its threads have. What it loads, and changes in its resources and its default theme, is its own, and the next play loads them anew.
  • Global variables are the one thing a play shares with you and the plays after it. When a play ends, play-changed-variables names those of the game's package, the one named as its system is, or of the :packages you give, whose values it changed, and the output says so. Keep a game's state in its nodes and resources.
  • Its output and errors: what the game writes goes to :output, by default where you called play. An error in a node's callback stops the node, with a warning there, and the game goes on; one that reaches the debugger, such as an error in the engine's own drawing, waits in SLY's, or for a game the editor plays, in its Debugger dock, on the game's render thread, which stops the game's frames and nothing else.
  • Stopping: close the window, have a node call (sc:quit), or (stop-play *play*). A game that does not stop within five seconds, being stuck in a loop of its own code or waiting in the debugger, makes stop-play signal play-not-responding, with the restarts wait-longer; break-into-play, which breaks into the game's render thread with the debugger, as break-into-engine does, where you see what it does and choose stop-engine; and abandon-play, which lets it go, its threads staying until your Lisp ends. It is never unwound from outside, since an interrupt may land in foreign code.