vydd / sketch
- вторник, 22 марта 2016 г. в 02:12:56
Common Lisp
A Common Lisp framework for the creation of electronic art, visual design, game prototyping, game making, computer graphics, exploration of human-computer interaction, and more.
Sketch is a Common Lisp environment for the creation of electronic art, visual design, game prototyping, game making, computer graphics, exploration of human-computer interaction and more. It is inspired by Processing Language and shares some of the API.
Today (March 2016), Quicklisp is Common Lisp's de facto package manager. Sketch is not a part of Quicklisp yet, but it is intended to be used with it, so you will have to clone it to your local-projects directory manually. If you're not sure how to do that, read the Quicklisp FAQ.
Sketch should be compatible with all major Common Lisp implementations and all major operating systems - more specifically, all CL implementations and operating systems that cl-sdl2 runs on. Incompatibily with any of those is considered a bug.
Sketch is known to work with:
Sketch is known to not work with:
If you test it on other systems, please send a pull request to include your results.
SDL2 is Sketch's only backend. It is a C library which you will need to download manually from libsdl webpage. Select the relase compatible with your operating system, or compile from the source code.
For loading image and font files, Sketch relies on SDL2 Image and SDL2 TTF, respectively, both part of the SDL project.
Some users have reported that libffi needed to be installed to make Sketch work.
Sketch requires graphics hardware and drivers with support for GL version 3.3.
Because Sketch is not in Quicklisp yet, you're going to need to clone https://github.com/vydd/sketch to your quicklisp/local-projects directory. Fire up your favorite Common Lisp implementation and type (ql:quickload :sketch)
.
To get a feel for what Sketch can do, and also to make sure that everything has been installed correctly, you can look at the examples. The code below will run all four currently provided examples at once. Note that on older machines running four sketches at once might result in a small degradation in performance, so you might want to run sketches separately.
CL-USER> (ql:quickload :sketch-examples)
CL-USER> (make-instance 'sketch-examples:hello-world)
CL-USER> (make-instance 'sketch-examples:sinewave)
CL-USER> (make-instance 'sketch-examples:brownian)
CL-USER> (make-instance 'sketch-examples:life) ; Click to toggle cells,
; any key to toggle iteration
In this, and all other examples, we're going to assume that Sketch is loaded with (ql:quickload :sketch)
, and that we're in package :SKETCH
, either after explicitly doing that via REPL:
CL-USER> (ql:quickload :sketch)
...
CL-USER> (in-package :sketch)
...
SKETCH> _
or by depending on :SKETCH
and :USE
ing it in a system and package definition respectively, like it's done for :SKETCH-EXAMPLES
.
Defining sketches is done via the DEFSKETCH
macro, that wraps DEFCLASS
. Using DEFCLASS
is still possible, but DEFSKETCH
makes everything so much easier, and in these examples, we're going to pretend that's the only way.
;; Let's say it one more time: All examples on this page need to have
;; :sketch loaded, and all of them execute inside the :sketch package.
(defsketch hello-world () ())
(make-instance 'hello-world)
If all goes well, this should give you an unremarkable gray window.
Let's add some color. Assuming that you're using Emacs + SLIME, or a similarly capable environment, you can just re-evaluate with the following code:
(defsketch hello-world () ()
(background +yellow+))
The screen becomes yellow. There are a couple of things to note. Drawing code doesn't need to go into a special function or method, or be binded to a sketch explicitly. DEFSKETCH
is defined as (defsketch sketch-name window-options slot-bindings &body body)
: that body is your drawing code. We will get to WINDOW-OPTIONS
and SLOT-BINDINGS
later. The other thing is that Sketch comes with its own color library. Currently, it supports RGBA and HSBA models, multiple convenient ways of defining colors, basic color mixing, basic color filters and a small number of predefined colors.
Let's draw something.
(defsketch hello-world () ()
(background (rgb 1 1 0))
(with-pen (make-pen :stroke (gray 0) :fill (rgb-255 200 200 200))
(ngon 6 (/ width 2) (/ height 2) 30 50 90)))
You get a vertically elongated hexagon. Let's see what we said here. We used a WITH-PEN
block to declare the PEN
- a set of drawing parameters - applied to elements inside. Notice a couple more ways of declaring colors.
Then we draw a shape, an NGON
, which is an n-sided convex polygon, inscribed in an ellipse.
The sketch is using WIDTH
and HEIGHT
to calculate a hexagon's center. These are actually the slots inherited from the SKETCH
class, made easy to use when drawing by being automatically wrapped inside WITH-SLOTS
with all slots listed. Other inherited slots are TITLE
, defaulting to "Sketch"
and being displayed on the titlebar, Y-AXIS
, which can be set to :UP
or :DOWN
(default), and COPY-PIXELS
which can be used to switch clearing the screen before drawing frames on or off.
All of these slots can be set using DEFSKETCH
syntax, using WINDOW-OPTIONS
:
(defsketch using-win-opts (:title "Hello, World"
:width 300
:height 300
:y-axis :down
:copy-pixels nil)
())
The third argument, SLOT-BINDINGS
, is reserved for defining slots. It's different from standard slot definition, looking more like a let init-form. Currently, initial values are mandatory and there are no special slot modifiers, but the latter will change soon.
(defsketch full-utilization (:title "We have slots")
((first-slot 0)
(foobar (if t "Foo?" "???")
(sym 'DEFAULT-SYMBOL)))
(background (hsb 0.5 1.0 1.0)))
These user-defined slots are also wrapped inside WITH-SLOTS
.
You have all the power of CL at your disposal when drawing, and you're not restricted to using only drawing primitives.
(defsketch hello-world (:title "Hello, World") ()
(background (rgb 1 1 0))
(with-pen (make-pen :stroke (gray 0) :fill (rgb-255 200 200 200))
(dotimes (i 11)
(ngon 6 (/ width 2) (/ height 2) (- 30 (* i 3)) (- 50 (* i 3))
:angle (- 90 (* i 4))))))
For everything else, read the code or ask vydd at #lispgames.
Go make something pretty.