summaryrefslogtreecommitdiffstats
path: root/site/posts/DiscoveringCommonLisp.org
diff options
context:
space:
mode:
authorThomas Letan <lthms@soap.coffee>2020-02-05 23:17:34 +0100
committerThomas Letan <lthms@soap.coffee>2020-02-05 23:17:34 +0100
commit7c47d2b8f99be4a53f50e46015c15301ffa16ae1 (patch)
tree80535ee8c3f9d545f4052e088f10bbbae33adc6b /site/posts/DiscoveringCommonLisp.org
parente0648ba3161016c8abad5cd80f03eef189cc4078 (diff)
Rename org posts
Diffstat (limited to 'site/posts/DiscoveringCommonLisp.org')
-rw-r--r--site/posts/DiscoveringCommonLisp.org258
1 files changed, 258 insertions, 0 deletions
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
+<h1>Discovering Common Lisp with <code>trivial-gamekit</code></h1>
+
+<span class="time">June 17, 2018</span>
+#+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