View this PageEdit this PageAttachments to this PageHistory of this PageHomeRecent ChangesSearch the SwikiHelp Guide
Hotspots: Admin Pages | Turn-in Site |
Current Links: Cases Final Project Summer 2007

Team: Wyld Stallyns

I welcome you, fellow Squeaker. This is my outlet, my canvas, and the manifestation of my experiences in this class during the Fall of 2004. But mostly, it's a write-up of how my group did our project.

More than once, my group members and I described Squeak as "quaint." And it is. Writing code in it is so simple, so you can focus more on what the code is doing, how your objects interact. Usually, that's the hard part. Still, it does grant plenty of opportunities to put that OO knowledge to work and to really see how they can work together, making the most of the OO paradigm.

But enough of that. What follows is a brief outline of what I have written below. I hope you will learn from our successes and failures and use whatever knowledge you can find here to improve your grade.
  1. Designing the Game
    1. Looking Ahead
  2. Dividing Up the Work
    1. Creating the Simulation
    2. Figuring out Wonderland
    3. Building the GUI
[] Here's our code, diagrams, and all that other required stuff. To play our game, just unzip it into your Squeak directory, fileIn the .st file, and type "Game new" in the Workspace. Then "Do It."
[M3-presentation.ppt] Here's the presentation we gave of our initial design.

1 - Designing the Game

Our task was to create a simulation, so we realized early on that how we chose to represent our world would determine the complexity of our engine. Thus, we had a single Campus object which held a number of Places. Each Place had a unique id (actually coordinates of its location in a grid) and held any Person and Thing objects which inhabited it. Simple.
In our original design, Thing was an abstract class which had two subclasses, Item and Producer. We ended up removing Items and Producers since we could have item functionality be handled in Blocks within Thing. But more on that later.

As far as game design went, we chose to have the focus of the game be maximizing enrollment in the virtual college. You could add a new Person to the Campus at any time, but if their individual needs were not met, they would drop out. We also decided that we weren't going to have the user be able to control a Person directly. Our implementation would allow for it if we needed to change that later, but we thought it made things more interesting if the user's interaction with the Sims was more indirect. By supplying a Person with a world filled with Things to satisfy his/her needs and by modifying his/her desires to match those needs, the user could leave that Person alone and focus on micromanaging another Person. For more on the mechanics, take a look at our Powerpoint presentation.

1.1 - Looking Ahead

One thing that was especially nice about this project was that the milestones were already decided before we even started. This meant that we could look ahead, see what would be expected later, and account for it now. In most cases, we had to make very few allowances.

Since we knew we would have to represent the world graphically at some point, we put effort into learning how Wonderland worked. We also knew we would have to save and load our game world, so we looked into the "storeString" Object message and the "evaluate:" Compiler message.

While I'm on the topic, I ought to mention some of the problems we encountered since we decided to use storeString. Since it returns a string representation of the object and everything it links to (including string representations of other objects), it doesn't work on circularly-linked objects. Also, it doesn't work on Blocks. To fix this, we had to destroy and recreate links between objects any time the game was saved or loaded (which is why it takes so long). We also removed many of the links to the Campus object by making all the variables and methods into class variables and class methods. It was a hasty decision that caused our design to be kind of messy. Sure, it worked, but it would have been cleaner to manage the links between objects than to remove them altogether.

This taught us that it's all well and good to be able to use some of the perks of a language, but they shouldn't be an integral part of your design. They should be utilized to make specific tasks easier. In our case, we didn't completely understand how all of them worked, so I suggest that you explore the details of such features all the time, just by playing around with the language. You'll save yourself a lot of trouble later on.

2 - Dividing Up the Work

Everyone in the group needs to take part in the design process and understand the design that comes out of it. Not everyone in the group needs to know everything about every piece of code. That's the whole point of designing it: so everyone can work separately and then piece it back together. Remember abstraction from 1321? If each piece of the puzzle is truly a stand-alone problem, you'll minimize the trouble that frequently arises when it comes time to reassemble everyone's code.

2.1 - Creating the Simulation

The simulation part of our game was captured by the automatic actions taken by every Person in every Place in the Campus. We randomly generated Tasks based on the person's desires. A high desire increased the probability that a Task related to satisfying that desire would be assigned. A person might have multiple related Tasks, such as "find a room with a desk" and "work at the desk" The person would perform Tasks in the order they were received. The only exception to this was the socialize Task, when a person would assign a Task to "stop moving" to another person and then assign the "walk to that person and talk to them" Task to itself. This approach is called a Task Queue, and it worked flawlessly.

The code which handled interaction with Things made use of Blocks. The blocks themselves were passed as parameters to methods which executed them. It actually worked quite well. Here are some examples of Blocks in use:
     testBlockOne := [
Transcript clear.
Transcript show: 'I am in a block.'.
"Other commands can go here."
testBlockTwo := [:param |
show: 'start block';
show: ' ', param;
show: 'end block'.
"Other commands can go here, too."
testBlockOne value.
testBlockTwo value: 'this string was passed into the Block'.

2.2 - Figuring out Wonderland

We found The Squeak Wonderland Tutorial very helpful, but most of our knowledge came from just playing with Wonderland. In fact, half of our team (a total of 2 guys) was devoted to just figuring out how it all came together. Why? Because by utilizing Wonderland, we didn't have to write our own graphics engine, make the graphics, and coordinate it all with the GUI. In the end, it not only saved time but made our project look very professional.

The inclusion of Wonderland extended our design a little bit, and the most sensical way was as follows:
This was extremely inefficient, as it turned out, but more on that later.

2.3 - Building the GUI

The Game object itself created and assembled all of the graphical components we used as well as handling events. Any actions you performed were passed to the Campus, the currently displayed Place, or in cases where the Wonderland was trapping events, to the Person and Thing itself.

As I said before, each Place had its own Wonderland. This slowed down the game a lot, especially when we had random hidden GUI components clogging up Squeak in the background. Having many Wonderlands was bad enough, but if they're not closed properly, they leave random components in the background, so we had to figure out how to get rid of them.

When we were initializing our game and setting up the GUI, we used this code (more or less):
     "gameWindow is a SystemWindow object"
"wonderland is the Wonderland object for a Place"

| cameraWindow |
gameWindow makeUnclosable. "removes the 'X' on the window"
wonderland getEditor hide. "hides the Wonderland editor window"
cameraWindow := wonderland getNamespace at: 'cameraWindow'.
gameWindow addMorph: cameraWindow frame: (0.00@0.05 extent: 1.00@0.90).
By removing the 'X' from the window, the user must click 'Quit' to quit, and the event handler for that button performs all of our Wonderland cleanup. When the user actually clicked on the Quit button, we had to do this:
     Campus placesList do: [:eachPlace |              "iterates through each Place
eachPlace getWonderland release. "frees up each Wonderland"
makeClosable; "makes it so the next command actually works"
delete. "closes the game SystemWindow"
This solved our memory problem, at least to the extent that our design allowed us. If I were to go back, I would create just one Wonderland object for the Campus and manage the WonderlandActors within it.

Link to this Page