Using Racket BSL to design a World program that allows a user to customize a face upon a "menu" of options for eyes, mouth, and hair - racket

TODO: design the World program bit-face to allow
someone to customize a face based upon a "menu"
of options for eyes, mouth, and hair.
You should have (at least) three options for eyes,
three options for mouth, and three options for hair.
Each time the user presses the "e" key, they should
see the next option for eyes (cycling as necessary);
same with "m" for mouth and "h" for hair. The
bit-face function should supply initial values for
each of these face features.
Images are random eyes, mouth, and hair images from the internet.
I can't seem to figure out how to cycle the eyes, mouth, and hair using on-key and am not sure how to use the to-draw in this specific scenario.
This is what I have so far using Racket BSL:
(require 2htdp/image)
(require 2htdp/universe)
(define EYES-1 [image here])
(define EYES-2 [image here])
(define EYES-3 [image here])
(define MOUTH-1 [image here])
(define MOUTH-2 [image here])
(define MOUTH-3 [image here])
(define HAIR-1 [image here])
(define HAIR-2 [image here])
(define HAIR-3 [image here])
(define-struct bf [eyes mouth hair])
; A BitFace (BF) is a (make-bf Image Image Image)
; Interpretation: customizable face based upon a
; menu of eyes, mouth, and hair
(define BF-1
(make-bf EYES-1 MOUTH-1 HAIR-1))
(define BF-2
(make-bf EYES-2 MOUTH-2 HAIR-2))
(define BF-3
(make-bf EYES-3 MOUTH-3 HAIR-3))
(define (bf-temp bf)
(... (bf-eyes bf) ...
(bf-mouth bf) ...
(bf-hair bf) ...))
; bit-face : Image Image Image -> Image
; creates a customized face based upon a "menu"
(define (bit-face e m h)
(big-bang (make-bf e m h)
[to-draw draw-bf]))
; Wishlist:
; - draw-bf
; - key-bf
; draw-bf : BF -> Image
; visualize a bit face
(define (draw-bf bf)
(place-image
(circle 100 "outline" "black")
150 150
(empty-scene 300 300)))
; key-bf : BF KeyEvent -> BF
; cycle the eyes, mouth, and
; hair when keys are pressed
(define (key-bf bf)
(... (bf-eyes bf) ...
(bf-mouth bf) ...
(bf-hair bf) ...))

Since it is big-bang, I think you should use on-key function. It is kind of similar like we have done for the color changing before. This time we are going to rotate the images not color. You can probably start with that.

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)

How to make a color changing sky in Racket?

I have a variable that controls the number of blue in (color R, G, B). Now I am confused about how to use that variable in (color R, G, B). Also, I am totally new to Racket. I know I can combine these functions together, but I don't know how :( The purpose of this code is to make a color changing scene in animate.
Here is my code:
(require 2htdp/image)
(define(Skycolor num)
(remainder num 510))
(define(skycolor num)
(abs(- 255(Skycolor num))))
(define(sky-color num)
(color 0 0 (skycolor num)))
(define (SKY num )
(square 200 "solid" (color 0 0 (sky-color num)))))
It's not very clear what do you mean with "color changing", but you can take some inspiration from following code. See also this similar question, where I explain how animate works.
#lang racket
(require 2htdp/universe)
(require 2htdp/image)
(define speed 5)
(define (sky-color ticks)
(color 0 (modulo (* speed (- 255 ticks)) 255) 255))
(define bg
(empty-scene 125 125))
(define (make-sky ticks)
(square 250 "solid" (sky-color ticks)))
(define (draw-image ticks)
(place-image (make-sky ticks) 0 0 bg))
(animate draw-image)

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.

Smoother projectile motion in Racket?

I'm playing a little with Racket big-bang mechanism, but I cannot get both smooth and fast going projectile. There's so much ugly flickering. Here's my code:
(require 2htdp/universe
2htdp/image)
(define gx 0)
(define gy 0.35)
(struct ballstate (x y vx vy) #:transparent)
(define startstate (ballstate 10 590 7 -20))
(define (make-new-state old)
(define newvx (+ (ballstate-vx old) gx))
(define newvy (+ (ballstate-vy old) gy))
(ballstate (+ (ballstate-x old) newvx)
(+ (ballstate-y old) newvy)
newvx
newvy))
(define (main)
(big-bang startstate
[on-tick make-new-state]
[to-draw place-ball-at]
[on-key reset]))
(define (place-ball-at s)
(place-image (circle 10 "solid" "red")
(ballstate-x s)
(ballstate-y s)
(empty-scene 800 600)))
(define (reset s ke)
startstate)
(main)
The question is: how to make it better, faster, smoother and flicker-free?
Here are two things that might help:
The on-tick clause takes an optional parameter that determines the time between two ticks. The default is 1/28, so if you lower this you will get more frames resulting in a smoother animation.
If your program takes longer than the time between each tick to produce an image, you will see stuttering. Precomputing everything that can be precomputed is a good thing. For example, there is no reason to produce a new empty scene each time, so below I have simply stored it in a variable.
(define (main)
(big-bang startstate
[on-tick make-new-state 1/50]
[to-draw place-ball-at]
[on-key reset]))
(define background (empty-scene 800 600))
(define (place-ball-at s)
(place-image (circle 10 "solid" "red")
(ballstate-x s)
(ballstate-y s)
background))

Racket: Why can't set canvas's background in windows

This my code:
#lang racket
(require racket/gui)
(define-values (screen-width screen-height) (get-display-size))
(define *app-width* 400)
(define *app-height* 125)
(define *vm-frame* (new frame%
[label "Test"]
[width *app-width*]
[height *app-height*]
[x (- (quotient screen-width 2) (quotient *app-width* 2))]
[y (- (quotient screen-height 2) (quotient *app-height* 2))]
))
(define frame-canvas%
(class canvas%
(super-new)
(inherit get-dc)
(define/override (on-paint)
(let ([my-dc (get-dc)])
(send my-dc clear)
(send my-dc set-background "black")))))
(let ([frame-canvas (new frame-canvas% [parent *vm-frame*])])
(send *vm-frame* show #t))
On mac os, this is normal, show a app with a black background.
But on windows, background is white.
Why? Racket version is 5.3, it's a 5.3 bug?
Reverse the order of set-background and clear.
The call to clear uses the color of the current background to do the fill. If somehow your on-paint were called at least more than once, then you would observe a black background, since the second time around, the current background color would be black. I suspect this is what explains the platform-specific difference you observed.