Clojure + Slick - "stylistic" questions

45 views
Skip to first unread message

phtrivier

unread,
Feb 9, 2009, 8:14:00 AM2/9/09
to Clojure
Hi everyone

first of all, this is my first post, so if I ask FAQs or deserve to
RTFM, please tell me.

I am learning clojure, and trying to adapt some game code written in a
Java framework called Slick. After a couple of beginner's mistake (the
kind you do to learn ;) ), I got a working convestion of a Scoller
example. Still, there are some things that I don't find very elegant,
or where I'm pretty sure to be reinventing some wheel.

Code is here :

http://tinyurl.com/dj4l9z
or
git://github.com/phtrivier/clj-slick-tank.git

* The game is tile-based. I need to build up a collision map ("can the
tank walk on cell [3,2] ?"). Java does it with a two-dimensional array
of booleans. From discussion here :
http://groups.google.com/group/clojure/browse_thread/thread/5eb78c620eac19ea/b4d75ac4644c06a9?lnk=gst&q=two+dimensional+vector#b4d75ac4644c06a9
, I choosed to use a vector of vector (i probably should'nt have, but
that's another point). I wrote this :

(defn blocked?
"Is a position blocked in the screen?"
[screen x y]
(let [i (int x)
j (int y)]
(true? (get (get (screen :blocked) i) j))))

(defn make-row-generator
[cell-generator w]
(fn [i]
(vec (map (fn [j] (cell-generator i j))
(range 0 w)))))

(defn make-matrix
[w h cell-generator]
(vec (map (make-row-generator cell-generator w)
(range 0 h))))

(defn make-collision-map
"Builds a double dimensioned array telling
whether a cell is blocked"
[m w h]
(make-matrix
w h
(fn [i j]
(let [tileId (.getTileId m i j 0)]
(let [res
(Boolean/parseBoolean
(.getTileProperty m tileId "blocked" "false"))]
res
)))))

(the 'm' is a slick-specific stucture that holds the tile map).
Am I duplicating some existing library to build matrices ? Is there a
cleaner way to do it ?

* In a method I check for collisions :

;; Movement
(defn try-move
"Try and move a player in the screen given a direction.
Returns a list with the moved player, and a
boolean indicating whether the move was successfull.
"
[player screen dx dy]
(let [new_x (+ (player :x) dx)
new_y (+ (player :y) dy)]

(let [bxy (blocked? screen new_x new_y)
bx (blocked? screen new_x (player :y))
by (blocked? screen (player :x) new_y)]
(if bxy
(if bx
(if by
[player, false]
[(assoc player :y new_y), true])
[(assoc player :x new_x), true])
[(assoc player :x new_x :y new_y), true]))))

Will i get used to the nested 'if' blocks someday ? Any way to write
the equivalent of a switch case here, if only to improve
readibility ?

* Finally, my code starts with a rather ugly

(ns tank
(:import (org.newdawn.slick Animation
AppGameContainer
BasicGame
GameContainer
Graphics
Input
SlickException
SpriteSheet)
(org.newdawn.slick.tiled TiledMap)
(org.newdawn.slick.util Log)))

I know there is no way to import org.newdawn.slick.* (as discussed
here :
http://groups.google.com/group/clojure/browse_thread/thread/fa00a0ff4c264f9a/bcde2b6a4742fe6b?lnk=gst&q=import+all+classes+from+package#bcde2b6a4742fe6b
). What do you do in programs that need huge list of imports ? I'm
kinda spoiled by the Eclipse way of doing this, which is roughly :
import everything, forget about it, and let you IDE clear up the list.
And at least for development part it make things easier. If I hadn't
had the exact list of import to copy paste in this case, I would
probably have gone bored and depressed by the second class to import
manually (lazyness is not only for evaluation ;) )

Thanks for any ideas, sorry if post is too long / newbie-like.

Cheers
PH

Laurent PETIT

unread,
Feb 9, 2009, 9:08:44 AM2/9/09
to clo...@googlegroups.com
Since you say you're an Eclipse user, one answer could be : use clojuredev (eclipse plugin supporting clojure development),

and wait patiently for this feature to be included :-).

More seriously : clojuredev, while still a baby compared to slime, has some interesting features worth considering for current eclipse users :
- syntax coloring + rainbow parens
- namespace browser
- REPL launcher
- auto-compilation of files + problem markers (for compilation errors)
- "survival kit" of keyboard shortcuts in the editor : top-level s-expression selection, send to REPL (current selection or top-level s-expression), compile file, ...

Code completion and integration with the JDT are next on my todo list. It would be based on heuristics in a first time (deduction of the namespace of a symbol by simple/naive detection of the ns of the file), but would work 95% (if not better) of the time, and then, when time permits, based on real static analysis+dynamic analysis of code.

By integration with the JDT, the automatic addition of imports is indeed a really interesting feature I would like to add (I intend to first use a lot clojure for replacing bits of java in existing java projects, so our needs will match in this area :-).

Cheers,

--
Laurent


2009/2/9 phtrivier <phtr...@gmail.com>

Laurent PETIT

unread,
Feb 9, 2009, 9:18:11 AM2/9/09
to clo...@googlegroups.com
I wanted to say compared to emacs+slime+clojure-swank, of course.

There are also netbeans and jetbrain Ideas implementations, also.
I just posted here because you told about eclipse, but those other environments are good, too !

--
Laurent

2009/2/9 Laurent PETIT <lauren...@gmail.com>

phtrivier

unread,
Feb 9, 2009, 11:50:48 AM2/9/09
to Clojure
Oh, don't worry, I used clojuredev for this ;) I noticed a few bugs
here and there, by the way, so i'll have to find some time and
report / patch ... anyway on this topic you really have the same
probleme with java, except that propers tools just hide the hugly list
of import anyway.

Cheers
PH
> 2009/2/9 phtrivier <phtriv...@gmail.com>
>
>
>
> > Hi everyone
>
> >  first of all, this is my first post, so if I ask FAQs or deserve to
> > RTFM, please tell me.
>
> > I am learning clojure, and trying to adapt some game code written in a
> > Java framework called Slick. After a couple of beginner's mistake (the
> > kind you do to learn ;) ), I got a working convestion of a Scoller
> > example. Still, there are some things that I don't find very elegant,
> > or where I'm pretty sure to be reinventing some wheel.
>
> > Code is here :
>
> >http://tinyurl.com/dj4l9z
> > or
> > git://github.com/phtrivier/clj-slick-tank.git
>
> > * The game is tile-based. I need to build up a collision map ("can the
> > tank walk on cell [3,2] ?"). Java does it with a two-dimensional array
> > of booleans. From discussion here :
>
> >http://groups.google.com/group/clojure/browse_thread/thread/5eb78c620...
> >http://groups.google.com/group/clojure/browse_thread/thread/fa00a0ff4...

phtrivier

unread,
Feb 9, 2009, 11:51:06 AM2/9/09
to Clojure
Oh, don't worry, I used clojuredev for this ;) I noticed a few bugs
here and there, by the way, so i'll have to find some time and
report / patch ... anyway on this topic you really have the same
probleme with java, except that propers tools just hide the hugly list
of import anyway.

Cheers
PH

On 9 fév, 15:08, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> 2009/2/9 phtrivier <phtriv...@gmail.com>
>
>
>
> > Hi everyone
>
> >  first of all, this is my first post, so if I ask FAQs or deserve to
> > RTFM, please tell me.
>
> > I am learning clojure, and trying to adapt some game code written in a
> > Java framework called Slick. After a couple of beginner's mistake (the
> > kind you do to learn ;) ), I got a working convestion of a Scoller
> > example. Still, there are some things that I don't find very elegant,
> > or where I'm pretty sure to be reinventing some wheel.
>
> > Code is here :
>
> >http://tinyurl.com/dj4l9z
> > or
> > git://github.com/phtrivier/clj-slick-tank.git
>
> > * The game is tile-based. I need to build up a collision map ("can the
> > tank walk on cell [3,2] ?"). Java does it with a two-dimensional array
> > of booleans. From discussion here :
>
> >http://groups.google.com/group/clojure/browse_thread/thread/5eb78c620...
> >http://groups.google.com/group/clojure/browse_thread/thread/fa00a0ff4...

Matt Clark

unread,
Feb 9, 2009, 11:57:10 AM2/9/09
to Clojure
I agree with what Laurent said about clojuredev, I've been having
great success using it myself, for my clojure/slick creations. My
first project was converting Kevin Glass's platformer example over to
clojure which gave me a chance to learn slick and Clojure all in one
go! Unfortunately, the code I wrote for that is getting to be quite
out of date now and probably doesn't work with the latest clojure, but
I can at least offer some input based on my experience.

The platformer example is based on a tile grid with some fancy phys2d
stuff thrown in for collision detection. For grid storage I started
with a vector of vectors, and like you, which I too found far too
cumbersome. So I ditched it and decided to go with a sorted map of
coordinates to tiles (from the suggestion made in your linked thread
actually). Although I'm still not sure this is going to be a "best
practice" in clojure grids, it worked really well for me, simplifying
access to grid immensely. In your code, moving over to a map would
probably reduce the number of functions involved in your matrix
generation phase.

Also, in order to reduce passing around refs to collections for all
the functions, I declared things like the player and the screen in the
game's namespace and then later defined them during the game's init
stage. Still not completely ok with that solution, but I think it's
OK within the context of a slick game.

For me the import count reduced as the game grew and I separated it
into various files, so I wouldn't worry about that too much.
Personally, I've always been a fan of explicit imports so I know
what's going on when I reference a class name :)

-Matt



On Feb 9, 9:14 am, phtrivier <phtriv...@gmail.com> wrote:
> Hi everyone
>
>  first of all, this is my first post, so if I ask FAQs or deserve to
> RTFM, please tell me.
>
> I am learning clojure, and trying to adapt some game code written in a
> Java framework called Slick. After a couple of beginner's mistake (the
> kind you do to learn ;) ), I got a working convestion of a Scoller
> example. Still, there are some things that I don't find very elegant,
> or where I'm pretty sure to be reinventing some wheel.
>
> Code is here :
>
> http://tinyurl.com/dj4l9z
> or
> git://github.com/phtrivier/clj-slick-tank.git
>
> * The game is tile-based. I need to build up a collision map ("can the
> tank walk on cell [3,2] ?"). Java does it with a two-dimensional array
> of booleans. From discussion here :http://groups.google.com/group/clojure/browse_thread/thread/5eb78c620...
> here :http://groups.google.com/group/clojure/browse_thread/thread/fa00a0ff4...

Laurent PETIT

unread,
Feb 9, 2009, 12:12:22 PM2/9/09
to clo...@googlegroups.com
Oh nice !

So there's more clojuredev users than the ones having subscribed to the clojuredev-user ml :-)

Feel free to report bugs. I like them :-) Correcting a bug is like a step forward to perfection :-) :-)

--
Laurent

2009/2/9 phtrivier <phtr...@gmail.com>

Timothy Pratley

unread,
Feb 9, 2009, 6:36:47 PM2/9/09
to Clojure
> Will i get used to the nested 'if' blocks someday ? Any way to write
> the equivalent of a switch case here, if only to improve
> readibility ?

You could use cond:

(cond
(not (blocked? screen new_x new_y)) [(assoc player :y new_y) true]
(not (blocked? screen new_x (player :y)) [(assoc player :x new_x)
true]
(not (blocked? screen (player :x) new_y) [(assoc player :y new_y)
true]
:else [player false])

Jason Wolfe

unread,
Feb 9, 2009, 6:51:17 PM2/9/09
to Clojure
> I know there is no way to import org.newdawn.slick.* (as discussed
> here :http://groups.google.com/group/clojure/browse_thread/thread/fa00a0ff4...
> ). What do you do in programs that need huge list of imports ? I'm
> kinda spoiled by the Eclipse way of doing this, which is roughly :
> import everything, forget about it, and let you IDE clear up the list.
> And at least for development part it make things easier. If I hadn't
> had the exact list of import to copy paste in this case, I would
> probably have gone bored and depressed by the second class to import
> manually (lazyness is not only for evaluation ;) )

I have a way to import .* if you really want it, although it's so ugly
and not recommended I won't post it here :) I have found it useful
when I just want to mess around with quick scripts though. If you're
interested email me and I'll pass it on.

-Jason

phtrivier

unread,
Feb 10, 2009, 3:53:06 AM2/10/09
to Clojure
Thanks !

phtrivier

unread,
Feb 10, 2009, 4:52:01 PM2/10/09
to Clojure
Okay, can I ask exactly how you produce the map ? In my situation I
know how to compute whether a cell [i,j] is blocked, I can generate
the list of couples [i,j] that suits me ... and then I am stuck, not
knowing with function / macro to call. I guess it's just the same
problem as with cond, I am pretty sure their is a function that does
just that, but I don't have a clue how it's called ;) what I am
looking for is :

foobar [f col]
"Returns a map of the elements of col to the evaluation of function
f on each of them"

For some value of foobar ... I tried google all functions starting
with "Returns a map", but I had no luck .... it is some usage of map ?
of assoc itself in a way that I haven't tried ?

Cheers
PH

On 9 fév, 17:57, Matt Clark <matt.clar...@gmail.com> wrote:
> I agree with what Laurent said about clojuredev, I've been having
> great success using it myself, for my clojure/slickcreations.  My
> first project was converting Kevin Glass's platformer example over to
> clojure which gave me a chance to learnslickand Clojure all in one
> > Java framework calledSlick. After a couple of beginner's mistake (the
> > (the 'm' is aslick-specific stucture that holds the tile map).

Timothy Pratley

unread,
Feb 10, 2009, 5:38:26 PM2/10/09
to Clojure
Hi PH,

> "Returns a map of the elements of col to the evaluation of function

(zipmap keys (map fun keys))
http://groups.google.com/group/clojure/browse_thread/thread/8fe99ca560c4515/9721d59987207241?lnk=gst&q=zipmap#9721d59987207241

If you are following Matt's suggestion of a sorted map though then you
might need something a bit more complex:
"(sorted-map-by comparator & keyvals)" where comparator would probably
sort by x then y, you can generate you keyvals like so:
(interleave keys (map fun keys))

user=> (def ks [1 2 3])
user=> (defn f [x] (+ x 1))
user=> (apply sorted-map-by < (interleave ks (map f ks)))
{1 2, 2 3, 3 4}
user=> (zipmap ks (map f ks))
{3 4, 2 3, 1 2}

(note that < is not really necessary as is the default)

There are lots of ways to construct maps eg:
user=> (into {} [[1 2] [3 4]])
{3 4, 1 2}
user=> {1 2 3 4}
{1 2, 3 4}
user=> (hash-map 1 2 3 4)
{1 2, 3 4}

Regards,
Tim.

phtrivier

unread,
Feb 11, 2009, 8:15:37 AM2/11/09
to Clojure
So a FAQ it was, and not an old one with that ;) Thanks a lot !

On 10 fév, 23:38, Timothy Pratley <timothyprat...@gmail.com> wrote:
> Hi PH,
>
> >   "Returns a map of the elements of col to the evaluation of function
>
> (zipmap keys (map fun keys))http://groups.google.com/group/clojure/browse_thread/thread/8fe99ca56...
Reply all
Reply to author
Forward
0 new messages