;; targets.scm Daniel Azus 12-4-2006 ;; This program uses the world teachpack ;; Purpose: Change an element in a list dynamically in a world program ;; This program allows the user to control the crosshair ;; When the mouse if clicked on a target it will change color the first time it is clicked ;; Constants for window (define WindowWidth 800) ;; The width of the window in pixels (define WindowHeight 640) ;; The height of the window in pixels (define FrameRate 30) ;; The target rate the window is updated per second (frames per second) (define FrameDelay (/ 1 FrameRate)) ;; The delay between frames, based on the frame rate ;; Constants (define CrosshairRadius 20) (define TargetWidth 30) (define TargetHeight 30) ;; Default values for variables (define InitFrame 0) (define InitCosshairX 0) (define InitCosshairY 0) (define InitPaused false) ;; Defining structures (define-struct Target [x y Width Height Hit]) ;; rand: start (num) end (num) --> random number >= start and <= end (define (rand start end) (if (> (- end start) 0) (+ start (random (- (+ end 1) start))) 0) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; Defining and setting the default world ;; Defining the world ;; World variables ;; Frame = Frames since the program started ;; CrosshairX = X position of the crosshair ;; CrosshairY = Y position of the crosshair ;; TargetList = List of the targets ;; Paused = If the world is paused (define-struct World [Frame CrosshairX CrosshairY TargetList Paused]) (define (CreateInitialTarget Hit) (make-Target (rand 0 (- WindowWidth (* TargetWidth 10))) (rand 0 (- WindowWidth (* TargetHeight 10))) TargetWidth TargetHeight Hit ) ) ;; The first world that starts with the default values (define InitialWorld (make-World InitFrame InitCosshairX InitCosshairY (list (CreateInitialTarget false) (CreateInitialTarget false) (CreateInitialTarget false) (CreateInitialTarget false) (CreateInitialTarget false) (CreateInitialTarget false) (CreateInitialTarget false) (CreateInitialTarget false) (CreateInitialTarget false) (CreateInitialTarget false) ) InitPaused ) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; List helpers ;; Checks the size of a list (length function does the same thing) (define (size alist) (cond [(empty? alist) 0] [else (+ 1 (size (rest alist)))] ) ) ;; Gets a specified element in a list (define (GetElement AList Index) (cond [(empty? AList) empty] [(< Index 1) empty] [(= Index 1) (first AList)] [else (GetElement (rest AList) (- Index 1))] ) ) ;; Gets the last element in a list (define (last alist) (GetElement alist (size alist))) ;; Helps find a specified value in a list (define (FindHelper AList Value Index) (cond [(empty? AList) 0] [(eqv? (first AList) Value) Index] [else (FindHelper (rest AList) Value (+ Index 1))] ) ) ;; Finds a specified value in a list ;; Used to pass the initial index of 1 to the helper function (define (Find AList Value) (FindHelper AList Value 1) ) ;; Chops off all elements after and including the AfterThis value ;; It should be called by ChopListA (define (ChopListAHelper AList AfterThis SoFar) (cond [(empty? AList) empty] [(< AfterThis 1) empty] [(= AfterThis 1) empty] [else (cons SoFar (ChopListAHelper (rest AList) (- AfterThis 1) (first AList)))] ) ) ;; Chops off all elements after and including the AfterThis value (define (ChopListA AList AfterThis) (cond [(empty? AList) empty] [(< AfterThis 1) empty] [(= AfterThis 1) (rest AList)] [else (ChopListAHelper (rest AList) (- AfterThis 0) (first AList))] ) ) ;; Chops off all elements before and including the BeforeThis value (define (ChopListB AList BeforeThis) (cond [(empty? AList) empty] [(< BeforeThis 1) empty] [(= BeforeThis 1) (rest AList)] [else (ChopListB (rest AList) (- BeforeThis 1))] ) ) ;; Helps SetElement add the 2 lists together (define (SetElementHelper AList1 List1Size AList2) (cond [(empty? AList1) AList2] [(< List1Size 1) AList2] [else (SetElementHelper AList1 (- List1Size 1) (cons (GetElement AList1 List1Size) AList2))] ) ) ;; Sets the given index in a list to the value given (define (SetElement AList Index Value) (cond [(empty? AList) AList] [(<= Index 1) (cons Value (ChopListB AList 1))] [else (SetElementHelper (ChopListA AList Index) (size (ChopListA AList Index)) (cons Value (ChopListB AList Index)) ) ] ) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; Drawing helper functions ;; 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)) 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) ) ;; Used when drawing a line in a world (define (PutLine X1 Y1 X2 Y2 Color image2) (PutImageNorm (line (- X2 X1) (- Y2 Y1) Color) X1 Y1 image2) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; Other helper functions ;; Converts a number to true or false (define (ConvertNumToTF Value) (if (= Value 0) false true ) ) ;; Checks if two rectangles are intersecting (define (CollTarget R1X1 R1Y1 R1X2 R1Y2 R2X1 R2Y1 R2X2 R2Y2) (if (and (<= R1X1 R2X2) (>= R1X2 R2X1) (<= R1Y1 R2Y2) (>= R1Y2 R2Y1)) true false ) ) ;; Checks if two rectangles are intersecting with relative width and heights (define (CollTargetRel R1X R1Y R1W R1H R2X R2Y R2W R2H) (if (and (<= R1X (+ R2X R2W)) (>= (+ R1X R1W) R2X) (<= R1Y (+ R2Y R2H)) (>= (+ R1Y R1H) R2Y)) true false ) ) ;; Helper function for InTarget ;; Is recursive until a target is found or the list is empty (define (CollTargetsHelper Target TargIndex TargetList Index) (cond [(empty? TargetList) 0] [else (if (and (CollTargetRel (Target-x Target) (Target-y Target) (Target-Width Target) (Target-Height Target) (Target-x (first TargetList)) (Target-y (first TargetList)) (Target-Width (first TargetList)) (Target-Height (first TargetList))) (not (= TargIndex Index)) ) Index (InTargetHelper Target TargIndex (rest TargetList) (+ Index 1)) ) ] ) ) ;; Checks if a point is in a target (define (CollTargets Target TargIndex TargetList) (InTargetHelper Target TargIndex TargetList 1) ) ;; Checks if a point is in a rect (define (InRect X Y RectX RectY RectWidth RectHeight) (if (and (>= X RectX) (<= X (+ RectX RectWidth)) (>= Y RectY) (<= Y (+ RectY RectHeight))) true false ) ) ;; Helper function for InTarget ;; Is recursive until a target is found or the list is empty (define (InTargetHelper X Y TargetList Index) (cond [(empty? TargetList) 0] [else (if (InRect X Y (Target-x (first TargetList)) (Target-y (first TargetList)) (Target-Width (first TargetList)) (Target-Height (first TargetList))) Index (InTargetHelper X Y (rest TargetList) (+ Index 1)) ) ] ) ) ;; Checks if a point is in a target (define (InTarget X Y TargetList) (InTargetHelper X Y TargetList 1) ) ;; Sets a target to hit (define (SetTargetHit ATarget) (make-Target (Target-x ATarget) (Target-y ATarget) (Target-Width ATarget) (Target-Height ATarget) true) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; Everything that has to do with drawing ;; 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)) (define ColorDarkGreen (make-color 0 150 0)) ;; Constants for drawing (define Background (rectangle WindowWidth WindowHeight 'solid ColorDarkGrey)) (define Crosshair (circle CrosshairRadius 'outline ColorGreen)) ;; Draws a target (define (DrawTarget ATarget) (rectangle (Target-Width ATarget) (Target-Height ATarget) 'solid (if (Target-Hit ATarget) ColorRed ColorBlue)) ) ;; Drawing the rest of the targets (define(DrawTargets2 image1 TargetList image2) (cond [(empty? TargetList) image1] [else (PutImage (DrawTarget (first TargetList)) (Target-x (first TargetList)) (Target-y (first TargetList)) (DrawTargets2 image1 (rest TargetList) image2))] ) ) ;; Drawing the first target (define (DrawTargets TargetList image2) (DrawTargets2 (PutImage (DrawTarget (first TargetList)) (Target-x (first TargetList)) (Target-y (first TargetList)) image2) (rest TargetList) image2) ) ;; This takes care of making sure everything gets drawn (define (Draw-Window aworld) (PutLine (+ (World-CrosshairX aworld) CrosshairRadius) (- (+ (World-CrosshairY aworld) CrosshairRadius) CrosshairRadius) (+ (World-CrosshairX aworld) CrosshairRadius) (+ (+ (World-CrosshairY aworld) CrosshairRadius) CrosshairRadius) ColorDarkGreen (PutLine (- (+ (World-CrosshairX aworld) CrosshairRadius) CrosshairRadius) (+ (World-CrosshairY aworld) CrosshairRadius) (+ (+ (World-CrosshairX aworld) CrosshairRadius) CrosshairRadius) (+ (World-CrosshairY aworld) CrosshairRadius) ColorDarkGreen (PutImage Crosshair (World-CrosshairX aworld) (World-CrosshairY aworld) (PutTextSized (number->string (World-Frame aworld)) ColorWhite 18 (/ WindowWidth 2) 0 (DrawTargets (World-TargetList aworld) (PutImage Background 0 0 (empty-scene WindowWidth WindowHeight) )))))) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; Everything that has to do with updating ;; Update a single target (define (UpdateTarget ATarget) (make-Target (Target-x ATarget) (Target-y ATarget) (Target-Width ATarget) (Target-Height ATarget) (Target-Hit ATarget) ) ) ;; Updates a list of targets (define (UpdateTargets TargetList) (cond [(empty? TargetList) empty] [else (cons (UpdateTarget (first TargetList)) (UpdateTargets (rest TargetList)))] ) ) ;; 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-CrosshairX aworld) ;; The crosshair's x position (World-CrosshairY aworld) ;; The crosshair's y position (UpdateTargets (World-TargetList aworld)) ;; The target list false ;; Paused ) ] ) ) ;; 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)] ) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; Everything that has to do with mouse input ;; This is called when a mouse button is pressed. ;; It is unable to tell which button. (define (Mouse-Button-Down x y aworld) (make-World (World-Frame aworld) (- x CrosshairRadius 2) (- y CrosshairRadius 2) (if (ConvertNumToTF (InTarget x y (World-TargetList aworld))) (SetElement (World-TargetList aworld) (InTarget x y (World-TargetList aworld)) (make-Target (Target-x (GetElement (World-TargetList aworld) (InTarget x y (World-TargetList aworld)))) (Target-y (GetElement (World-TargetList aworld) (InTarget x y (World-TargetList aworld)))) (Target-Width (GetElement (World-TargetList aworld) (InTarget x y (World-TargetList aworld)))) (Target-Height (GetElement (World-TargetList aworld) (InTarget x y (World-TargetList aworld)))) true ) ) (World-TargetList aworld) ) (World-Paused aworld) ) ) ;; This is called when a mouse button is released. ;; It is unable to tell which button. (define (Mouse-Button-Released x y aworld) (make-World (World-Frame aworld) (- x CrosshairRadius 2) (- y CrosshairRadius 2) (World-TargetList aworld) (World-Paused aworld) ) ) ;; This is called when the mouse is moved. ;; It is unable to tell which button. (define (Mouse-Move x y aworld) (make-World (World-Frame aworld) (- x CrosshairRadius 2) (- y CrosshairRadius 2) (World-TargetList aworld) (World-Paused aworld) ) ) ;; This is called when the mouse is dragged. ;; It is unable to tell which button. (define (Mouse-Drag x y aworld) (make-World (World-Frame aworld) (- x CrosshairRadius 2) (- y CrosshairRadius 2) (World-TargetList aworld) (World-Paused 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] ) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; Everything that has to do with keyboard input ;; The up arrow key was pressed (define (Key-UpArrow aworld) (make-World (World-Frame aworld) (World-CrosshairX aworld) (World-CrosshairY aworld) (World-TargetList aworld) (World-Paused aworld) ) ) ;; The down arrow key was pressed (define (Key-DownArrow aworld) (make-World (World-Frame aworld) (World-CrosshairX aworld) (World-CrosshairY aworld) (World-TargetList aworld) (World-Paused aworld) ) ) ;; The left arrow key was pressed (define (Key-LeftArrow aworld) (make-World (World-Frame aworld) (World-CrosshairX aworld) (World-CrosshairY aworld) (World-TargetList aworld) (World-Paused aworld) ) ) ;; The right arrow key was pressed (define (Key-RightArrow aworld) (make-World (World-Frame aworld) (World-CrosshairX aworld) (World-CrosshairY aworld) (World-TargetList 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 'left) (Key-LeftArrow a)] [(eqv? b 'right) (Key-RightArrow a)] [else a] ) ) ;; =====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====*=====* ;; Sets up the window and what functions to call and when they should be called ;; 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)