Step3 - CSE 335 Step 3: Files, Time, Animation, and...

Info iconThis preview shows pages 1–8. Sign up to view the full content.

View Full Document Right Arrow Icon
Background image of page 1

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 2
Background image of page 3

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 4
Background image of page 5

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 6
Background image of page 7

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 8
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: CSE 335 Step 3: Files, Time, Animation, and Visitors This is CSE 335 Step 3. This assignment Will address three important topics Fil s e Savmg your city as an XMLfile and loading it back in. Time - Making your tiles change overtime and creating a simple animation. Visitors 7 Using a Visitor pattern for efficient operations on our tiles. The bulk ofthis step assignment is tutorial, but there are seVeraI programming tasks you Will need to complete and you haVe to create a UMLdiagram The programming elements ofthis assignment are due Thursday, September 23, 2010 at ll 55pm. WheneVer you see this icon you should be sure your program Will compile and run I have supplied a hints and suggestions page for this step. Before you Begin This assignment builds on Step 2 lfyou did not complete Step 2, please contact course staffto discuss alternatIVes to continue on this step. This step builds the foundation for Proyect l. You Will be responsible forthis step individually. Yourgroup Will selem one Step 3 solution ofthe members ofyour group to extend for ProjeCtl Please do not turn in a DijECE named Step2 for this assignment ln Eclipse, it is easy to copy a DfUlEfl Click on an open DijECE and select Edit/Copy. Then selettt Edit/‘Paste. It Will alloW you to give the copy a new name. I Would use Step3 You should then close Step2. In the Modes enum in CFrame, please change option 5 from Commune to Windmill. The enum should now be: enum Modes (Trash=0, Blank=1, Grass=2, Firestation=8 , University=9 , Residentia1=l4, Parkland=15 l ; Blacksmith=3, Coalmine=4, Windmill=5, Cricket=6, Port='7, Industryfleavy=10, lndustryLight=ll, Market=12, Tree=13, A Save As menu option Our city builder program is not much use ifyou have to rebuild the city eVery time you stait the program. So, we are going to add the ability to save and load the citydata to/from files First, We need to add a menu option Add a new menu option to the file menu called "SaVe &As.. lt should call the function CFrame::OnFileSaveAs(). lfyou don't recall how to create menu options, see the page 1: ea’ ‘ ’ You should be able to run your program and select the File/Save As menu option lt should notdo anything, yet The WxWidgets class to pop up a File SaVe Dialog box is waileDialog. Add this code to CFrame::OnFileSaveAs()to bring up thatdialog box amehti ‘ e's wxE'ileDialog dlgtthis, L"Save File", L"", L"", L"*.oity", waD_SAVE if(d1g.3hownoas1() != wxlD_OK) return; I waD_dVERW'RITE_PROM'—”T) 7 Feel free to peruse the documentation. You should be able to run your program and select the File/Save As menu option. The save dialog box should come up. 3 a to options in the documentation. The options l have selemed indicate this is a save dailog box and that I Want a Warning if l try to oVerwrite a file BTW, you can usually type a wxWidgets class name into Google and itWilI go straight to the We are going to have an extension of.city forthe files We save our city in. Unfortunately, ifyoujusttype in “file” as the filename, waileDialog Will give you that name and doesn‘t automatically add the extension. So, we Want to tack “ city“ onto the end of the filename ONLY if it is not already there, because it Will be there is we are overwriting an existing file // Get: the filename into a local string wstring filename = dlg.GetPath() .wc_str(); // If no suffix is supplied for the file, supply it here wstring suffix(L".city") ,' if ( ! equal (suffix. rbegin“ , l suffix.rend () , filename.rbegin () )) filename += suffix; l The function dlg.GetFatht) returns a watrihg, wxWidgets own string implementation. l prefer to use STL strings when posSIble, so l‘m converting the filehame to an STL string using its memberfunction WILSHO This returns a Wide charadter string in C format (null terminated) The folIoWing code is a bit oftrickery The STL function equal can be used to test to strings for equality By using rbegin and rend, I‘m testing from the end ofthe strings rather than the beginning lfthe suffix does not exist, l add it. Who should do the Work of savmg the city? lt seems logical that CCity should be responsible for that task. CFrame Was responsible for getting a filename. Now We‘ll let CCitydo the rest ofthe Work. Add this member function to CCity wxWidgels has its own class fol strings called Sti ing. it by default handles Unicode stlings However, I pretet to Lise the STL string functions in progtarns when possible to avoid much platform specific code Also, the plan is that watring Will be phased out inlhe fulule in favor of using the STL siting classes. You can conved a walling to a wstring using the .WtiiSIIO function on watring That returns a pointer to a null lenninaled const WCl‘lafJ * string We can put that into a wslring /x * Name CCity: :SaveO * Description Save the city as a .oity XML. file. */ void CCity::Save(oonst std: :wstring Efilename) l l Now add this code to the end of CFrame"OnFileSaveAs(lto save the city' mCity . Save (filename) F XML Set a breakpoint in CCity: Save(l and run You should be able to enter a filename and have the debugger stop in the routine This ensures you are getting to this point in execution okay If you don‘t knowwhat It! . Microsoft Office 2007 replaced the Office file formats With XMLfiIes (multiple files stored in a Zip archive) It is a very convenient and popularformat. This is what an XMLfile for our city Will look like when we are done. <?x.ml version="1 .0" encoding="utf-8"?> (city) <tile x.="341" y="248“ time="1264370381921" type-"grass"/> <tile x.="403" 279" tim '12643'70381941" grass"/> <tile x.=“279" y="279“ time=“1264370381941“ type=“graas"/> <tile x="465" y="310“ time=“126437035194l“ type="grass"/> <tile x="341" y="310" time="12643'70381941" type="windmill"/> <tile x="217" y="310" time="1264370382061“ type="grass"/> <tile x=“403" y="341“ time=“1264370382061“ type="grass"/> <tile x.="2'79" y="341" time="12643'70382061" type="grass"/> <tile x="341" y="372" time="1264370382061“ type="grass"/> <lcity> _ is, now is a good time to learn. XML is a standard way to encode documents. The vast mayority of new application that save files containing text data Will save it in XML and even applications With lots ofbinary data areiumping on the bandwagon. XML looks a lot like HTML It consists of tags, which start With < and end with >. There are three types oftags: start tags, end tags, and emptyrelementtags. In the example above, <city> is a staittag What follows is contained in that tag. We call the outer tag the root tag and only allow one. lnside We see other tags fortiles. These are empty element tags, since theydon‘t contain other content between the tag and an end tag Empty-element tags begin With < and end With f: Each tag has the name tile followed by attributes (called propenies in wxWidgets). An attribute consists ofa name and a value in quotation marks. The file contains only text. XML suppons many different character formats We‘ll use ufl-, which is a representation of Unicode as one to four bytes per character. We‘ll let the library deal With those details for us The XML version and encoding is indicated by the special <9me> tag that stans the document. Atag that encloses other tags Will have a start, as in <city> and an end, as in </city>, Atag that stands alone, like the tile tags above Wlll end With “/>“ You should be familiar With the format; you‘ll likely see it a lot. Fortunately, there are numerous libraries that support XML for us We'll use the library built into wxWidgets, since it is already there and is one ofthe easiest libraries l haVe found to use It also handles the encoding for us. Creating XML To write an XMLfile, We need to build an XML document in memory, then save it to disk Add this line of code to be beginning ofCCity"Save()' // Create an empty XML document wmelDocument xmlooe; To use the XML library, you need to add this line to CCity cpp it include "wx/ xml/ xml . )1" You'll need to add this in several places Ifyou get errors that it can notfind XMqunctions, then you need to add this header lfyou are using ‘ I recommend adding this line to prech and rebuilding it a Be sure this at least compiles so you know you have your headers right. We need to add a root node to the XML document. Add this code to create a root node named city // Create a root node wmelNode “root = new wxfinlNode(waCMI-_EIEMENT_NODE, L"city“); xmlDoc.SetRoat (root) ; Each tag is considered an XML node In the above example, each city and tile tag is a node when the document is in memory. The tile nodes are children ofthe city node The city node is the root node. Add this code to save the XML document // And save the file to disk xmlDoc . Save (filename . c_str ()3 ; E Run this and do a File/Save As... and proVIde some filename. Look at the file it created. It should look like this. <'?)un1 version=“1 .0" eneading="utf—B"?> <city/> This created an empty cityfile. We are notyet saving tiles, so the tag was empty. We‘re going to really take advantage of inhentanceto save our tiles. Add this public virtual function to CTile: wmelNude ‘C'l'ile: :XmlSave () l // Create a new node for the tile wxxmlNode *nade = new wmnlNodE(wm_EIMNT_NODE, L"tile“) ,' return node; l You'll need to include wxlxml/xml h in CTile h Be sure you make the function virtual. This is a function that creates an XML node With the name “tile” We‘ll ask each tile to create an XML node for us. We now have a funrition in CTile that Will create an XML node The nodes We create need to be children ofthe <city> node You do this by building a singly linked list of nodes We Will set the child of root to one node, then each node‘s next child Will be set to another node Add this code to CCity::Savel) al'terthe root node is created, but before we save the document: wmelNode *lastChild = NULL; for(list<C'l'ile *>: :const_iterator t=mTi1es.begin(); trmmilesendn; t++) t I] Create a node for the tile wmelNode *node = (*t)->Xm13ave(); II If we have a previous child, add this node after H the child. if(1astChi1d = NULL) { root->AddChi1d(node) 7 } else I lastChild—>SetNext (node) ,- } lastChild = node; Be sure you understand what this does and how it creates a linked list. Run this. Drag a few tiles to the city and do a File/Save As Then look at the generated cityfile It should look something like this: <?x.ml version="1.0" encoding="utf-8"?> (city) <tile/> <tile/> <ti1e/> <lcity> We created a <tilef> node for each tile Read the code above carefully, perhaps drawmg the nodes it is creating on paper The first node it creates as it iterates over the nodes is added as the child ofroot. Then lastChi/d is set to that node. The next node is added as SetNext for the preVious node and so on, creating a singlyelinked list of nodes. We want to set attributes on the tile nodes Whatdoes CTile know') It knows the x,y location forthe file. We‘ll add that information to the XML node. Add this code to CTile::XmlSaVel) alter the node is created node—>AddProperty (L'lx'l , waString' node->AddProperty (L"y" , wxstring ormat (L"%d" , mm) : ormat (L"%d" , mYH .' This sets two properties x and y XML is a text format We haveto convert any numbers to strings to save in the file There are many ways to convert a number to a string that XML can output In this case I have used the wxWidgets watring::Format fundion, which Works a lot like printl, only the output is a Unicode string. Vou may need to convert other numbers as well later on, so be sure you know what the code above is doing E Run this. Drag a few tiles to the city and do a File/Save As Then look at the generated city file lt should look something like this: <?.imil version="1.0” encoding="utf-B”?> (city) (tile x="279" y="217"/> <ti1e x="155" y=”248"/> (tile “"495” y="310“/> <fnity> The only thing we still need is to be able to tell what type oftile we have saved. Right now they all look the same In the file l can‘t tell a grass tile from a blacksmith shop tile. Add this public Virtual function to CTileBlank: /* * Name : C'l'ileBlank: :XmlSaven * Description : Create an XML node and save the information about * this tile into it. */ wmelNode *C'l'ileBlank: :Xmlsave () l wmelNode *node = CTile: :XmlSave”; return node 7 We diScussed this syntax in class. When the fundion XmlSaye is called on CTile where the underlying object is adually of type CTileBlank, this funflion will override the version in the base class But, the call to CTile::XmlSave() allows us to still call that function This is handy here, since we let CTile XmlSaveO do its work, then weJust add more stutfto the node. We need an indication of type, so add this code to CTileBlank XmISaveO (do you know where?): no de — >AddPrope rty (L " type " , L"b1 an): ") ,- n Run this. Drag a few tiles to the city including blank and grass tiles and do a File/Save As... Then look at the generated .city file. ll should look something like this: <?.imil version="1.0” enooding="utf-E”?> <city> (tile x.=“124" y="124“ type=“b1ank"/> <ti1e x="248" y=”217"/> (tile x.="310" y="24B"/> (tile x.=“124" Y="372“ type=“b1ank"/> <lcity> Note that we only got the type attribute for nodes that We did add ourselves Now, you are responsible for adding this capability to your other node types grass and blacksmith shop E Run this and be sure it is saying all tile types correctly A File Open menu option We are saying. Now we need to openthe files. Add a menu option. File/Open. and a handler CFrame..OnFileOpen. Add this function to the city for loading: y:- * Name : CCity::Load() * Description : Load the city from a .city XML file. */ void CCity::Load(const std: :wstring .ifilename) l l Now, add this code to CFrame OnFileOpenO wxE'ileDialog dlg (this , L"0pen File" , L”" , L"" , L"* . city" , waD_0PEN I waD_E'II-E_WJST_EXIS'I) ; if (dlg. Showflodal 0 != waD_0K) return; wstring filename = dlg.GetPath() .wc_str(); mCity.Load(fi1ename) ; RefreshU 7 This does the file dialog box, but parameterizes it for open instead of save. Then weJust call a Load function in the city. Note the Refresh to ensure Window is redrawn after we load new data E Run this and be sure the open file dialog box comes up and that you are reaching the CCity::Load() function This won‘t do anything, yet. A Clear procedure Whenever we load data into the city, we need to clear out the old data first. Because we also need to do this when we des1ruct, it makes sense to create a single fundionto clear the city. Add this public function to CCity: /:- * Name : CCity::Clear() * Description : Clear the city data. */ void CCity: :Clear() l ) I‘ll leave it up to you now to fill in the body of thisfunction. Vou should make the destruclor call this instead of duplicating the clear code here It's very cmmonfor applicators like ttiisttia'l load dalafrornfiles to have a Clearfunchon. I otten write one somewhat aiilmriatirally instead (if wnlJrig a desli'uclor, since I know [It otteri need it Opening the XML document Add this codeto CCity Load() HmelDocument :milDoc; if ( lamilDoc. Load (filename . c_str() )) l wstringstream str; str << L”Unab1e to open file ” << filenaine << ends; wxMessageBoxtstr.str() .c_str() , L"Error", waK | waCON_ERROR)7 return; // Clear our existing city Clear() ,' I put in code to error check that the load was successful. lt would be good practice to do so for the save as well, but l‘m not gorng to worry about all of these details in this assignment. You will need to #include <sstream> to use wstringstrearn. This code opens an XML document and loads the file into it, lfitfails, it pops up an error message box and returns, DtherWise, it clears the city, We are now ready to load the city data. Run this and be sure it is opening the file okay, We traverse the linked list of children oftne root usrng this code that you should put at the end of CCity::Load(): wmelNode *child = xmlDoc.GetRoot()->GetChi1dren() ,- while(child != NULL) t // Move to the next child child = child—>GetNext0 f- This should look familiar, ltgets a pointerto the first child node and then continues following the next pointers until we are done, Add this code to the interior ofthe traversal loop before the child : Cl’llldJGEtNEXfl) line // This is the tile we will create CTile *tile = NULL; // We have a tile. What type? watring type = child->GetPrana1(L"ty‘pe", L"")F if(type = L"blank") ( tile = new C'l'ileBlank(this)i' else iftty‘pe = L"blaclcsmith—shop") { tile = new C'l'ileBlacksmithShop(this); else if(ty'pe L"grass“) { tile = new C'l'ileGrass(this); } if(tile != NULL) ( m'l‘iles.push_back (tile) 7 } This allocates a node of the proper type depending on the value of the type attribute You get the value of an attribute using child»>GetPropVal(), The first parameter is the attribute you are looking for The second is a default value that Will be returned ifthe attribute does not exist mom have waves me pmpertyvalue mm a wsmng’ bm’ 5mm we are my damg em ‘mmemate campare’ lyust left it in a watring Vou are welcome to use watring ifyou like in your programs in this class The type determines what objectto create Be sure you know what this code does You‘ll need to add to rt later on We need to be sure the tiles are in sorted order when done, so add this line to the end ofCCity::Load() // When done, sort the files SortTiles U i' We are not yet done, This does create the tiles, but itdoesn‘t read the attributes associated With the tiles otherthan the type, Specifically, itdoes not yet read the x and y location for the tile, Where should that code go? You might want to put rt here, butdiliferenttiles may have different attributes. lt‘s betterto give that responsrbilityto the tiles themselves. Add this Virtual public member function to CTile: /: * Name : CTile::XmlLoad() * Description : Load the attributes for a tile nude. This is the * base class version that load the attributes common * to all tiles. Override this to load custom attributes * for specific tiles. */ void C'l'ile::XmlLaad(wmelNoi:‘le *node) t m}! = westel(node->GetPrepVal(L"x", L“0") , NULL, 10) ; mY = westol(node->GetPropVal(L"y", L"64") , NULL, 10) ,- } The property value is in a Unicode string of type watring We need to convert that to a number For this, l'm using wcstol, which is "wide strong to long“ The first argument is the string to convert The second argument can be set to a pointer to a pointer to allow scanning to continue from that point. We are just using NULL since we don‘t need that feature. Thethird option is the base. We‘re using base 10. To call this, add this line to CCity Loadt) right before the call to mTrles pushiback(tile) tile—>Xmanad (child) ,- At this time load and save should be fully functional I have not overwrittenthis tuncticn inthe base clam, since none O‘Hth have specific dale we needtd rad That willchange as you do your part dtthis assigrmerit rim.“ “ mg, Is this cool or what? l. Time lwould like for our city to have the concept of time and lthrhk it would be neat if it would keep track of time eVen aiter being closed and reopened We‘re going to keep track of time wrth a 64 bit number that is the number of milliseconds since January l, 1970 l think someone considers this the birthday of Ul'llX or something lts oiten called the Unix Epoch lt is a common time measure in Unix systems, wxWidgets has functions to support this time format easily, lwant each tile to know when rtwas created, Add this membervariable to CTile: waong-Lang mCreatedTime; The waongLong type is a 64 bit type that works crossplatform, since not all platforms support 64 bit types, Vou can subtrad; waongLong values to determine the amount of time that as pas5ed and you can get that value into a regular integer using the ,Long() member function, as We shall see, Add this code to the CTile constructorto set the time mCreatedTime = wxGetLucal'l'imeMillis () 7 T j is Will work great as we are creating our city, but what ifwe save and load? Add this line to CTile::XmlSave to save the time as a property‘ node->AddProperty (L"time" , mCreatedTime . ToString () ) ; Run this and be sure it IS saving the time in the XMLfile. lt should look something like this (different numbers, of course): <'?x.m1 versiam"l.0" encading=“utf—B"?> <city> (tile x.="217“ y="248" time="1264382921330" type="grass"/> (tile x="124" y="248" time="1264382921360" type="blank"/> <ti1e x="310" y="279“ time=“1264382921370“ type="b1acksmith—shop“/> <tile x="186“ y="403" time=“1264382921390“ type="grass"/> (Icity> Now We need to load this Add this code to CTile XmlLoadO if (made —>HasPrap (1.“ time") ) t wstringstreem str(node—>GetPrapVal (L"time", L"") .wx_st:r()) ; long long unsigned int time; str >> time; mCreatedTime = time; } You'll need to #include <sstream> and using namespace std; but l hope you‘re starting to figure that out on your oWn "long long unsigned int“ is a type in C++ on the platforms We are using and the extraction operator Works to read itfrom a stream: Run this and be it works How can you know if it's loading okay? Load a file and save it as a new name The times in the two files should be the same in this Simple structure, the age ofsomething is Since itwas created and the clock runs even ifthe City is not loaded. l‘m perfectly happy With that approach for this step, stnce making the clock only run when the City is open would require a bit of extra logicthat‘s not really germane to the course: But, ifyou want to make the clock Work that Way, feel free to do so: lt‘s a little bit ofa challenge, though not much: Hint: save the age in the file instead ofthe actual time An Animated Tile Okay, here‘s a bit of Workfor you to do: Create a new tile type for thewindmill. The file to display is windmill1.png. Create a class CTileWindmill and make it Work like the othertiles. Be sure you have it saying and loading okay. You‘ll need a new class for it, new code in CFrame to create it, and new code on CCity :Load to load it The Windmill tile is a little bit different from the otherfiles Change the line to display it in CTileWindmill::Draw()to: dc.DrawBit.map(*mWindmi11, Getxt) - 95, Geth) + 32 — mWindmill—>GetI-Ieight(), true); The only difierence is the 96 instead of 64: This is because the windmill file is wider to accommodate the larger image Use 96 ONLY for the windmill tile, not for any other tiles unless specifically indicated: Use64 for the Coal Mine tile later in this step, tor example. Run this and be sure it Works There are actually three Windmill images Windmillt png, Windmill2 png, and WindmillS png lfyou play them in sequence, the Windmill turns: Add this constant to CTileWindmill: static const: int NumberOfImeges = 3,- The static keyword Just means that this variable is associated With the class rather than an object it is a global constant in the class namespace Change the member variable in CTileWindmill that contains the bitmap to and array: waitmlap *mWindmi11[NumberOfImages] ,- Replace the constant that defines the file names in CTileWindmill cpp With this: Genet: wstring TileWindmillImagelN-ame(L“wind.mi111 .png“) : Genet: wstring TileWindmillImageZName(L“wind.mi112 .png“) ; const wetring 'l'ileWindmillImageSNeme(L"windmi113.png"); Change the constructor body to this: mWiniimil-‘l. [0] mWindmil-‘l. [1] mWindmill [2] city—>GetCachedImage (TileWindznillImagelN-ame) 7 city->GetCachedImage (TileWindmillImageZName) ; city—metcachedlmage (TilewindmilllmageSNeme) ; And change the code in CTileWindmill Drawtlto waitmap *windmill = mWindznilJ-[O]: dc.DrawBitmap(*windmill, GetXO - 96, GetYO + 32 - windmill->Getfleight0, true); This should run, but not look any different, yet: Try changing the values in dc DrawBitmap to see the other bitmaps Age and Time We‘re going to animate our Windmill by keeping track ofhow old it IS: Now, We couldyust call WxGetLocalTimeMillis()to determine the current time, but that is a system call and is rather expensive ifyou do it a lot Also, We want to always draw based on one point in time: So, let‘s let the City keep track ofthe current time: Add this membervariable to CCity waongLang mCurre nt Time ,- And add this public access function to get to it: waonchmg GetCurrentTimeU Const (return mCurrentTim27) We need to initialize it in the CCity construCtor so it always has a valid value in it: mCurrent'l'ime = wxGethcalTimeMillis 0 ,- Add the same line as the first line in CCity :OnDraW() so the time is read right before We draw everytime mCurrent'l'ime = wxGetLacalEl'imeMillis () ,- Now, the ctty knows the ttme Let‘s add the abtltty to determtne the age, Add thts memberfunctton to CTtle' h; * Name : CTile::Get:Ag-e() * Description : Determine the age of this object in milliseconds. */ int C'l'ile: :GetAgen const ( return (mCity->GetCurrent'l'ime() - mCreatedTime) .ToLongt); i Animating the Windmill Replace the first ltne of CTtlethdmtll'Dran wtth thts code: int age = GetAgeUF age /= 150; // Divide by 150 milliseconds waitmap *windmill = mWindmill[ag-e % NumberOfImag-es]: Thts should run, You won‘t see the wtndmtll turntng But, grab any ttle wtth the mouse and drag It around, Then you should see the wtndmtll turntng Why ts thts worktng thts way“? Age ts the age ofthe windmill tn milltseconds, lfl dtvtde by 150, tt becomes the age in 150 milltsecond tntervals t can mod that wtth NurnberOflmages to sequence through the tmages tn the order 0, t, 2, 0, t, 2, A Timer Event The wtndmtll ts turntng tn a ytrtual sense, butwe do not see tt because the wtndow ts not redrawtng regularly. To make the wtndow draw regularly, we need to call Refresho regularly. To do thts we‘ll create a trmerevent. Add a new td: ID_Ttmer to the Ids enum tn CFrame. Mtne now looks ltke thts: enum Ids {ID_Exit=l, ID_Abaut, ID_Count'l'iles, ID_FileSaveAs, ID_E‘ileOpen, ID 'l'imeri.‘ Add thts member vartable to CFrame waimer mTimer; Add an tntttaltzer to the CFrame construCtor for the watmer object CFrame::CE‘rame() : wxE‘rame( NULL, *1, L"wxwldgecs Application", wxPoint(20, 20), wxsizeuOZLBOOJ J, ml'imer(this, ID_'l'imerJ Add thts event handler that does the refresh: /a * Name : CFrame: :OnTimerU * Description : This function is called on a regular basis to invalidate * the window, allowing for animation. */ void CFrame: :On'l‘imer(waimerEvent Sevent) ( Refresho ,- ) Add the event handler to the event table EV‘l'_T HER ( ID_El'imer , CFrame: :OnTimer) F nally, add code to the CFrame constructorto set the ttmer mTimer. Start (30) : BTW Shanta mm and me ammamn Shuutd ptay, The 30 means OnTtmerwtll be called once every 30 mtlltseconds, lfyou are workth remotely, that may create too much communtcattons bandwtdth to be usable Consider trying a larger number, tnstalltng Ltnux on your own machine, or worktng tn the labs, lfyou have problems shutttng your ctty down, constder addtng commands to stop the ttmer to the CFrame OnExtt()functton: m'l'imer.Stop() ; A Visitor class Step 2 asked you to count the number of btanktttes. Most ttkety the way you dtd thts was to add a vtt'tuat functton to CTtte somethtng ltke thts: virtual bool IsBlank'l'ileO const {return false;} Then you overrode it in the blanktile class to return true That was what I expeCted for that step, However, the bad thtng about thts approach ts that you had to modtfy the base class to suppon this feature, What ts you want to count other types ofttles’? What tfyou have spectal operattons you want to do ltke computtng stattsttcs on yourfac'tortes or surnrntng the output ofyourwtndmtlls overttme? Do we create a vtnual functton for every posstble case and do we change our classes everyttme we need a new capabtltty? There has to be a betterway, There tsl it‘s called the Vtsttor Pattern, You can find tt begtnntng on page 331 ofthe Gang of Four book, it ts gotng to make these features easy to add Avtsttor class allows us to create an objectthatwtll be sent to all of our ttles as a vtsttor Each ttle wtll then askthe vtsttor to do any work tt needs done forthat vtsttor and for the type ofthatttle, Create a new class called CTlieVlSltOl. Add this code In CTlieVlSltOf.“ before the class is declared: class C'l'ileBlank; class CTileBlaeksmithShap; class C'l'ileGrass; class CTileWindmill; These are forward references to our dtfferentttle classes, We don‘t need the whole class,yust a reference to know tt extsts, And, this header wtll be tncluded tn CCtty, so tt can not include any ofthe ttle headers, stnce they, tn turn, tnclude CCttyh Now, add these publtcvtrtual functtons virtual void VisitBlanktC'l'ileBlank *tile) {i virtual void VisitBlacksmithShop(C'l'ileBlacksmithShop *tile) {} virtual void VisitGrass(CEl'ileGrass *tile) H virtual void VisitWindmill (CTileWindmill *tile) (} Now, make the default constructor proteCted to force thts to be an abstraCt base class. Adding Accept Functions Add thts publtcvtrtual funcrton to CTtle: virtual void Acceptvisitor(CTilevisitnr ’visitor) = 0; This is the accept function we Will call With our VlSllOl. Now add this publiCVinual function to CTileBlank: void C'l'ileBlank: :Acceptvisitor(CTilevisitor *visitor) l visitor->VisitBlank (this) F I Add an AcceptVisitorfunction to CTileGrass, CTileElacksrnithShop, and CTileWindmill, in each case, call the appropriate Visitorfunction, Adding Accept to the City Add this function to CCity: e /* Name : CCity::VisitTiles() * Description : Visit all tiles with a visitor class. v: void CCity::visitEl'iles(CEl'ileVisitor *visitor) ‘ for(list<CTile *>: :iterator t=mTiles.begin(); t!=mTiles.end(); t++) { (’t) —>Acceptvisitor(visitor) ; ) A Concrete Visitor Create a new class CVisitorBlankCounter derived from CTileVisitor Add an Integer rnembervariable ant and initialize it to zero in the constructor Add this access funcuon int GetCountO Const {return ant:i Add this publicvu'tual function to CVisitorBlankCounter: /* * Name : CVisitorBlankCounter: :VisitBlankO * Description : Handle a visit from a blank tile object. We are counting them. */ void C'VisitorBlankCounter: :VisitBlank (CTileBlank ’tile) l ant-H-F 1 Using It Somewhere you should have code that counted the blank tiles. Replace that With this code: CVisitorBlankCounter visitor; mCity.Visit-.Ti1es“visitor-J ; int cnt = visitor.GetCount() i' This should run and count tiles as before, Feel free to remove that stu‘ffwe had before for counting, we now have a betterway, Your Programming Tasks Your programming tasks, and what you Will turn in, are 1 . Create a menu option that displays the average age ofall tiles in seconds, You won‘t need a Visitor class for this functionality 2. Add a concrete Visitor that determines the average age ofall ofthe Windmills only (in seconds) and create a menu option to display it, The function to compute the average Windmill age must use a yiSitor and should look something like this: void CFrame: :OnStepAverageWindmillAge (waommandEvent ievent) l CTileWindmillAgeVisitor visitor; mCity .VisitTiles (fivisitor) ; int angg'e = visitor.AverageAg-e(); wstringstream str; str << L"Average age of windmills in the city is: " << angge << ends; wxMessageBox(str.str(J .C_str() i L"Astounding Information" , Vlon I waCON_INFORMATION, this); Hint The difference between the Visitor that counts the number ofblank tiles and this Visitor is that this one has to call a function on the Windmill tile. You‘ll need code that looks something like this: void CTileWindmillAgeVisitor: :VisitWindmill(CTileWindmill *tile) l int tileAg'e = tile—>GetAg'e() ,' // More code you have to figure out... You Will most likely get an errorthat looks like this: . ./CTileWindmillAg-eVisitor.cpp: In member function iatsvirtual void CTileWindmillAg-evisitor: :VisitWindmill(C'l'ileWindmill‘)i . .ICTileWindmillAgeVisitor.cpp:25: error: invalid use of incomplete type ia‘éstruct CTileWindmillia‘é . ./CTileVisitor.h:14: error: forward declaration of igléstruct CTileWindmillia‘é The second line (the first error} tells you everything you need to know You are using CTileWindmill (calling a function on it), Without it being declared other than the forward reference in CTileVisitorh This tells you that you need to #include “CTileWindmillh” in CTileWindrnillAgeVisitorcpp, 3. Add a new tile type Coalrnine, The behaVior ofthe coalmine is as follows There are four images: coalminerempty png, coalrninerlow png, coalminermedpng, and coalminerfullpng, When a coal mine is created, it should display coalminerempty png After 10 seconds, it should display coalminerlowpng indicating 100 tons of coal is available After to more seconds it should display coalminermed png indicating 200 tons of coal is available, After another 10 seconds it should display coalminerfull png indicating 300 tons of coal is available, lllElE snuulu UH H tup lEVHl lllHllU EHllEU bullllllElLE Wllll an uullull rlHUl LUHl L/lluublllg lllHl uptlull lb EquVHlEllt lU bEllUlllQ H tlUEK tU HVEly Lqu llllllE Wllll H LHVHLHY UI IUU tullb {H Ulg HULK]: ll H Lqu llllllE lle JUU tullb Ul {Lqu HVHllHUlEY tllE Hllluflllt Ul HVHllHUlE Lqu decreases to 200 tons and the lmage changes pack to coalmlnemed png: lfa coal mlne has 200 tons ofcoal avallaple, the amount of available coal decreases to 100 tons and the Image changes back to coalmlne7luw png lfa coal mIne has 100 tons of coal avallaple, the amount of avallable coal decreases to O and the lmage changes back to coalmihe-emptypng: lfa coal nnne has he coal avallable, do nothlhg: Afier hauling coal, the coalmlne Wlll then contlnue to mlne Ul'ltll n is full agaln When you haul coal, pop up a message box that Indlcates how much coal was hauled: An example: Assume the followmg thlngs happen at the speclfied tlmes 1n mlnutes and seconds: 10:20 - | create coal name A 10:25 7| create coal mlne B 10:30 7 Coal mlne A‘s lmage changes from coalmlneemptypng to coalmlne7low.png and 100 tons of coal l5 avallable (from that mlne). 10:35 7 Coal mlne B‘s lmage changes from coalmlneemptypng to coalmlne7lowpng and 100 tons of coal l5 avallable: 10:37 7| create coal mlne C 10:40 - Coal mlne A‘s lmage changes to coalrnlne-n'redpng and 200 tons of coal l5 avallable 10:45 7 Coal mlne B‘s lmage changes to coalmlnemedpng and 200 tons of coal l5 avallaple 10:47 7 Coal mlne C‘s Image changes to coalmlne7low and 100 tons of coal IS avallable. 10:50 7 Coal mlne A‘s lmage changes to coalmlneiullpng and 300 tons of coal l5 avallable: 10:52 7| selectthe Haul Coal open Coalmlne A‘s lmage changes to coalmlne7medpng and We haul 100 tons of coal, leaVlng 200 tons Coalmlne B‘s lmage changes to coalmlne7low png and We haul 100 tons olcoal,leav1ng 100 tons Coalmlne C‘s lmage changes to coalnnne-ernpty png and we haul 100 tons ofcoal,leav1ng none The total amount we hauled was 300 tons and we report that amount: - 11:02 - Coal mlne A‘s lmage changes to coalmlne-fullpng and 300 tons of coal l5 avallaple: Coal mlne B's lmage changes to coalmlne—med png and 200 tons of coal l5 available Coal mlne C's lmage changes to coalmlne-lowpng and 100 tons of coal l5 avallable. NOthE' The age ofthe coal mlne does not reset when we haul coal, only the mlnlng pehavror You Wlll have to keep track oftwo dlfierent ages, the age Sll‘lCE creatlon and the age Sll‘lCE the last tlme coal was hauled Be sure save and load wurk ll'l all cases: ...
View Full Document

This note was uploaded on 12/12/2010 for the course CSE CSE 335 taught by Professor Owen during the Fall '10 term at Michigan State University.

Page1 / 8

Step3 - CSE 335 Step 3: Files, Time, Animation, and...

This preview shows document pages 1 - 8. Sign up to view the full document.

View Full Document Right Arrow Icon
Ask a homework question - tutors are online