unit 7 more on the adventure game Working with the code The code is divided into several files It is distributed as a .zip file Download it from the web Unzip it into the directory of your choice The list of files is stored in the variable source-files in Adventure.meta To add a new file To load the code Click the file “Adventure.meta” Choose Execute All from the Execute menu Add its name to the end of source-files Type Control-E to update the definition Run: [reload] A tour of the code Adventure.meta Sound stuff.meta Basic code for handling text input Basic class files Things.meta, Places.meta, Actors.meta, Player.meta, Portals.meta OS-dependent code for window updating, and handling of user events (clicks and text input) String utilities.meta OS-dependent code for loading and playing .wav files User interface.meta Parsing.meta List of source files Code to load other source files Code to find art assets (sound and image files) Stuff for handling text Sample game.meta Example game You only need to worry about the basic class files and the sample game Subdirectories Sounds Holds any sound files you want (.wav only, sorry) Files can be accessed using the [sound-file filename] procedure Images Holds any images files (.jpg, .gif, .bmp, or .png) you want to use Files can be accessed using the [image-file filename] procedure Note: You don’t have to include the directory names in the filenames for sound-file and image-file. They know to search in the Sounds and Images directories, respectively. Recap: OOP in Meta [class [Name fields …] Parent more-fields …] Makes a new object of type Type And sets its fields based on args Defines a method for initializing an object of type Type before it’s returned by new Makes a procedure that can be specialized with methods [define-method [generic [Type arg] …] body …] [define-method [initialize [Type arg]] [generic-procedure] [new Type args …] Creates a new class named Name With parent class Parent And fields fields … and more-fields … Adds/modifies a method for generic procedure generic Matches only those calls whose args have their corresponding Types When a match is found, executes body [call-next-method] When used inside a method, calls the method of the parent class An adventure game in Meta Supports Pictures (for point-and-click style) Text output Sound You can decide which of these you want to use Basic ontology Things (have name, location) Places (have name, contents) Player Portals (have name, location, destination) The Thing class Things have: Name Location A string describing the object May be null Place in which the Thing can be found May be null Adjectives List of strings describing the object May be null [define Thing [class [Thing name location] Object adjectives]] [define-method [initialize [Thing x]] [move x x.location]] The Place class Places have Contents A list of Things inside them Sound Sound-loop? If true, the sound plays continuously Image Buffer to play when the user enters the room Can be null if no sound Bitmap to display when the user enters the room Hotspots A list of places in the image the player can click and handlers (procedures to call) for when they’re clicked [define Place [class [Place name] Thing contents hotspots sound sound-loop? image]] [define-method [initialize [Place p]] [call-next-method] [p.contents ← [new ArrayList]]] Update: Handling clicks of the mouse We’ve made definition of click actions more versatile since the last lecture [define click [generic-procedure]] The hotspots of a Place is a field with a list of lists: [define-method [click [Place p] mouseEventArgs] [with x = mouseEventArgs.X y = mouseEventArgs.Y [unless [null? p.hotspots] [for-each [hotspot → [when [and [≥ x [first hotspot]] [≥ y [second hotspot]] [≤ x [third hotspot]] [≤ y [fourth hotspot]]] [click [fifth hotspot]]]] p.hotspots]]]] [list left top right bottom handler] Where: Left and top give the coordinates of the upper-left corner of an area of the image Right and bottom give the coordinates of its lower-right corner handler is either a procedure to call or a game object such as a place If it’s a procedure, the system calls it If it’s a string, the system prints it If it’s a place, the system moves the user there If it’s any other game object, it runs click on it. [define-method [click [Place p]] [move the-player p] true] «Returning true tells the system to update the image, replay the sound, and generate new text» [define-method [click [String s]] [print-line s] false] «Returning false means don’t redraw anything» [define-method [click [Procedure p]] [p]] The Portal class Portals are objects that, when clicked on, move the player to a specified destination However, it looks funny for the system to print “You see a portal” So there’s a subclass called “Door” [define Portal [class [Portal name location destination] Thing]] [define Door [class [Door name location destination] Portal]] [define-method [click [Portal p]] [move the-player p.destination] true] Handling text input [define-pattern procedure pattern …] Tells the system to run procedure when the user types something that looks like pattern … Elements of pattern can be: Strings (must be matched exactly) Type names String (the type) Matches whatever the next word is Thing, Place, etc. System searches the user’s current location for an object of this type [define quit [→ [current-window.Close] false]] [define-pattern quit “quit”] Tells the system to run the quit procedure when the player types “quit” A fancier example This example sets the variable mouse-debug-mode? To true when the user types “mouse debug on” Or false if they type “mouse debug off” [define set-mouse-mode [mode → [mouse-debug-mode? ← [≠ mode “off”]] [print-line [if mouse-debug-mode? “Mouse hits will display coordinates” When mouse-debug-mode? is true The system prints the image coordinates of the point you click on Rather than running the click procedure This lets you easily find coordinates when you’re making hotspots in your images “Mouse hits will call click methods” false]] [define-pattern set-mouse-mode “mouse” “debug” String] ]] Other built-in handlers “debug [on/off]” Turns the variable debug-mode? true or false Not used by the system but might be useful for you. “go back” Brings the user to the place they were last A more interesting example Typing “go to” and a Portal clicks the Portal (which moves the user to the portal’s destination) You can define behavior for going to other kinds of things by writing methods for the goto procedure. [define goto [generic-procedure]] [define-method [goto [Thing p]] «Nothing happens» false] [define-method [goto [Portal p]] [click p]] [define-pattern goto “go” “to” Thing] [define-pattern goto “go” Thing] The sample game Brief highlights of my trip to AAAI last year AAAI is an Artificial Intelligence Conference Yes, I know this is a lame example To run it: Load: Sample game.meta Run [sample-game] [define great-hall null] [define robot-room null] [define art-room null] [define origami-room null] [define sample-game [→ [great-hall ← [new Place “the Video Games Symposium”]] [robot-room ← [new Place “the robot area”]] [art-room ← [new Place “the art installation”]] [origami-room ← [new Place null]] [set-up-hall] [set-up-robot-room] [set-up-art] [set-up-doors] [start-game “Sample game” 800 600 100 100]]] Example room: the great hall It’s best to write a separate procedure to initialize each room Set up sound and image Set misc-text field Which we didn’t talk about, but which prints when you enter the room Set hotspots to various strings and procedures to run Make the player That keeps the top-level procedure from being too big and hard to read And put it in the magic variable the-player Make the nerds [define set-up-hall [→ «Set up the great hall» [great-hall.image ← [image-file “Aaron talk.jpg”]] [great-hall.sound ← [sound-file “clap.wav”]] [great-hall.misc-text ← “Aaron Khoo is giving a talk on Mythica.”] [great-hall.hotspots ← [list [list 174 392 238 471 ouch] [list 466 346 585 451 ouch] [list 46 87 513 440 “Stop that. You'll get finger prints on it.”] [list 640 320 760 450 “Aaron says Mythica was great until they killed the project.”]]] [the-player ← [new Player “Emily” great-hall]] [with nerds = [new Nerds null great-hall] [nerds.adjectives ← [list “many”]]]]] The ouch procedure [define ouch-counter 0] [define ouch-statements [list “Ouch” “Please don't do that.” “Ouch!” “Are you having a good time?” “This is getting a little infantile, isn't it?”]] [define ouch [→ [print-line [get ouch-statements ouch-counter]] [when [< ouch-counter [− [length ouch-statements] 1]] [ouch-counter ← [+ ouch-counter 1]]]]] The Eat procedure Lets you type “Eat [Thing]” Simulates destroying the Thing by moving it to null (i.e. nowhere) Now it’s not in the room And so it appears to be destroyed Prints “Mmmm, yumming Things …” Returns false Which tells the system not to redraw the display [define eat [thing → [move thing null] [print-line “Mmmm, yummy ” [[type-of thing].Name.ToLower] “...”] false]] [define-pattern eat “eat” Thing] The art and origami rooms The art room [define set-up-art brings you to the [→ origami room when «Set up the art room» you click on it [art-room.image ← [image-file “Art installation.JPG”]] [art-room.misc-text ← “It was make by art and robotics students from the University of New Orleans.”] [art-room.hotspots ← [list [list 130 50 323 360 origami-room]]] «Set up the origami room» [origami-room.image ← [image-file “Origami room.jpg”]] [origami-room.sound ← [sound-file “dog-bark4.wav”]] [origami-room.adjectives ← [list “origami filled”]]]] Making doors Doors in this system are only one-way So we need to make doors in pairs They live in one room And lead to the other But aren’t visible in the other One from room A to room B One from room B to room A So it’s easiest to make a procedure to do this for us [define make-door-pair [place1 name1 place2 name2 → [new Door name1 place1 place2] [new Door name2 place2 place1]]] [define set-up-doors [→ «Connect the rooms» [make-door-pair great-hall null robot-room “symposium”] [make-door-pair art-room null robot-room “art”]]]