On Feb 1, 2011, at 9:27 PM, Yaron Minsky wrote:
> I am trying to teach my scratch-addicted son a bit about racket, and I'm
> finding it to be rather tough going, mostly because a lot of things that are
> really easy in scratch seem surprisingly hard in racket. Also, even when I
> can get things done, the performance of the graphics leaves something to be
> desired. I'm wondering if this is just the way the world is right now, or if
> somehow I'm approaching this the wrong way.
>
> I was trying to put together a simple animation using the universe and image
> teachpacks where:
>
> - there is a "sprite" which switches between two images periodically
> - the sprite is always pointing at the mouse
When I run this code, the sprite points at the mouse as long as the mouse is to
the right of the sprite; once I move to its left, the sprite rotates in the
wrong direction.
And there are some minor inefficiencies that have nothing to do with the
graphics-and-animation library.
As it happens, one can address both of these at the same time: replace
(hyp (posn-mag delta))
(angle-in-radians (if (= hyp 0) 0 (asin (/ (posn-y delta) hyp))))
with
(angle-in-radians (if (= (posn-x delta) (posn-y delta) 0)
0
(atan (posn-y delta) (posn-x delta))))
which requires not only less computation (you can drop the "hyp" function
entirely) but less knowledge of trig.
There are a number of other things that would simplify the code, some of which
would also make things (slightly) more efficient.
Your sprite switches between its two images every 10 clock-ticks, where a
clock-tick defaults to 1/28 second. Instead, just set the tick interval to
what you want, and skip the 0.1 and the rounding.
(big-bang ...
(on-tick tick (/ 1 2.8)) ; or (on-tick tick 1/3) or (on-tick tick .382)
or whatever
... )
And since there are only two possible images in the world, I would probably use
a boolean or a pair of symbols or strings to choose between them:
(define WIDTH 400)
(define HEIGHT 400)
(define BACKGROUND (empty-scene WIDTH HEIGHT))
(define CENTER (make-posn (/ WIDTH 2) (/ HEIGHT 2)))
(define-struct world (pos mouse-pos sprite))
(define initial-world (make-world CENTER CENTER "fred"))
...
(define (next-sprite current)
(cond [(string=? current "fred") "george"]
[(string=? current "george") "fred"]))
(define (sprite-image current)
(cond [(string=? current "fred") pic1]
[(string=? current "george") pic2]))
(define (draw w)
(place-image
(rotate (angle-between (world-pos w) (world-mouse-pos w))
(sprite-image (world-sprite w)))
(posn-x (world-pos w))
(posn-y (world-pos w))
BACKGROUND))
(Symbols or booleans would be slightly more efficient, but I introduce strings
much earlier in my course than symbols or booleans.)
> Another thing I'd be interested in suggestions with is how to deal with
> updating a struct in a clean way. Right now, you need to explicitly wrote
> set-world-X functions for each field in your struct, which is pretty ugly.
> Also, the fact that structs don't have field names makes them more error
> prone. None of this is well suited towards building complex worlds with lots
> of components.
I'm not sure what you mean by "structs don't have field names", but the issue
of updating individual fields of a struct is under discussion; in a version
Fairly Soon the student languages will probably have functions that produce a
copy of a given struct with a single field replaced.
Stephen Bloch
[email protected]
_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users