Intro to programming games with clojure
-
Upload
juio-barros -
Category
Technology
-
view
180 -
download
0
Transcript of Intro to programming games with clojure
Intro to Programming Gameswith Clojure
Julio Barros
E-String.com
1 / 57
We are all here to learn
No mistakes. Learningopportunities.
Learn from each other
2 / 57
"Give a person an app, frustratethem for a day. Teach a person to
code, frustrate them for alifetime."
-- Someone Internet Famous
3 / 57
Agenda
1. Introduce the game
2. Hands-on modifications
3. Game and Clojure concepts
4. Questions and experiments
4 / 57
Before
5 / 57
After
6 / 57
AboutJulio Barros / @JulioBarros
Assistants: Jed, Justin and Nuatu
Thank: Maureen Dugan & Jennifer / Epicodus
7 / 57
Creating a game1. Double click nightcode-0.4.2-standalone.jar2. Create an game using the Arcade Template named PDXvsSEA3. Play it
8 / 57
Resources1. Download http://bit.ly/intro-game-clojure2. Copy files from Downloads/intro-game-clojure/resources into your-
home/Nightmod/pdxvssea
9 / 57
Our first mod
10 / 57
Change Player
1. Open core.clj go to line 25.
2. Change "player.png" to "tram.png"
3. Save the file
(defscreen main-screen
:on-show
(fn [screen entities]
(update! screen :renderer (stage) :camera (orthographic)) (add-timer! screen :spawn-enemy 0 2)
(assoc (texture "player.png") ;; make this "tram.png"
:player? true
:x (/ (game :width) 2)
:y 10
:width 64
:height 64))
11 / 57
Change the enemy
1. Open entities.clj
2. Go to line 57
3. Change "enemy.png" to "needle.png"
(defn create-enemy
"Returns an enemy at a random position."
[]
(assoc (texture "enemy.png") ;; make this "needle.png"
:enemy? true
:x (rand (game :width))
:y (game :height)
:width 6 4
:height 64))
12 / 57
Change the missileStarts on line 24 in entities.clj
(defn create-missile "Returns a missile at the same x position as the mouse." [] (assoc (shape :filled :set-color (color :blue) ;; make :red :circle 0 0 10) ;; :ellipse 0 0 10 50 :missile? true :x (game :x) :y 50 ;; make 70 :width 10 :height 10)) ;; make 50
13 / 57
Play a sound when the missilefires(defn create-missile "Returns a missile at the same x position as the mouse." [] (sound "laser.wav" :play) ;; Add this (assoc (shape :filled :set-color (color :red) :ellipse 0 0 10 70) :missile? true :x (game :x) :y 70 :width 20 :height 70))
14 / 57
Play background music
Back in core.clj around line 21
(defscreen main-screen
:on-show
(fn [screen entities]
(sound "music.wav" :loop) ;; Add this
(update! screen :renderer (stage) :camera (orthographic)) (add-timer! screen :spawn-enemy 0 2)
(assoc (texture "tram.png")
:player? true
:x (/ (game :width) 2)
:y 10
:width 64
:height 64))
...
*Originally called http://ccmixter.org/files/djlang59/37792
15 / 57
Silence the background music(defscreen main-screen :on-show (fn [screen entities] ;; (sound "music.wav" :loop) (update! screen :renderer (stage) :camera (orthographic)) (add-timer! screen :spawn-enemy 0 2) (assoc (texture "tram.png") :player? true :x (/ (game :width) 2) :y 10 :width 64 :height 64)) ...
16 / 57
Games1) Setup
2) Loop
17 / 57
Setupcore.clj line 20
(defscreen main-screen :on-show (fn [screen entities] (update! screen :renderer (stage) :camera (orthographic)) (add-timer! screen :spawn-enemy 0 2) (assoc (texture "tram.png") :player? true :x (/ (game :width) 2) :y 10 :width 64 :height 64))...
18 / 57
Game space
19 / 57
Game loops are like flip books
20 / 57
The game loop - Hollywood
principle
Don't call us we'll call you.
Every time its time to draw a new screen :on-render (line 32) is called
:on-render
(fn [screen entities]
(clear!)
(->> entities
(move-missiles)
(move-enemies)
(update-score!)
(remove-missiles)
(remove-enemies)
(remove :remove?)
(render! screen)))
21 / 57
Move missilesentities.clj line 37
(defn move-missiles "Moves the missiles up." [entities] (for [e entities] (if (:missile? e) (assoc e :y (+ (:y e) 5)) e)))
22 / 57
Move enemiesentities.clj line 65
(defn move-enemies "Moves the enemies down." [entities] (for [e entities] (if (:enemy? e) (assoc e :y (- (:y e) 3)) e)))
23 / 57
Clojure Maps - A little bundle of
information
Other languages call them hash maps, hash or dictionary.
Maps associate keys and values.
Curly braces, {}, denote maps.
;; a map or record for a person
{:first-name "Julio"
:last-name "Barros"
:age 29}
;; a map for a game entity
{:texture-info "some stuff the system builds for us"
:missile? true :x 23
:y 30
:color :red}
24 / 57
The REPL
Open the repl and type (+ 2 4) and {:name "your name here"}
25 / 57
assocAssociates (adds or updates) a key and value in one map creating a new map.
(assoc {:name "Julio" } :loves "Clojure")
;; results in - ie outputs
{ :name "Julio" :loves "Clojure"}
(assoc {:x 10, :color :red} :x 11);; results in
{ :color :red :x 11}
26 / 57
Getting values from a map(get {:y "because"} :y) ;; gets the value of y
(:y {:y "because"}) ;; same thing just shorter
({:y "because"} :y) ;; this works too
27 / 57
What's with all those round ()things?Parentheses (round braces) denote lists. Lists are a sequence of things.
The special thing about lists is that usually the first item is executed.
(action argument1 argument2)
(function parameter1 parameter2)
(+ 3 4)
(assoc e :x 33)(assoc {:x 22, :color :red} :x 33)
quote or ' keeps the list from being executed
'(1 2 3) ;; [1 2 3] more common
28 / 57
What's up with the square []things?Square brackets, [] denote a vector (array). Vectors are also a sequence.
[1 2 3][1 2 [3 4]]
(count [5 5 5])=> 3
(get [1 2 3] 1) ;; Note: zero based.=> 2
You can have any length vector (or list) made up of any "type"
[3 {:name "Joe"} [1 2 3] '(1 2 [3 5])]'(3 {:name "Joe"} [1 2 3] '(1 2 [3 5]))
29 / 57
Other interesting types
"I'm a string" ;; strings
:name ;; keyword
3 ;; integer
3.0 ;; double
;; Note: 3.0 is different than "3.0"
0.5 ;; must start with a number
{} ;; map
[] ;; vectors
() ;; lists
#{} ;; set - unordered collection with no duplicates
30 / 57
if(if (some-test) (if-true-return-this) (if-not-true-return-this))
(if true "Told you so" "Never mind")=> "Told you so"
(if (= 1 2) "Told you so" "Never mind")=> "Never mind"
(if (even? x) x (+ x 1))
31 / 57
forWalks through vector/sequence giving each element the name "e" and using it in the stepsthat follow.
"e" can be any name.
Returns a vector.
(for [e [1 2 3]] (+ e e))
=> (2 4 6)
(for [current-n [1 2 3]] (even? current-n))
=> (false true false)
(for [e entities] (if (:missile? e) (assoc e :y (+ (:y e) 5)) e))
32 / 57
FunctionsTakes zero or more input parameters and returns a single value.
The return value could be a list or map or vectors of multiple things.
Returns the result of the last expression executed.
(defn my-function-name "A documentation string" [param1 param2] (functionA param1) (functionB param1 param2))
(defn increment "Adds one to the parameter" [a-number] (+ 1 a-number))
(increment 3)=> 4
33 / 57
Move enemies(defn move-enemies "Moves the enemies down." [entities] (for [e entities] (if (:enemy? e) (assoc e :y (- (:y e) 3)) e)))
(move-enemies [{:enemy? true :y 100} {:enemy? false :y 25} {:missile? true :y 50}])
=> ({:y 97, :enemy? true} {:y 25, :enemy? false} {:y 50, :missile? true})
34 / 57
Create an enemy(defn create-enemy "Returns an enemy at a random position." [] (assoc (texture "needle.png") :enemy? true :x (rand (game :width)) :y (game :height) :width 64 :height 64))
(create-enemy)
{:object "... some stuff about com.badlogic.gdx.graphics.g2d.TextureRegion" :height 64, :width 64, :y 965, :x 173.37581878372418, :enemy? true}
35 / 57
Random numbersRandom numbers are super useful in games.
(rand-int n) returns a random integer between 0 (inclusive) and n (exclusive).
(rand-int 10)=> 3 ;; or 0 or 1 or 2 .. or 9
36 / 57
Exercise: Our own Function -choose-oneWrite a function called choose-one that randomly chooses one element from a vector(choose-one [3 6]) chooses either 3 or 6 randomly. Put the function at the top of entities.clj
Things to think about:
1. How do you know how many things are in the vector?2. How do you pick an index between 0 and the last index in the vector?3. How do you get the item in the vector at that index?
37 / 57
Step 1Figure out how many things we have to choose from.
38 / 57
Step 1Figure out how many things we have to choose from.
(defn choose-one "Pick and return one thing from v. Well just the number of things in v." [v] (count v))
39 / 57
Step 2Pick a random index - a number from 0 to the number of things we have to choose from.
40 / 57
Step 2Pick a random index - a number from 0 to the number of things we have to choose from.
(defn choose-one "Pick and return one thing from v. Well a random valid index into v." [v] (rand-int (count v)))
41 / 57
Step 3Get the item at that index in the vector.
42 / 57
A solutionGet the item at that index in the vector
(defn choose-one "Pick and return one thing from v." [v] (get v (rand-int (count v))))
43 / 57
Use choose-one to pick differentenemies(defn create-enemy "Returns an enemy at a random position." [] (assoc (texture (choose-one ["enemy.png","needle.png"])) :enemy? true :x (rand (game :width)) :y (game :height) :width 6 4 :height 64))
44 / 57
Exercise: one-inWrite a function called one-in that takes a number, n, and returns true 1 in n times. (one-in5) returns true ~20% (1 in 5) of the time
Use it to create an old style enemy 1 out of 10 times.
Can you use choose-one to do the same thing?
45 / 57
Back to the game loop
Every function takes a list of entities and returns a list of entities.
May be the same list. More likely a new list made from the old list with a few changes.
(->> entities
(move-missiles)
(move-enemies)
(update-score!)
(remove-missiles) ;; mark missiles for removal
(remove-enemies) ;; mark enemies for removal
(remove :remove?) ;; actually do the remove
(render! screen)))
The remove step logic is a little tricky.
Homework: Study it to see if you can figure out how it works.
46 / 57
Wrap up
47 / 57
Programmable Music - Sonic Pihttp://sonic-pi.net
http://vimeo.com/113811476
48 / 57
Today's Parts ReviewClojure - Modern LISP targeting the Java Virtual Machine (JVM). http://clojure.org
Java / JVM - Mature enterprise programming language and the system that runs it.https://www.java.com/
Nightmod - Tool for making live-moddable games using Clojure and play-clj.https://nightmod.net
play-clj - Clojure game library that uses libGDX. https://github.com/oakes/play-clj
libGDX - Game development framework written in Java. http://libgdx.badlogicgames.com
49 / 57
Clojure ResourcesClojure Cheat Sheet
http://clojure.org/cheatsheet
Clojure From The Ground Up
https://aphyr.com/tags/Clojure-from-the-ground-up
Clojure For the brave and true
http://www.braveclojure.com
ClojureBridge
https://github.com/ClojureBridge/curriculum
Nightmod / Nightcode - thank Zach
https://nightmod.net
Emacs, Clojure Cursive, LightTable - other environments (IDEs).
50 / 57
Other popular languages
Javascript - Runs in the browser.
ClojureScript - Clojure for Javascript.
Ruby - Popular language with startups.
Python - Popular for data science.
Many many more.
Find one you (and your friends) like and form a
study group.
51 / 57
Programming ResourcesEpicodus - https://www.epicodus.com
Meetup.com
Clojure - http://www.meetup.com/clojerks/
Python - http://www.meetup.com/pdxpython/
PyLadies - http://www.meetup.com/PyLadies-PDX/
Ruby Brigade - http://pdxruby.org
Portland Indie Game Squad (PIGSquad) - http://pigsquad.com
Portland Tech Calendar - http://calagator.org
52 / 57
Games Resources
Cocos2D - http://cocos2d.org
For JavaScript, C++, Python, Swift, ...
GameKit - iOS/MacOS only
Unity, LibGDX - http://en.wikipedia.org/wiki/List_of_game_engines
Portland Indie Game Squad (PIGSquad) - http://pigsquad.com
53 / 57
Questions?
54 / 57
Thank You
Julio Barros - http://twitter.com/JulioBarros
Justin Holguin
Jed Clinger
Nuatu Tseggai
55 / 57
Feedback
1. What went well?
2. What can be improved?
3. How do we reach more people?
56 / 57
Exercise: Better Motion1) Make the enemies drift to the right as they fall.
2) Make some enemies go much faster than other enemies
3) Make enemies zig zag in a smooth(ish) manner as they fall.
57 / 57