;; pong.scm Daniel Azus 11-13-2006 ;; This program uses the world teachpack ;; Controls: ;; W = Up for left paddle ;; S = Down for left paddle ;; Up arrow = Up for right paddle ;; Down arrow = Down for right paddle ;; Constants (define WindowWidth 900) ;; The width of the window (define WindowHeight 600) ;; The height of the window (define FrameRate 100) ;; The rate the window is updated per second (define FrameDelay (/ 1 FrameRate)) ;; The delay between frames, based on the frame rate ;; Constants ;; Default values for variables (define CircleStartX (/ WindowWidth 2)) ;; The starting x position for the ball, and used when the balls is reset (define CircleStartY (/ WindowHeight 2)) ;; The starting y position for the ball, and used when the balls is reset (define CircleRadius 30) ;; Radius of the ball (define CircleSpeedStartX -15) ;; The x velocity of the ball (define CircleSpeedStartY -7) ;; The y velocity of the ball (define Paddle1Width 10) ;; Width of the left paddle (define Paddle1Height 100) ;; Height of the left paddle (define Paddle2Width 10) ;; Width of the right paddle (define Paddle2Height 100) ;; Height of the right paddle (define P1X 20) ;; Starting x position for the left paddle (define P1Y 100) ;; Starting y position for the left paddle (define P1Speed 50) ;; Speed the left paddle moves at (define P2X (- WindowWidth 20)) ;; Starting x position for the right paddle (define P2Y 0) ;; Starting y position for the right paddle (define P2Speed 50) ;; Speed the right paddle moves at (define P1Score 0) ;; The starting score for the left paddle (define P2Score 0) ;; The starting score for the right paddle ;; Defining the world ;; World variables ;; Frame = Frames since the program started ;; P1X = Left paddle x position ;; P1Y = Left paddle y position ;; P2X = Right paddle x position ;; P2Y = Right paddle y position ;; CircleX = The ball's x position ;; CircleY = The ball's y position ;; CircleSpeedX = The ball's x velocity ;; CircleSpeedY = The ball's y velocity ;; P1Score = Left paddle's score ;; P2Score = Right paddle's score ;; Paused = If the world is paused (define-struct World [Frame P1X P1Y P2X P2Y CircleX CircleY CircleSpeedX CircleSpeedY P1Score P2Score Paused]) ;; The first world that starts with the default values (define InitialWorld (make-World 0 P1X P1Y P2X P2Y CircleStartX CircleStartY CircleSpeedStartX CircleSpeedStartY P1Score P2Score false)) ;; Used when drawing images in a world (define (PutImage image x y image2) (place-image image (+ x (/ (image-width image) 2)) (- (+ y (/ (image-height image) 2)) 1) image2) ) ;; Used when drawing images in a world with out offset (define (PutImageNorm image x y image2) (place-image image x y image2) ) ;; Used when drawing text in a world (define (PutText Text TextColor x y image2) (PutImageNorm (text Text 12 TextColor) x y image2) ) ;; Used when drawing text in a world with a font size (define (PutTextSized Text TextColor fontsize x y image2) (PutImageNorm (text Text fontsize TextColor) x y image2) ) ;; Constant drawing colors (define ColorWhite (make-color 0 0 0)) (define ColorBlack (make-color 0 0 0)) (define ColorRed (make-color 255 0 0)) (define ColorGreen (make-color 0 255 0)) (define ColorBlue (make-color 0 0 255)) (define ColorDarkGrey (make-color 100 100 100)) ;; Constants for drawing (define PaddleRed (rectangle Paddle1Width Paddle1Height 'solid ColorRed)) (define PaddleBlue (rectangle Paddle2Width Paddle2Height 'solid ColorBlue)) (define BallGreen (circle CircleRadius 'solid ColorGreen)) (define Background (rectangle WindowWidth WindowHeight 'solid ColorDarkGrey)) ;; This takes care of making sure everything gets drawn (define (Draw-Window aworld) (PutTextSized (number->string (World-P1Score aworld)) ColorRed 25 (/ WindowWidth 3) 0 (PutTextSized (number->string (World-P2Score aworld)) ColorBlue 25 (* (/ WindowWidth 3) 2) 0 (PutImageNorm BallGreen (World-CircleX aworld) (World-CircleY aworld) (PutImage PaddleRed (World-P1X aworld) (World-P1Y aworld) (PutImage PaddleBlue (World-P2X aworld) (World-P2Y aworld) (PutImage Background 0 0 (empty-scene WindowWidth WindowHeight) )))))) ) ;; Takes care of updating all the world variables of the current world (define (UpdateWorld aworld) (cond [(World-Paused aworld) aworld] ;; Check if this world is paused [else (make-World (+ (World-Frame aworld) 1) ;; Increment the frame count (World-P1X aworld) ;; Do not change the left paddle's x position (World-P1Y aworld) ;; Do not change the left paddle's y position (World-P2X aworld) ;; Do not change the right paddle's x position (World-P2Y aworld) ;; Do not change the right paddle's y position (cond ;; CircleX [(<= (+ (World-CircleX aworld) CircleRadius) 0) CircleStartX] [(>= (- (World-CircleX aworld) CircleRadius) WindowWidth) CircleStartX] [else (+ (World-CircleX aworld) (World-CircleSpeedX aworld))] ) (cond ;; CircleY [(<= (+ (World-CircleX aworld) CircleRadius) 0) CircleStartY] [(>= (- (World-CircleX aworld) CircleRadius) WindowWidth) CircleStartY] [else (+ (World-CircleY aworld) (World-CircleSpeedY aworld))] ) (cond ;; CircleSpeedX, checks for boundries and paddles [(and (<= (- (World-CircleX aworld) CircleRadius) (+ (World-P1X aworld) Paddle1Width)) (>= (+ (World-CircleX aworld) CircleRadius) (World-P1X aworld)) (>= (+ (World-CircleY aworld) CircleRadius) (World-P1Y aworld)) (<= (- (World-CircleY aworld) CircleRadius) (+ (World-P1Y aworld) Paddle1Height))) (cond [(< (World-CircleSpeedX aworld) 0) (- (World-CircleSpeedX aworld))] [else (World-CircleSpeedX aworld)])] [(and (<= (- (World-CircleX aworld) CircleRadius) (+ (World-P2X aworld) Paddle2Width)) (>= (+ (World-CircleX aworld) CircleRadius) (World-P2X aworld)) (>= (+ (World-CircleY aworld) CircleRadius) (World-P2Y aworld)) (<= (- (World-CircleY aworld) CircleRadius) (+ (World-P2Y aworld) Paddle2Height))) (cond [(> (World-CircleSpeedX aworld) 0) (- (World-CircleSpeedX aworld))] [else (World-CircleSpeedX aworld)])] [else (World-CircleSpeedX aworld)] ) (cond ;; CircleSpeedY, checks for boundries and bouces off the top and bottom [(<= (- (World-CircleY aworld) CircleRadius) 0) (- CircleSpeedStartY)] [(>= (+ (World-CircleY aworld) CircleRadius) WindowHeight) CircleSpeedStartY] [else (World-CircleSpeedY aworld)] ) (cond ;; P1Score, increase when the ball is in a goal [(>= (- (World-CircleX aworld) CircleRadius) WindowWidth) (+ (World-P1Score aworld) 1)] [else (World-P1Score aworld)] ) (cond ;; P2Score, increase when the ball is in a goal [(<= (+ (World-CircleX aworld) CircleRadius) 0) (+ (World-P2Score aworld) 1)] [else (World-P2Score aworld)] ) false ;; This code will not be reached if the world is paused, so it is ok to use a constant value. ) ]) ) ;; This takes care of making sure everything gets updated (define (Update aworld) (cond [(World-Paused aworld) aworld] ; If world is paused nothing changes [else (UpdateWorld aworld)] ) ) ;; This is called when a mouse button is pressed. ;; It is unable to tell which button. (define (Mouse-Button-Down x y aworld) aworld ) ;; This is called when a mouse button is released. ;; It is unable to tell which button. (define (Mouse-Button-Released x y aworld) aworld ) ;; This is called when the mouse is moved. ;; It is unable to tell which button. (define (Mouse-Move x y aworld) aworld ) ;; This is called when the mouse is dragged. ;; It is unable to tell which button. (define (Mouse-Drag x y aworld) aworld ) ;; This is called anytime the mouse changes. ;; It is unable to tell which button is pressed or released. (define (Handle-Mouse a b c d) (cond [(eqv? d 'button-down) (Mouse-Button-Down b c a)] [(eqv? d 'button-up) (Mouse-Button-Released b c a)] [(eqv? d 'drag) (Mouse-Drag b c a)] [(eqv? d 'move) (Mouse-Move b c a)] [else a] ) ) ;; The up arrow key was pressed (define (Key-UpArrow aworld) (make-World (World-Frame aworld) (World-P1X aworld) (World-P1Y aworld) (World-P2X aworld) (- (World-P2Y aworld) P2Speed) (World-CircleX aworld) (World-CircleY aworld) (World-CircleSpeedX aworld) (World-CircleSpeedY aworld) (World-P1Score aworld) (World-P2Score aworld) (World-Paused aworld) ) ) ;; The down arrow key was pressed (define (Key-DownArrow aworld) (make-World (World-Frame aworld) (World-P1X aworld) (World-P1Y aworld) (World-P2X aworld) (+ (World-P2Y aworld) P2Speed) (World-CircleX aworld) (World-CircleY aworld) (World-CircleSpeedX aworld) (World-CircleSpeedY aworld) (World-P1Score aworld) (World-P2Score aworld) (World-Paused aworld) ) ) ;; The W key was pressed (define (Key-W aworld) (make-World (World-Frame aworld) (World-P1X aworld) (- (World-P1Y aworld) P1Speed) (World-P2X aworld) (World-P2Y aworld) (World-CircleX aworld) (World-CircleY aworld) (World-CircleSpeedX aworld) (World-CircleSpeedY aworld) (World-P1Score aworld) (World-P2Score aworld) (World-Paused aworld) ) ) ;; The S key was pressed (define (Key-S aworld) (make-World (World-Frame aworld) (World-P1X aworld) (+ (World-P1Y aworld) P1Speed) (World-P2X aworld) (World-P2Y aworld) (World-CircleX aworld) (World-CircleY aworld) (World-CircleSpeedX aworld) (World-CircleSpeedY aworld) (World-P1Score aworld) (World-P2Score aworld) (World-Paused aworld) ) ) ;; This is called anytime a key to pressed or released. ;; It is unable to tell if a key is still pressed or which key was released. ;; If a key is held down then the function will get called multiple times. (define (Handle-Keys a b) (cond [(eqv? b 'up) (Key-UpArrow a)] [(eqv? b 'down) (Key-DownArrow a)] [(eqv? b #\w) (Key-W a)] [(eqv? b #\s) (Key-S a)] [else a] ) ) ;; Creates the window (big-bang WindowWidth WindowHeight FrameDelay InitialWorld) ;; Set the drawing function (on-redraw Draw-Window) ;; Set the updating function (on-tick-event Update) ;; Set the key press function (on-key-event Handle-Keys) ;; Set the mouse handler function (on-mouse-event Handle-Mouse)