Animation in Racket - racket

Running program window So I'm doing this exercise from pictured programs and I've got the program to do as the exercise wants, but the image in the interaction window looks like a bunch of stacked backgrounds. I'm missing something with this program and I don't know what it is. Interaction window after program runs
Also I might add that this must be done without conditionals, for loops etc... advanced functions.
You can see that it overlays a white background that keeps the program from populating that space and I can't seem to find a way around this. I've literally brute forced every possible combination that I can think of and this is the best I could come with at this moment.
Exercise explanation is below:
Write an animation that starts with a blank screen, and each half
second adds a small dot at a completely random location — both the x coordinate and the
y coordinate are chosen at random.
Hint: Since you need to keep all the previous dots and add one more, your “model”
should probably be an image rather than a number. How can you add a dot at a specified
location to an existing image?
Hint: It would be especially nice if you could start the animation with any image, of
any size or shape, and it would sprinkle dots at random all over that background, without
rewriting the handlers.
; Random dots
(define DOT
(circle 4 "solid" "black"))
(define blank-screen
(rectangle 200 200 "solid" "white"))
(define (next-dot x)
(overlay/xy x
(min 200 (random 200)) (min 200 (random 200))
(old-dot DOT)))
(define (old-dot x)
(overlay/xy x
(min 200 (random 200)) (min 200 (random 200))
blank-screen))
(big-bang DOT
(on-tick next-dot 1/2)
(on-draw old-dot 200 200))

; Random dots
(define DOT
(circle 4 "solid" "black"))
(define blank-screen
(rectangle 200 200 "solid" "white"))
(define (next-dot x)
(overlay/xy x
(random 200) (random 200)
DOT))
(define (old-dot x)
(overlay/xy x
(random 200) (random 200)
blank-screen))
(big-bang DOT
(on-tick next-dot 1/2)
(on-draw old-dot 200 200))

Related

Racket/Beginner Student Language Confusion

I am trying to animate the word "floccinaucinihilipilification" letter by letter. Right now it displays the complete word in the animation window, but I am lost on how to animate it so it will count up from the first character to the last, looping back to 0.
(define LONG-WORD "floccinaucinihilipilification")
; cycle-spelling : String -> Image
; display an animation of a long
; word being spelled out
(define a (string-length LONG-WORD))
(define TXT
(text (substring LONG-WORD 0 a) 30 "black"))
(define BG
(empty-scene 400 400))
(define (cycle-spelling a)
(place-image TXT 200 200 BG))
(animate cycle-spelling)
See what animate does:
(animate create-image) → natural-number/c
create-image : (-> natural-number/c scene?)
opens a canvas and starts a clock that ticks 28 times per second. Every time the clock ticks, DrRacket applies create-image to the number of ticks passed since this function call. The results of these function calls are displayed in the canvas. The simulation runs until you click the Stop button in DrRacket or close the window. At that point, animate returns the number of ticks that have passed.
So you have to base your code on the number of ticks, passed to create-image function.
(animate cycle-spelling)
(define (cycle-spelling ticks) ... )
Start with (quotient ticks 28), value of this expression increases each second by 1.
Looping is created with modulo, so after some experimenting, you should have something like this:
(modulo (quotient ticks 28) (+ (string-length long-word) 1))
Rest of the code will be similar.
Following code animates given word letter by letter and then loops back to 0.
#lang racket
(require 2htdp/universe)
(require 2htdp/image)
(define long-word "floccinaucinihilipilification")
(define speed 3) ; try also 7, 14, 28 ...
(define bg
(empty-scene 400 400))
(define (cycle-spelling ticks)
(place-image (text (substring long-word 0
(modulo (quotient ticks speed)
(+ (string-length long-word) 1)))
30 "black")
200 200 bg))
(animate cycle-spelling)

What makes my image look half as wide as intended?

I am trying to place a vertically positioned rectangle and another object on an empty-scene using place-images in Beginning Student Language. However, when I run the function, the rectangle only takes up half the scene horizontally when its width is set equal to the width of the scene.
I checked what happens to my code using Stepper and found where the image-width halves but I do not know why. Probably it's to do with cons which I am not very familiar with.
Here's the full code:
(require 2htdp/image)
(define WIDTH 400)
(define HEIGHT 300)
(define HMAX 100)
(define SCENE (empty-scene WIDTH HEIGHT))
(define-struct vcham [x h c])
(define c (make-vcham 0 100 "white"))
(define (render ch)
(place-images (list (rectangle (* 1 WIDTH (/ (vcham-h ch) HMAX)) 50 "solid" "maroon")
(rectangle 1 1 "solid" "blue"))
(list (make-posn 0 0) (make-posn 20 20))
SCENE))
(render c)
I have simplified this code as much as a I could, thus the 1×1 rectangle. I am also interested in elegant alternatives to implement this, but am most interested in finding out why this happens.
place-images is like place-image :
Places image onto scene with its center at the coordinates (x,y)
and crops the resulting image so that it has the same size as
scene. The coordinates are relative to the top-left of scene.
you can change (make-posn 0 0) to (make-posn 200 25), or try place-images/align
(define (render ch)
(place-images/align (list (rectangle (* 1 WIDTH (/ (vcham-h ch) HMAX)) 50 "solid" "maroon")
(rectangle 1 1 "solid" "blue"))
(list (make-posn 0 0) (make-posn 20 20))
"left" "top" SCENE))

Racket: How do I keep an image from going off screen to appear on the other side?

I'm currently making a game where your character must dodge objects going on and off the scene.
My problem is that, when the objects go off the scene, they do not reappear on the other side.
Each object is represented by a posn structure, and they move a certain distance on the scene each time there's a tick from left to right and vise versa. I've attached which part of the code I think needs to be edited.
For clarity, a world is a struct containing a chicken and car, both of which are structs containing x and y posns.
And MOVE-CAR is a constant set to (add1 (random 49)) that determines how fast or slow the car will move during gameplay.
;update-world: world -> world
;purpose: updates the position of the car
(define (update-world a-world)
(make-world (world-chicken a-world) (move-horiz (world-car a-world) (* -1 MOVE-CAR))))
;move-horiz: posn number -> posn
;purpose: moves the posn left or right
(define (move-horiz a-posn delta-x)
(make-posn (+ delta-x (posn-x a-posn)) (posn-y a-posn)))
If more code is necessary, I will try and sift through the rest of what I have.
Any help is much appreciated.
To calculate the new x position, you are currently using:
(+ delta-x (posn-x a-posn))
If the result is between 0 and the width, this gives the correct result.
If the result is greater than the width, then the new x should be 0.
If the result is less than 0, then the new x should be the width.
Let's write a function adjust-x that adjusts the x-position you have calculated:
(define WIDTH 100)
(define (adjust-x x)
(cond
[(and (<= 0 x) (<= x WIDTH)) x]
[(> x WIDTH) 0]
[(< x 0) WIDTH]
Then you can change move-horiz to:
(define (move-horiz a-posn delta-x)
(make-posn (adjust-x (+ delta-x (posn-x a-posn)))
(posn-y a-posn)))

DrRacket: put two objects into big-bang

How can i put two objects with its own coordinates
(define padle1 (rectangle 10 30 "solid" "red"))
(define padle2 (rectangle 10 30 "solid" "red"))
(define (place-dot-at ... ) ...)
into bin-bang function
(big-bang ...
[to-draw place-dot-at])
Can i use list of padles
(define new-list (list padle1 padle2))
big-bang stores only one piece of information, usually called the "world state." All the functions that work with big-bang, like your drawing function, tick handler, and so on, must accept that world state as a single parameter.
It's up to you to decide what to store in your world state. If you want to store two locations (one for each paddle), a list or struct is the way to go. For instance, here is how you might define a struct called world that can hold two positions at once.
; Create a type called `world` that holds two locations.
(define-struct world [paddle1 paddle2])
; Create a variable to store the initial state of the world.
(define initial-world (make-world (make-posn 0 100) (make-posn 300 100)))
When you write your drawing function, it must accept the entire world state at once:
(define (draw-game world)
(place-image
paddle1
(posn-x (world-paddle1 world))
(posn-y (world-paddle1 world))
(place-image
paddle2
(posn-x (world-paddle2 world))
(posn-y (world-paddle2 world))
BACKGROUND)))
In your big-bang, treat the world state like any other kind of data:
(big-bang
initial-world
[to-draw draw-game])
I recommend making a draw-paddle function that draws a single paddle on top of an image i.
(define (draw-paddle p i)
(overlay/xy (rectangle ...) ; the paddle
50 70 ; coordinates on paddle on screen
i)) ; image of what's previously drawn
Then make a function that draws all paddles in a list on top of an image i.
(define (draw-paddles ps i)
(cond
[(empty? ps) i] ; no more paddles to draw
[else (draw-paddles
(rest ps) ; draw the rest of the paddles on top
(draw-paddle (first p) i))])) ; of the first paddle
; ontop of i
Then finally you can made:
(define (on-draw state)
(draw-paddles (list paddle1 paddle2) my-background))
If you don't have a background you can make one with empty-image or rectangle.

Why doesn't the UFO touch the flatbed rock at the bottom of the scene? Why does it stop before?

This is my program
; constants
(define SCENE-WIDTH 200)
(define SCENE-HEIGHT 200)
(define BGR-COLOR "blue")
(define FLAT-ROCKBED (rectangle 100 10 "solid" "black"))
(define MTSCN (place-image FLAT-ROCKBED
(/ SCENE-WIDTH 2) SCENE-HEIGHT
(empty-scene SCENE-WIDTH SCENE-HEIGHT BGR-COLOR)))
[define UFO
[overlay [circle 10 "solid" "green"]
[rectangle 40 4 "solid" "green"]]]
(define X-POS (/ SCENE-WIDTH 2))
(define UFO-PADDING
(- SCENE-HEIGHT
(/ (image-height UFO) 2)
(image-height FLAT-ROCKBED)))
; functions
[define [ufo-landing height]
[cond
[[<= height UFO-PADDING]
(place-image UFO X-POS height MTSCN)]
[[> height UFO-PADDING]
(place-image UFO X-POS UFO-PADDING MTSCN)]]]
It is from the first chapter of the How to Design Programs, 2nd Edition.
When I call the (animate ufo-landing) function in the interactions area this is the output I get
The UFO does not touch the flatbed rock.
How do I make it do that?
Edit 1:
The ordinate for placing UFO on the scene is dependent on two factors.
The height of the FLATBED-ROCK over which it has to land so that the UFO just touches its surface.
The center of UFO; its placement takes up 10 px above and below its center coordinate since its height is 20 px.
The UFO-PADDING constant accounts for the two factors I described above and is used to place the UFO on the scene. Thus, I expect the UFO to stop when it barely touches the surface of the FLATBED-ROCK. But it does not! Is there any other factor that affects the ordinate of the UFO? What am I missing?
I believe the issue is because when you do:
(define UFO-PADDING
(- SCENE-HEIGHT
(/ (image-height UFO) 2)
(image-height FLAT-ROCKBED)))
What you're doing is saying the padding of the center of the UFO is the HEIGHT - (image-height UFO / 2) - the image-height FLAT-ROCKBED. I believe that you should also do:
(/ (image-height FLAT-ROCKBED) 2)
Otherwise you'd be subtracting too much.
The construct animate calls ufo-landing with numbers 0, 1, 2, ...
You can try this expression in the interaction window (the repl) to
see the end image.
(ufo-landing 1000)
With a height of say 1000, ufo-landing uses this clause:
[[> height UFO-PADDING]
(place-image UFO X-POS UFO-PADDING MTSCN)]]]
The y-coordinate is UFO-PADDING .
To move the end position of the ufo adjust UFO-PADDING.
(define UFO-PADDING
(+ ?
(- SCENE-HEIGHT
(/ (image-height UFO) 2)
(image-height FLAT-ROCKBED))))
Try different numbers at the spot marked with the question mark.