making games in racket

581 views
Skip to first unread message

Taro Annual

unread,
Dec 26, 2015, 1:17:21 AM12/26/15
to Racket Users
Hi,

I make "pong" game in big-bang(2hdp/universe).
But, moving a racket(not language!) by keyboard("up", "down", ...), the racket freezes in 0.3~0.5s sometimes.

I think it is due to the beginner's platform.
What modules/syntaxes are used in action games in Racket language.

Thanks,
Taro.

Jay McCarthy

unread,
Dec 26, 2015, 7:52:36 AM12/26/15
to Taro Annual, Racket Users
Hi Taro,

The freezes are probably garbage-collection pauses. Recently (in the
snapshot builds) there is a new incremental GC mode that may improve
your program.

I have a few libraries---lux and mode-lambda---that are designed for
higher performance than 2htdp/universe and 2htdp/image but provide
similar functionalities

Jay
> --
> You received this message because you are subscribed to the Google Groups "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



--
Jay McCarthy
Associate Professor
PLT @ CS @ UMass Lowell
http://jeapostrophe.github.io

"Wherefore, be not weary in well-doing,
for ye are laying the foundation of a great work.
And out of small things proceedeth that which is great."
- D&C 64:33

Matthew Flatt

unread,
Dec 26, 2015, 7:54:52 AM12/26/15
to Taro Annual, Racket Users
It sounds like you're seeing pauses related to garbage collection. The
current pre-release version of Racket includes improvements aimed
specifically at this problem.

Can you try a current snapshot to see whether it eliminates pauses?:

http://pre.racket-lang.org/

The program should run better within DrRacket. For best results,
though, you may need to run outside of DrRacket (either by starting the
program with `racket` on the command line or by choosing "Create
Executable" in DrRacket's "Racket" menu).

If the pauses are still not eliminated in the current snapshot, I'm
interested to take a closer look at your program.

Thanks,
Matthew

Taro Annual

unread,
Dec 26, 2015, 9:52:20 AM12/26/15
to Racket Users, sagyo1...@gmail.com
2015年12月26日土曜日 21時54分52秒 UTC+9 Matthew Flatt:
Matthew,

Sorry, it doesn't work well. Try the follows:

---source code---

#lang racket
(require 2htdp/universe 2htdp/image point-free)
;(require lux mode-lambda)

; Tennis for two
;
; [Original Version]
; https://kyorohiro.gitbooks.io/doc_scratch/content/tennis_of_two/index.html

(struct world (player1 player2 ball) #:transparent)
(struct ball (x y dx dy) #:transparent)
(struct player (y keycnt) #:transparent)

(define BALL-IMAGE (circle 10 "solid" "orange"))
(define RACKET1-IMAGE (rectangle 5 100 "solid" "red"))
(define RACKET2-IMAGE (rectangle 5 100 "solid" "blue"))

(define (direction x)
(cond ((= x 0) 0)
((> x 0) 1)
(else -1)))
(define (saturate x a b) (max a (min b x)))
(define (from-to? x a b) (and (>= x a) (<= x b)))

(define (on-tick-func w)
(let ((player1 (world-player1 w)) (player2 (world-player2 w))
(ball1 (world-ball w)))
(let ((y1 (player-y player1)) (keycnt1 (player-keycnt player1))
(y2 (player-y player2)) (keycnt2 (player-keycnt player2))
(x (ball-x ball1)) (y (ball-y ball1))
(dx (ball-dx ball1)) (dy (ball-dy ball1)))
(let* ((n?x (+ x dx)) (n?y (+ y dy))
(top1 (- y1 50)) (btm1 (+ y1 50))
(top2 (- y2 50)) (btm2 (+ y2 50))
(collision1 (and (from-to? 50 n?x x)
(or (from-to? y top1 btm1)
(from-to? n?y top1 btm1))))
(collision2 (and (from-to? 550 x n?x)
(or (from-to? y top2 btm2)
(from-to? n?y top2 btm2))))
(nx (cond (collision1 (max n?x 50))
(collision2 (min n?x 550))
(else n?x)))
(ny (saturate n?y 0 400))
(ndx (cond (collision1 (abs dx))
(collision2 (- (abs dx)))
(else dx)))
(ndy (cond ((<= y 0) (abs dy))
((>= y 400) (- (abs dy)))
(else dy)))
(next-player1
(player
(saturate (+ y1 (* (direction keycnt1) 10)) 50 350)
(- keycnt1 (direction keycnt1))))
(next-player2
(player
(saturate (+ y2 (* (direction keycnt2) 10)) 50 350)
(- keycnt2 (direction keycnt2))))
(next-ball (ball nx ny ndx ndy)))
(when collision1 (display "collision1"))
(when collision2 (display "collision2"))
(world next-player1 next-player2 next-ball)))))

(big-bang
(world (player 200 0) (player 200 0) (ball 300 200 -5.1111 2.51111))

{on-key
(lambda (w key)
(case key
[("up") (world (world-player1 w)
(player (player-y (world-player2 w)) -10)
(world-ball w))]
[("down") (world (world-player1 w)
(player (player-y (world-player2 w)) 10)
(world-ball w))]
[("a") (world (player (player-y (world-player1 w)) -10)
(world-player2 w)
(world-ball w))]
[("z") (world (player (player-y (world-player1 w)) 10)
(world-player2 w)
(world-ball w))]
[("b") (display w)
w]
[else w]))}

{on-release
(lambda (w key)
(world (player (player-y (world-player1 w)) 0)
(player (player-y (world-player2 w)) 0)
(world-ball w)))}

{on-tick on-tick-func}

{on-draw
(lambda (w)
(~> (empty-scene 600 400)
(curry place-image/align
RACKET1-IMAGE 50 (player-y (world-player1 w))
"right" "center")
(curry place-image/align
RACKET2-IMAGE 550 (player-y (world-player2 w))
"left" "center")
(curry place-image/align
BALL-IMAGE (ball-x (world-ball w)) (ball-y (world-ball w))
"center" "center")))})

Taro Annual

unread,
Dec 26, 2015, 10:00:10 AM12/26/15
to Racket Users, sagyo1...@gmail.com
2015年12月26日土曜日 21時52分36秒 UTC+9 Jay McCarthy:
Jay,

Thank you. I'll try these.

Taro

Matthew Flatt

unread,
Dec 26, 2015, 9:39:10 PM12/26/15
to Taro Annual, Racket Users, sagyo1...@gmail.com
At Sat, 26 Dec 2015 06:52:19 -0800 (PST), Taro Annual wrote:
> 2015年12月26日土曜日 21時54分52秒 UTC+9 Matthew Flatt:
> > Can you try a current snapshot to see whether it eliminates pauses?:
> >
> > http://pre.racket-lang.org/
> >
> > [...]
>
> Sorry, it doesn't work well. Try the follows:

Can you say more about your platform, how you're running the program,
and what the pause looks like?

On OS X 10.11 and Racket 6.3.0.10, I started the program with

env PLTSTDERR="debug@GC error" racket pong.rkt

and I see output like

...
GC: 0:MAJ @ 111,386K(+56,166K)[+7,508K]; free 31,113K(-47,429K) 145ms @ 1521
GC: 0:mIn @ 113,400K(+73,411K)[+9,864K]; free 29,273K(-27,310K) 18ms @ 3536
GC: 0:mIn @ 92,385K(+92,464K)[+9,756K]; free 8,216K(-8,216K) 4ms @ 4125
GC: 0:mIn @ 92,433K(+92,416K)[+9,752K]; free 8,249K(-8,249K) 3ms @ 4705
GC: 0:mIn @ 92,470K(+92,379K)[+9,752K]; free 8,267K(-8,267K) 4ms @ 5295
GC: 0:mIn @ 92,447K(+92,402K)[+9,752K]; free 8,235K(-8,235K) 4ms @ 5898
GC: 0:mIn @ 92,468K(+92,381K)[+9,752K]; free 8,231K(-8,231K) 4ms @ 6485
GC: 0:mIn @ 92,517K(+92,331K)[+9,760K]; free 8,266K(-8,266K) 4ms @ 7050
GC: 0:mIn @ 92,511K(+92,337K)[+9,760K]; free 8,237K(-8,237K) 3ms @ 7599
GC: 0:mIn @ 92,559K(+92,290K)[+9,756K]; free 8,282K(-8,282K) 4ms @ 8181
GC: 0:mIn @ 92,520K(+92,328K)[+9,756K]; free 8,225K(-8,225K) 3ms @ 8767
GC: 0:mIn @ 92,521K(+92,328K)[+9,756K]; free 8,203K(-8,203K) 4ms @ 9355
GC: 0:mIn @ 92,542K(+92,307K)[+9,752K]; free 8,211K(-8,211K) 3ms @ 9929
GC: 0:mIn @ 92,659K(+92,190K)[+9,756K]; free 8,232K(-8,232K) 4ms @ 10501

where the "MAJ" is just before the game window shows. I'm not noticing
pauses interactively, either. I'm only running the game for under a
minute, though.

I see similar results when I run in DrRacket. The pauses tend to be
longer, but usually in the 6-10ms range -- and nothing close to
300-500ms after the forced GC before the game starts.


Thanks for your help,
Matthew

Taro Annual

unread,
Dec 27, 2015, 10:55:56 AM12/27/15
to Racket Users, sagyo1...@gmail.com
2015年12月27日日曜日 11時39分10秒 UTC+9 Matthew Flatt:
Umm, maybe there are some problems in my code.

Taro

Juan Francisco Cantero Hurtado

unread,
Dec 28, 2015, 12:54:21 PM12/28/15
to racket...@googlegroups.com
FYI, I also see the pauses in the game when I move the lateral bars
(with Racket 6.3 and git HEAD). I'm using Linux and the output of racket
only shows very small pauses.



Matthew Flatt

unread,
Dec 28, 2015, 9:07:17 PM12/28/15
to Juan Francisco Cantero Hurtado, sagyo1...@gmail.com, racket...@googlegroups.com
At Mon, 28 Dec 2015 18:54:10 +0100, Juan Francisco Cantero Hurtado wrote:
> FYI, I also see the pauses in the game when I move the lateral bars
> (with Racket 6.3 and git HEAD). I'm using Linux and the output of racket
> only shows very small pauses.

Aha --- do you mean that bars pause, but the ball moves smoothly? In
that case, maybe it has to do with key-repeat events. I have my repeat
delay set to its shortest value, but I think I see what you mean if I
turn it up to medium.

If that's the issue, a better approach may be to keep track of which
keys are pressed, using `on-key` to add to the key-pressed set and
`on-release` to subtract from the key-pressed set. Then, move the
paddles during `on-tick` based on the currently pressed keys.

Juan Francisco Cantero Hurtado

unread,
Dec 29, 2015, 12:18:49 PM12/29/15
to racket...@googlegroups.com, public-sagyo12341234-...@plane.gmane.org, public-racket-users-/...@plane.gmane.org
You're right. The problem is related to the key-repeat delay/rate
configuration.

Matthias Felleisen

unread,
Jan 5, 2016, 7:15:35 AM1/5/16
to Taro Annual, Racket Users

[[ Please, please break up your big function into small ones.
A function per handler would be a good start. -- Matthias ]]

Alexander Shopov

unread,
Jan 5, 2016, 8:39:34 AM1/5/16
to Racket Users
> break up your big function into small ones.
Apart from the obvious maintainability concerns - is there some rule
of thumb - how big a function shoul be in order to be inlined either
compile time or run time. If a code path is hot - what could stop the
inlining?
Kind regards:
al_shopov

Matthias Felleisen

unread,
Jan 5, 2016, 9:56:21 AM1/5/16
to Alexander Shopov, Racket Users
In general, I recommend

http://docs.racket-lang.org/style/
e.g., http://docs.racket-lang.org/style/Units_of_Code.html#%28part._.Size_.Matters%29

for such things. You really never want to read large units of code,
and all software used by someone other than the creator will have
to be understood and modified by either an older version of 'you' or
someone else.

Once you determine that your program is too slow for its intended uses,
consider using the Optimization Coach (together with the Profiler) to find
out whether a performance-critical part of your code suffers from a lack of
in-lining. If, and only if, you know that this is the problem, in-line via
suggestions to the compiler or via syntax definitions.

-- Matthias


p.s. Yes, not all of our software lives up to these standards. No excuses.
Occasionally we fail, too.

Vincent St-Amour

unread,
Jan 5, 2016, 9:56:21 AM1/5/16
to Alexander Shopov, Racket Users
While there's a hard size limit beyond which functions can't get
inlined, inlining most often stops because it performed "enough"
inlining starting from a given call site.

For each call site, the inliner starts with some amount of "fuel", which
is consumed after each successful inlining, proportional to the size of
the inlined function. Once the profiler runs out of fuel, it stops.

If you're interested in learning more about how the profiler affect your
programs, try the Optimization Coach DrRacket tool, which reports on
(among others) what the inliner does.

Vincent
Reply all
Reply to author
Forward
0 new messages