我一直在尝试让 Breakout 在球拍中工作,到目前为止,球从球拍上反弹(球拍由鼠标控制(并且砖块存在
以下是完整的代码:
(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)
球只是直接飞过砖块。我在其中添加了以下代码:
;--------------------------------------------------------------------------------------------------
(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))))))
;--------------------------------------------------------------------------------------------------------
但它似乎对任何事情都没有影响。我现在被困住了,希望有任何改进的提示!
我在雅达利经典版本中使用了以下内容:
(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)))))
这里的球拍和球都是一个"身体",它是一个矩形与和(x,y)
位置和宽度、w 和高度 h。
(struct body (x y w h) #:transparent)
注意:如果你的球碰巧移动得非常快,它可能会"跳过"球拍。这可以通过具有最大速度来解决。
另一个答案中,您可能能够解决这个问题而不会陷入速度跳跃的一种方法是计算球当前行进的线与球拍的边界线(大概是前部(的交点。然后,您只需确定该点是否真的在球拍的线段上,以及球先前位置与其假设位置之间的线段上,即可确定碰撞是否会发生"帧之间"并处理该反射。更彻底的检查是对球拍的边缘做同样的事情,因为那场比赛确实允许球拍从侧面击球。
计算示例:
#lang racket/base
(require racket/struct)
(struct line (a b c) #:transparent) ; ax+by=c
(struct pos (x y) #:transparent)
(define (meet l1 l2)
(let-values (((a b c) (apply values (struct->list l1)))
((d e f) (apply values (struct->list l2))))
(let ((denominator (- (* a e) (* b d))))
(if (zero? denominator)
'parallel ;probably impossible in your game
(let ((x* (- (* c e) (* b f)))
(y* (- (* a f) (* c d))))
(pos (/ x* denominator)
(/ y* denominator)))))))