From 7c47d2b8f99be4a53f50e46015c15301ffa16ae1 Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Wed, 5 Feb 2020 23:17:34 +0100 Subject: Rename org posts --- site/posts/DiscoveringCommonLisp.org | 258 +++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 site/posts/DiscoveringCommonLisp.org (limited to 'site/posts/DiscoveringCommonLisp.org') diff --git a/site/posts/DiscoveringCommonLisp.org b/site/posts/DiscoveringCommonLisp.org new file mode 100644 index 0000000..a198c3d --- /dev/null +++ b/site/posts/DiscoveringCommonLisp.org @@ -0,0 +1,258 @@ +#+BEGIN_EXPORT html +

Discovering Common Lisp with trivial-gamekit

+ +June 17, 2018 +#+END_EXPORT + + +I always wanted to learn some Lisp dialect. +In the meantime, [[https://github.com/lkn-org/lykan][lykan]] —my Slayers Online clone— begins to take shape. +So, of course, my brain got an idea: /why not writing a client for lykan in some +Lisp dialect?/ +I asked on [[https://mastodon.social/@lthms/100135240390747697][Mastodon]] if there were good game engine for Lisp, and someone told me +about [[https://github.com/borodust/trivial-gamekit][trivial-gamekit]]. + +I have no idea if I will manage to implement a decent client using +trivial-gamekit, but why not trying? +This article is the first of a series about my experiments, discoveries and +difficulties. + +The code of my client is hosted on my server, using the pijul vcs. +If you have pijul installed, you can clone the repository: + +#+BEGIN_SRC bash +pijul clone "https://pijul.lthms.xyz/lkn/lysk" +#+END_SRC + +In addition, the complete project detailed in this article is available [[https://gist.github.com/lthms/9833f4851843119c966917775b4c4180][as a +gist]]. + +#+OPTIONS: toc:nil +#+TOC: headlines 2 + +* Common Lisp, Quicklisp and trivial-gamekit + +The trivial-gamekit [[https://borodust.github.io/projects/trivial-gamekit/][website]] lists several requirements. +Two are related to Lisp: + +1. Quicklisp +2. SBCL or CCL + +Quicklisp is an experimental package manager for Lisp project (it was easy to +guess, because there is a link to [[https://quicklisp.org/beta][quicklisp website]] in the trivial-gamekit +documentation). +As for SBCL and CCL, it turns out they are two Lisp implementations. +I had already installed [[https://www.archlinux.org/packages/?name=clisp][clisp]], and it took me quite some times to understand my +mistake. +Fortunately, [[https://www.archlinux.org/packages/?name=sbcl][sbcl]] is also packaged in ArchLinux. + +With a compatible Lisp implementation, installing Quicklisp as a user is +straightforward. +Following the website instructions is enough. +At the end of the process, you will have a new directory ~${HOME}/quicklisp~, +whose purpose is similar to the [[https://github.com/golang/go/wiki/SettingGOPATH][go workspace]]. + +Quicklisp is not a native feature of sbcl, and has to be loaded to be available. +To do it automatically, you have to create a file ~${HOME}/.sbclrc~, with the +following content: + +#+BEGIN_SRC +(load "~/quicklisp/setup") +#+END_SRC + +There is one final step to be able to use trivial-gamekit. + +#+BEGIN_SRC bash +sbcl --eval '(ql-dist:install-dist "http://bodge.borodust.org/dist/org.borodust.bodge.txt")' \ + --quit +#+END_SRC + +As for now[fn::June 2018], Quicklisp [[https://github.com/quicklisp/quicklisp-client/issues/167][does not support HTTPS]]. + +* Introducing Lysk + +** Packaging + +The first thing I search for when I learn a new language is how projects are +organized. +From this perspective, trivial-gamekit pointed me directly to Quicklisp + +Creating a new Quicklisp project is very simple, and this is a very good thing. +As I said, the ~${HOME}/quicklisp~ directory acts like the go workspace. +As far as I can tell, new Quicklisp projects have to be located inside +~${HOME}/quicklisp/local-projects~. +I am not particularly happy with it, but it is not really important. + +The current code name of my Lisp game client is lysk. + +#+BEGIN_SRC bash +mkdir ~/quicklisp/local-projects/lysk +#+END_SRC + +Quicklisp packages (systems?) are defined through ~asd~ files. +I have firstly created ~lysk.asd~ as follows: + +#+BEGIN_SRC common-lisp +(asdf:defsystem lysk + :description "Lykan Game Client" + :author "lthms" + :license "GPLv3" + :version "0.0.1" + :serial t + :depends-on (trivial-gamekit) + :components ((:file "package") + (:file "lysk"))) +#+END_SRC + +~:serial t~ means that the files detailed in the ~components~ field depends on +the previous ones. +That is, ~lysk.lisp~ depends on ~package.lisp~ in this case. +It is possible to manage files dependencies manually, with the following syntax: + +#+BEGIN_SRC common-lisp +(:file "seconds" :depends-on "first") +#+END_SRC + +I have declared only one dependency: trivial-gamekit. +That way, Quicklisp will load it for us. + +The first “true” Lisp file we define in our skeleton is ~package.lisp~. +Here is its content: + +#+BEGIN_SRC common-lisp +(defpackage :lysk + (:use :cl) + (:export run app)) +#+END_SRC + +Basically, this means we use two symbols, ~run~ and ~app~. + +** A Game Client + +The ~lysk.lisp~ file contains the program in itself. +My first goal was to obtain the following program: at startup, it shall creates +a new window in fullscreen, and exit when users release the left button of their +mouse. +It is worth mentioning that I had to report [[https://github.com/borodust/trivial-gamekit/issues/30][an issue to the trivial-gamekit +upstream]] in order to make my program work as expected. +While it may sounds scary —it definitely shows trivial-gamekit is a relatively +young project— the author has implemented a fix in less than an hour! +He also took the time to answer many questions I had when I joined the +~#lispgames~ Freenode channel. + +Before going any further, lets have a look at the complete file. + +#+BEGIN_SRC common-lisp +(cl:in-package :lysk) + +(gamekit:defgame app () () + (:fullscreen-p 't)) + +(defmethod gamekit:post-initialize ((app app)) + (gamekit:bind-button :mouse-left :released + (lambda () (gamekit:stop)))) + +(defun run () + (gamekit:start 'app)) +#+END_SRC + +The first line is some kind of header, to tell Lisp the owner of the file. + +The ~gamekit:defgame~ function allows for creating a new game application +(called ~app~ in our case). +I ask for a fullscreen window with ~:fullscreen-p~. +Then, we use the ~gamekit:post-initialize~ hook to bind a handler to the release +of the left button of our mouse. +This handler is a simple call to ~gamekit:stop~. +Finally, we define a new function ~run~ which only starts our application. + +Pretty straightforward, right? + +** Running our Program + +To “play” our game, we can start the sbcl REPL. + +#+BEGIN_SRC bash +sbcl --eval '(ql:quickload :lysk)' --eval '(lysk:run)' +#+END_SRC + +And it works! + +** A Standalone Executable + +It looks like empower a REPL-driven development. +That being said, once the development is finished, I don't think I will have a +lot of success if I ask my future players to start sbcl to enjoy my game. +Fortunately, trivial-gamekit provides a dedicated function to bundle the game as +a standalone executable. + +Following the advises of the borodust —the trivial-gamekit author— I created a +second package to that end. +First, we need to edit the ~lysk.asd~ file to detail a second package: + +#+BEGIN_SRC common-lisp +(asdf:defsystem lysk/bundle + :description "Bundle the Lykan Game Client" + :author "lthms" + :license "GPLv3" + :version "0.0.1" + :serial t + :depends-on (trivial-gamekit/distribution lysk) + :components ((:file "bundle"))) +#+END_SRC + +This second package depends on lysk (our game client) and and +trivial-gamekit/distribution. +The latter provides the ~deliver~ function, and we use it in the ~bundle.lisp~ +file: + +#+BEGIN_SRC common-lisp +(cl:defpackage :lysk.bundle + (:use :cl) + (:export deliver)) + +(cl:in-package :lysk.bundle) + +(defun deliver () + (gamekit.distribution:deliver :lysk 'lysk:app)) +#+END_SRC + +To bundle the game, we can use ~sbcl~ from our command line interface. + +#+BEGIN_SRC bash +sbcl --eval "(ql:quickload :lysk/bundle)" \ + --eval "(lysk.bundle:deliver)" \ + --quit +#+END_SRC + +* Conclusion + +Objectively, there is not much in this article. +However, because I am totally new to Lisp, it took me quite some time to get +these few lines of code to work together. +All being told I think this constitutes a good trivial-gamekit skeleton. +Do not hesitate to us it this way. + +Thanks again to borodust, for your time and all your answers! + +* Appendix: a Makefile + +I like Makefile, so here is one to ~run~ the game directly, or ~bundle~ it. + +#+BEGIN_SRC makefile +run: + @sbcl --eval "(ql:quickload :lysk)" \ + --eval "(lysk:run)" + +bundle: + @echo -en "[ ] Remove old build" + @rm -rf build/ + @echo -e "\r[*] Remove old build" + @echo "[ ] Building" + @sbcl --eval "(ql:quickload :lysk/bundle)" \ + --eval "(lysk.bundle:deliver)" \ + --quit + @echo "[*] Building" + +.PHONY: bundle run +#+END_SRC -- cgit v1.2.3