| |||||||||||||||||||||||||||
|
| |||||||||||||||||||||||||||
Print This Article REALbasic University: Column 034
RBU Pyramid VIIIn our previous lesson, we added the ability for a sound to play when a card is clicked. But not everyone likes sounds -- some find them annoying. So before we go any further with sounds, we'll add in a control so the user can turn sounds on or off.
Adding Sound ControlThe sound control we'll add is a simple toggle switch: we'll use a basic sound on/off graphic (included in this week's project file). The two graphics are sound.pct and nosound.pct -- drag them from the Finder into your project window. Note: to keep things organized, it works best if you put your imported sounds and graphics inside a special folder inside the folder your project is in. I call mine "Linked Resources" but you can name yours whatever you want. REALbasic will look inside that folder for those resources in the future. Remember, RB doesn't store sounds and graphics inside your project file: it only maintains a link to the original file on disk. Drag a BevelButton control onto gameWindow. Give it the following settings (be careful -- there are a few subtle but critical changes in this list of properties): ![]() Now let's add some code to prevent sounds from being played if the toggle is set to off. Open the playSound method we added last week and insert this at the top (before any other code): if soundBevel.value then Now run the program: when the sound toggle is set to true, that means the sound is off (no sound). When soundBevel is false, sound is on. Our little check code above simply returns from the playSound without doing anything if soundBevel.value is true. To get this to work right, we need to make sure the soundBevel icon is correct. Let's add a new method called updateSoundIcon to do this. In it, put this code: if soundBevel.value then Excellent. Now we just need to put in two calls to that method. For the first, go to the Open event in gameWindow and type in updateSoundIcon. Then go to soundBevel's Action event and put in updateSoundIcon. That way when the program is launched it will update the state of the icon, and whenever the icon is clicked (toggled) it will make sure it has the correct picture.
Adding a Scoring SystemAn important part of any game is the ability to track a player's score. With Pyramid, we need to track two numbers: the player's score (as calculated by the game) and the number of pyramids the player solves (clears). Earlier in this process we created a global variable gScore to hold the player's score, so now let's an a property to count the number of pyramids completed. Open globalsModule and add a new property (Edit menu, "New Property"): gPyramids as integer. Now we need a place to display the score. For this, I could just use a simple staticText object; after all, we're just displaying some text, not graphics. But a staticText has two disadvantages. First, it flickers when you update it. Second, it's very plain. If we instead use a canvas and draw the text manually, we're free to embellish and enhance the graphical display as much as we'd like. For RBU Pyramid, we're just going to use a simple display inside a canvas object, but this could easily be changed to be prettier in the future. For instance, imagine drawing the score in LCD-like lettering: that'd be cool. So let's drag a canvas onto our gameWindow. Give it the following settings: ![]() Press Option-tab while selecting scoreCanvas to open the Code Editor. Within scoreCanvas' Paint event, put this code: dim y as integer As you can tell, this is a mud simple routine. We simply set our font, text size, and color and draw the text. Note that I don't "hard code" the vertical drawing position of the text -- I use the variable y to store that information. Why do I do that? Simply because it's more flexible: it makes it possible to adjust the size of the text without having to recalculate the vertical position. (Of course, if you make the text too large, it won't fit within the confines of our canvas.) That done, let's add code to actually track the player's score and redraw it. Go to the updateCards routine. At the very beginning, let's add the following line with some new properties (variables): dim count, bonus as integer Now at the bottom of the same routine, let's add the following (precede it with a few blank lines): // See if pyramid has been won The first part of this (with the count variable) is what checks to see if the user has completed a pyramid. We do this by counting the number of visible cards. If they're all invisible, the user has completed the pyramid. Once we've figured out the user has completed the pyramid, we calculate the player's score. We play a "win" sound, add one to gPyramids, and figure out the player's bonus. The bonus calculation is unique to RBU Pyramid (it's not based on any official rules or anything). I basically wanted the bonus to be higher the more pyramids are solved in a row, so I add two points for every pyramid solved. Since it's more difficult to solve a pyramid with only one shuffle of the Deck, I double the bonus if the player managed to clear the pyramid without reshuffling (gFirstTimeThrough is true). Finally, the bonus is added to the score, we deal a fresh set of cards, and the score is refreshed (redrawn). Be patient -- we're almost done. We just need to update our sound playing routine to play a sound when the player wins (clears a pyramid). Go to the playSound routine and insert the following into the select case statement: case "win" If you use a different sound than my applause file, change the name of the sound in the above to match your sound's name. If you want my sound file, it's located within this week's download -- just drag "APPLAUSE LOOP" to the project window. If you would like the complete REALbasic project file for this week's tutorial (including resources), you may download it here. Next WeekWe'll add a preference system to RBU Pyramid so we'll be able to save the state of things like the sound on/off setting.
LettersTripp Mullins writes:
Interesting problem, Tripp. I don't know of a resource off hand, though presumably there are some textbooks and algorithms on the net that would help with this situation. I'd look for other calculator projects and see if someone else has done something similar. Even if they aren't done in REALbasic, the actual method they use to solve the problem would be similar, and it might give you some ideas of how to approach the problem. The core of the problem to me appears to be converting the string fraction into numbers that you can work with. Obviously, the problem is simple once the values are converted to numbers (since fractions are just division). One possibility would be to break the input into multiple fields. This is perhaps more work to set up and ugly from the user's perspective, but it's easy to code (just convert the fraction fields to numbers and divide). ![]() The other approach is to use string manipulation to figure out which portions of the number are fractions and then convert those. This isn't as hard as it seems. For instance, without the complexity of mixing feet and inches in the same field, let's look at a separate inches field that accepts a whole number and a fraction portion. Like this: ![]() Here's a rough look at the conversion code:
I won't get into dreadful detail here, but you can see how we step-by-step break the string into various portions and convert those to numbers. We use the inStr function to find the first occurrence of a space -- that means everything to the left of that is a whole number. Once we've trimmed off the whole number portion, we can concentrate on the fraction, which is pretty easy as we simply find the slash ("/") and save each number into a separate variable. Obviously it gets more complicated if you want to mix feet and inches and parse for " and ' marks, but maybe this code gets you going in the right direction. The biggest problem with this kind of problem is anticipating all the bad inputs users might type in. What if the user doesn't put a space before the fraction? What if they forget the foot or inch mark? What if they include letters? What if they put a slash at the very beginning or put a space after the slash? On the one hand you can say "garbage in, garbage out" -- the user gets whatever they put in. But then a good Mac programmer will try to make these errors difficult to input. For instance, you could make the editField not accept letters. It all depends on the type of user you'll have and the amount of time you want to spend coding for rare but possible circumstances. BTW, if you want the above fraction project file, I've uploaded it here. I haven't thoroughly debugged it, so it might have errors, but it should be educational to play with. Next, we hear from Daniel Price, who writes:
You're probably just looking in the wrong place, Daniel. The folderItem object includes a createResourceFork method: you just pass it the file type of the file you want to create. It will create the file and erase any existing resource fork (if there is one). Once the fork is created, you can use standard resource fork commands to manipulate the contents of the fork (create/delete resources, etc). Here's a screen shot of the online help describing the command: ![]() (I don't have a copy of RB 1.1 but I'm sure that command was there as I used resource forks way back when I first started with RB.) That said, you might think about using a binary file instead of a resource fork. While I love them, Apple seems to be phasing them out in Mac OS X (though they are still supported). Also, using resource forks mean your file can never be moved to another platform (such as Windows). Right now you may not be interested in creating a Windows version of your program, but down the line you might be. If you go with a binary file, others won't be able to edit it, but since you mentioned you're writing your own editor anyway, that shouldn't be a problem.
Keep those letters coming! I may not answer your question immediately, but I'll hopefully get around to it in a future column. (If you don't want your correspondence published, just be sure to indicate that when you write. Otherwise I'll assume it's fair game.) About the Column REALbasic University is a weekly instructional column on programming with REALbasic and is brought to you by REALbasic Developer, the magazine for REALbasic programmers. Each week we answer select reader questions, and we're always open to ideas for future columns. Send your questions to . (Keep your questions simple and specific. General queries like "How do I write my own web browser?" will be neglected.) Your question won't be answered immediately, but will be answered in a future column. (If you don't want your correspondence published, just be sure to indicate that when you write. Otherwise it's fair game.) About the Author See the REALbasic University Archives
REALbasic University contents ©2001-2004 by Marc Zeedar and REALbasic Developer. All Rights Reserved.
|
. |
| |||||||||||||||||||||||||