Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
287 views
in Technique[技术] by (71.8m points)

scheme - How to have ball collide with bricks in Breakout (racket)

I've been trying to get Breakout to work in Racket, so far the ball bounces from the paddle (paddle is controlled by mouse) and the bricks are present

Here is the full on code:

(require 2htdp/image)
(require 2htdp/universe)

(define WIDTH 400)
(define HEIGHT 400)
(define BALL-RADIUS 10)
(define BALL-IMG (circle BALL-RADIUS "solid" "red"))

(define REC-WIDTH 50)
(define REC-HEIGHT 10)
(define REC-IMG (rectangle REC-WIDTH REC-HEIGHT "solid" "grey"))

(define BRICK-IMG0 (rectangle 60 30 "solid" "blue"))
(define BRICK-IMG1 (rectangle 60 30 "solid" "green"))

(define SCENE (empty-scene WIDTH HEIGHT))

(define STARTGAME
  (text "CLICK TO START" 60 "purple"))

(define GAMEOVER
 (text "GAMEOVER" 60 "red"))

(define-struct vel (delta-x delta-y))
; a Vel is a structure: (make-vel Number Number)
; interp. the velocity vector of a moving object

(define-struct ball (loc velocity))
; a Ball is a structure: (make-ball Posn Vel)
; interp. the position and velocity of a object

(define-struct rec (pos))
;
;

(define-struct brick (pos))
;
;

; Posn Vel -> Posn
; applies q to p and simulates the movement in one clock tick
(check-expect (posn+vel (make-posn 5 6) (make-vel 1 2))
              (make-posn 6 8))
(define (posn+vel p q)
  (make-posn (+ (posn-x p) (vel-delta-x q))
             (+ (posn-y p) (vel-delta-y q))))


; Ball -> Ball
; computes movement of ball in one clock tick
(check-expect (move-ball (make-ball (make-posn 20 30)
                                    (make-vel 5 10)))
              (make-ball (make-posn 25 40)
                         (make-vel 5 10)))
(define (move-ball ball)
  (make-ball (posn+vel (ball-loc ball)
                       (ball-velocity ball))
             (ball-velocity ball)))





; A Collision is either
; - "top"
; - "down"
; - "left"
; - "right"
; - "none"
; interp. the location where a ball collides with a wall

; Posn -> Collision
; detects with which of the bricks the ball collides
;(check-expect (collision (make-posn 0 12))  "left")
;(check-expect (collision (make-posn 15 HEIGHT)) "down")
;(check-expect (collision (make-posn WIDTH 12))  "right")
;(check-expect (collision (make-posn 15 0)) "top")
;(check-expect (collision (make-posn 55 55)) "none")

(define (collision ball rec)
  (cond
    [(<= (posn-x ball) BALL-RADIUS) "left"]
    [(<= (posn-y ball) BALL-RADIUS)  "top"]
    [(>= (posn-x ball) (- WIDTH BALL-RADIUS)) "right"]
    [(>= (posn-y ball) (- HEIGHT BALL-RADIUS)) "GAMEOVER"]
    [(and (>= (posn-x ball) (- (posn-x (rec-pos rec)) (/ REC-WIDTH 2)))
          (<= (posn-x ball) (+ (posn-x (rec-pos rec)) (/ REC-WIDTH 2)))
          (= (posn-y ball) (posn-y (rec-pos rec)))) "down"]
    [else "none"]))




; Vel Collision -> Vel  
; computes the velocity of an object after a collision
(check-expect (bounce (make-vel 3 4) "left")
              (make-vel -3 4))
(check-expect (bounce (make-vel 3 4) "top")
              (make-vel 3 -4))
(check-expect (bounce (make-vel 3 4) "none")
              (make-vel 3 4))

(define (bounce vel collision)
  (cond [(or (string=? collision "left")
             (string=? collision "right"))
         (make-vel (- (vel-delta-x vel))
                   (vel-delta-y vel))]
        [(or (string=? collision "down")
             (string=? collision "top"))
         (make-vel (vel-delta-x vel)
                   (- (vel-delta-y vel)))]
        [else vel]))


; WorldState is a Ball
; interp. the current state of the ball

; WorldState -> Image
; renders ball at its position
;(check-expect (image? (render INITIAL-BALL)) #true)
(define (render a-world)
  (draw-ball (world-ball a-world)
             (draw-bricklist (world-bricks a-world)
                             (draw-rect (world-rec a-world)))))


(define (draw-ball ball img)
  (place-image BALL-IMG
               (posn-x (ball-loc ball))
               (posn-y (ball-loc ball))
               img))

(define (draw-rect rec)
  (place-image REC-IMG
               (posn-x (rec-pos rec))
               (posn-y (rec-pos rec))
                SCENE))


(define (draw-bricklist list img)
  [cond ((empty? list) img)
        ((cons? list) (draw-bricklist (rest list) (draw-brick (first list) img)))])

(define (draw-brick brick image) 
  (place-image (choice BRICK-IMG0 BRICK-IMG1)
               (posn-x (brick-pos brick))
               (posn-y (brick-pos brick))
               image))


(define (choice a b )
  (if (zero? (random 1)) a b ))

; WorldState -> WorldState
; moves ball to its next location
;(check-expect (tick (make-ball (make-posn 20 12) (make-vel 1 2)))
;              (make-ball (make-posn 21 14) (make-vel 1 2)))
;(define (tick ball)
;  (move-ball (make-ball (ball-loc ball)
;                        (bounce (ball-velocity ball)
;                                (collision (ball-loc ball))))))

(define (tick world)
  (make-world (move-ball (make-ball (ball-loc (world-ball world))
                                    (bounce (ball-velocity (world-ball world))
                                            (collision (ball-loc (world-ball world))
                                                       (world-rec world)))))
  (world-rec world)
  (world-bricks world)))



(define (mouse world mouse-x mouse-y mouse-event)
  (cond
    [(string=? mouse-event "move") (make-world (world-ball world)
                                               (make-rec (make-posn mouse-x REC-Y-POS))
                                               (world-bricks world))]
    [else world]))



(define INITIAL-BALL (make-ball (make-posn 20 12)
                                (make-vel 1 2)))

(define REC-Y-POS (- HEIGHT (+ 20 REC-HEIGHT)))
(define INITIAL-REC (make-rec (make-posn 100 REC-Y-POS)))
(define INITIAL-BRICKS (list
                        (make-brick (make-posn 50 100))
                        (make-brick (make-posn 111 100))           
                        (make-brick (make-posn 172 100))
                        (make-brick (make-posn 233 100))
                        (make-brick (make-posn 294 100))
                        (make-brick (make-posn 355 100))
                        (make-brick (make-posn 50 131))
                        (make-brick (make-posn 111 131))           
                        (make-brick (make-posn 172 131))
                        (make-brick (make-posn 233 131))
                        (make-brick (make-posn 294 131))
                        (make-brick (make-posn 355 131))
                        (make-brick (make-posn 50 162))
                        (make-brick (make-posn 111 162))           
                        (make-brick (make-posn 172 162))
                        (make-brick (make-posn 233 162))
                        (make-brick (make-posn 294 162))
                        (make-brick (make-posn 355 162))))






(define-struct world (ball rec bricks))

(define INITIAL-WORLD-STATE (make-world INITIAL-BALL INITIAL-REC INITIAL-BRICKS))

(define (main state)
  (big-bang state (on-mouse mouse) (on-tick tick 0.01) (to-draw render)))

(main INITIAL-WORLD-STATE)

The Ball just flies straight through the bricks. I've added this following code to it:

;--------------------------------------------------------------------------------------------------
(define (overlap?
          brick-one-x brick-one-y brick-one-width brick-one-height
          brick-two-x brick-two-y brick-two-width brick-two-height)
          (cond
            [(and
                (and
                 (>= (+ brick-one-x brick-one-width) brick-two-x); within right bounds
                 (<= brick-one-x (+ brick-two-x brick-two-width)); within left bounds
                )
                (and
                 (>= (+ brick-one-y brick-one-height) brick-two-y) ;within top bounds
                 (<= brick-one-y (+ brick-two-y brick-two-height)) ; within bottom bounds
                ))
                #t]
             [else ;not overlapping
                #f]))



(define (brick-collide-ball? brick ball)
  (if
    (overlap?
       ;balls dimensions and location
        (posn-x (ball-loc ball))
        (posn-y (ball-loc ball))
        10
        10
     ;first brick in list
        (posn-x (brick-pos brick))
        (- (posn-y (brick-pos brick)) 10)
        60
        30)
         #t 
         #f))

(define (delete-bricks bricklist ball)
  (cond
    [(empty? bricklist) empty]
     ((cons? bricklist)
      (if (brick-collide-ball? (first bricklist) ball)
          (delete-bricks (rest bricklist) ball)
          (cons (first bricklist)(delete-bricks (rest bricklist) ball))))))

;--------------------------------------------------------------------------------------------------------

but it does not seem to make an impact on anything. I'm stuck now and would appreciate any tips to improve!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I used the following in my version of the Atari classic:

(define (colliding? b1 b2)
  (match-define (body x1 y1 w1 h1) b1)
  (match-define (body x2 y2 w2 h2) b2)
  (not (or (eq? b1 b2)
           (< (+ x1 w1) x2) (> x1 (+ x2 w2))
           (< (+ y1 h1) y2) (> y1 (+ y2 h2)))))

Here both the paddle and the ball is a "body", which is an rectangle with and (x,y) position and a width, w, and a height h.

(struct body (x y w h) #:transparent)

Note: If you ball happens to move very fast, it can happen that it "jumps over" the paddle. This can be fixed by having a maximum velocity.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...