REALbasic University Resources:

RBU: Glossary Defines common REALbasic programming terms
  Archives Previously published columns
Translations: Dutch Courtesy of Floris van Sandwijk
  Japanese Courtesy of Kazuo Ishizuka
  Chinese Courtesy of Dong Li
  RBU Translation Guide Information on Translating RBU into other languages
Books: Matt's Book (2nd Edition!) Ideal for experienced programmers
  Erick's Book Best for beginning programmers
Websites: Mother Ship The publisher of REALbasic
  RB Webring Links to hundreds of REALbasic websites
  RESExcellence Another REALbasic programming column
  REALbasic Developer Magazine The premiere source for REALbasic instruction.

REALbasic University is Sponsored by

Make your Mac do what YOU want it to. Create games, utilities, cool Mac OS X tricks. Download REALbasic now and create your own software.


Print This Article

REALbasic University: Column 052

Zoomer: Part I

Many times I've been asked, "How did you learn all this REALbasic stuff?" My answer is simple: I taught myself.

How do you teach yourself programming? You experiment, that's how. You play. You try things. It takes patience, perhaps some research, maybe even some assistance from someone else. But eventually you figure things out and get your program to work.

Sometimes these experiments are real programs you want or need. Sometimes they're just learning projects, like my little Shooting Gallery game, which I wrote simply to learn about sprites. Sometimes these projects are rather useless on their own: they don't do anything but help you learn a particular technique.

I've got literally hundreds of REALbasic projects like that. That's how I learned. I'd try to get RB to do something, or test a particular feature. So that's your word of warning: what we're going to do today is rather useless. But hopefully you'll learn something.

DrawInto

REALbasic includes an unusual command, drawInto. In earlier versions of REALbasic, it didn't work very well, but most of the bugs seem to be fixed in RB 4.

The online help describes the command like this:

When I first noticed this, it intrigued me. Apparently this would draw the contents of a window into a graphics object. What good is that? Well, since a picture object includes a graphics object, you could draw a window into a picture!

But what good is that? The first thing I thought of was that once you've got the window as a picture, you could draw it larger: basically zooming into the window! This could be cool, I thought. I could have a floating window that acts as a magnifier to a text field. That way you could keep your text at a reasonable size (10 or 12 points) but be able to read it in the zoomed window.

To test this, I wrote Zoomer, a simple experiment. It works pretty good, though I don't know how practical it would be in a real program. But it was good for learning.

Creating Zoomer

Start a new blank project. On the default window, drag on an editField, a Slider control, and several staticText objects. Arrange them to look something like this:

Set the properties of editField1 like this:

If you'd like, put some default text into the editField. That will make testing easier, since it's rather pointless to zoom in on an empty editField!

zoomSlider should have these characteristics:

Now here's a little tip. StaticTexts are rather useless as controls. After all, they just display some information. But if you add each staticText as a separate control, they clutter up your Code Editor window:

But if we give all the StaticTexts the same name, making them a control array, only a single object is displayed in the Controls list, which is easier on the brain.

So I've named all the statics "Label" and let them be numbered in a control array. (Since we're not doing anything with these staticText objects, the actual numbers are irrelevant, except for the bottom one [which has a default text of "4"] since that one we'll change dynamically as the user drags zoomSlider. That staticText needs these properties (especially note that the array index needs to be 3):

Next, we need to create a window for our zoomed view. Go to the File menu and choose "New Window." Give it the following settings:

Guess what? That's all we need to do for zoomWindow! It doesn't even contain any code!

How is that possible? It's possible because everything happens in window1. From there we'll control what's displayed by zoomWindow. The negative side effect of this is that zoomWindow won't redraw properly since it doesn't know how to draw itself. (In a real program you'd want to do this differently, but today we're just experimenting, so this behavior is okay.)

Adding Code

Let's start by adding a couple methods to window1. First, let's create a method called zoomAmount. This method will simply return the current zoom level (set via the zoomSlider control).

Go to the Edit menu and choose "New Method" and give it the name zoomAmount and a return type of Double. Then put in this code:

  
label(3).text = str(zoomSlider.value / 2) + "x"
return zoomSlider.value / 2

What we are doing here is adjusting the value of zoomSlider. We do this because a slider control cannot move in fractions, only whole integers. By setting zoomSlider's minimum and maximum values to double what we want and then dividing the current value by two, we end up with the range we want but with the ability to zoom to odd levels like 1.5x, 3.5x, etc.

The first line sets the staticText display to show to current zoom amount. The second line returns the current zoom amount after calculating it. Simple.

But now we need to make the core of the program. This method is the one that draws the zoomed area. For now, let's just put in an empty method. Choose "New Method" from the Edit menu and call it drawZoom, with x as integer, y as integer as the parameters.

Leave the method blank for now: we'll finish it next lesson. For now, let's go to the Events list within the window1 Code Editor. Find the event called mouseMove and put in this line:

 drawZoom(x, y) 

We've just told the program that every time the mouse is moved within window1, to redraw the zoomed window!

But if the user's typing in the editField, they wouldn't be moving the mouse, right? So let's go to the Controls area, expand the editField1 tab, and go to the selChange event. There we're going to put in this:

  
drawZoom(system.mouseX - window1.left, system.mouseY - window1.top)

Eek -- what is all that?

Okay, first a quick lesson in coordinates. Coordinates are horizontal (x) and vertical (y) values that represent individual pixels on the screen. But there are different kinds of coordinate systems. There's what's known as the global coordinate system: that's the entire screen, including multiple monitors. Then there are various local coordinate systems: those are the coordinates that represent a single window or object.

For example, in the following diagram, the yellow area represents the screen (obviously, a very small screen ;-).

All the x and y values are in global coordinates. But inside the window, the white box, which represents a canvas object, the lx and ly values are local coordinates. In this case, they are local to the window. (Note that this is just the drawing area of the window: the window's title bar is not part of the coordinate area.)

However, within the canvas, if you wanted to draw that red circle, you'd draw at local coordinates relative to the canvas: g.drawOval(10,10,30,30) would draw a circle 30 pixels square at ten pixels in and ten pixels over from the upper left edge of the canvas. Note that the canvas itself is on the window and thus canvas position info, like canvas1.left, would be window coordinates.

All this just means you have to be careful where you get your coordinate information, and be aware of what type of coordinates you are wanting. You may have to translate from one coordinate system to another.

That's what's happening on our situation. Our drawZoom routine, which asks for two coordinates, wants window coordinates. With mouseMove that wasn't a problem: the x and y values passed to the mouseMove event were in window coordinates, so we just passed them right on.

But now, within the selChange event, we don't have window coordinates to work with. Instead, we use the system.mouseX and system.mouseY functions, which return global coordinates. So we must translate those to window coordinates.

The translation is easy: we just subtract the window's left and top properties from the global x and y coordinates. Look back at that diagram. See how the upper left of the window is 42, 77? Subtract that from a global coordinate, like the 240 that's the width of the window. 240 - 42 is 198. So 198 would be the rightmost pixel of the window (in window coordinates)!

In Detail

The numbers in my diagram are approximate: REALbasic's calculations are exact, while mine aren't taking into account things like the window's border. But the general idea of what I'm conveying is accurate.

If you'd like to explore more about coordinate systems, play with this simple test program I wrote: testcoords.rb. It displays local and global coordinates as you move the mouse:

So all we're doing in the selChange event is translating global coordinates to window coordinates and passing those to our drawZoom routine.

Whew! That's enough of a lesson today. Next week we'll get into the actual drawing of the zoomed area (which is somewhat complicated). To give you a taste of what to expect, here's what our program will look like in action:

If you would like the complete REALbasic project file for this week's tutorial (including resources), you may download it here.

Next Week

We finish Zoomer.

REALbasic Developer Magazine Update

A few weeks ago I officially announced REALbasic Developer, the new printed magazine I'm launching this summer. Quite a few of you chose to become Charter subscribers, and I'm immensely grateful and pleased by your support. Charter subscriptions were higher than I projected, which is wonderful.

While the Charter membership offer has expired, we are now offering "Early Bird" subscriptions at a 25% discount. If you're interested in suscribing, you can save money and support the magazine by buying a subscription now. Once we begin publishing in July, subscriptions will be full price.

In other news, we're making great strides forward in this mammoth venture. Authors are turning in some great articles, and we're working hard to make this not just the best REALbasic publication, but a great magazine period. I'll post further updates in this column as we progress.

Letters

Last week, in response to Dr. Ribnik's quest for an RB class that would display info similar to Mac OS X's Column View, I mentioned I wasn't aware of one. As I suspected, one does exist, as Owen revealed to me:

When I read your response to the letter asking about an RB implementation of OS X's column view, I remembered seeing just such a thing. I thought it had been called OpenBrowser or something along those lines, and it was pretty advanced seeming. Unfortunately, I was unable to find it with google. However, I did find ColumnBrowser by Amar Sagoo. It's a very basic version of this view, without any more advanced features (ie, no finder icons of files & folders, no information about a file in the last column when the file is selected, etc.) It is a good basic implementation though, so I thought I'd pass along the info. Here's a link to it (it's the first thing on the page):

http://www.realbasic.com/learn/programmers/Class/ListBox/Premier.html

-- Owen

"In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move." - The Restaurant at the End of the Universe, by Douglas Adams (1952-2001)

Thanks, Owen. Anyone who quotes Douglas Adams in his sig can't be all bad! ;-)

Next, we've got some puzzles from Sven:

How's it going? I just began learning REALbasic recently, I have 4.02 and I am running it on Mac OS X (10.1.3). I am finding RBU very useful so far, even though I have run into some complications, such as my Sprite Animation lesson not functioning, and neither did yours, but in different ways. However my question isn't about that lesson.

I am a Game Art & Design student at the Art Institute of Phoenix, so I constantly am coming up with game concepts galore. I have this project I want to work on that I somewhat developed quite a while ago, and have now completely expanded upon. I have some roots in BASIC, but am having some trouble making the switch to OOP, and it has been some time since I coded anything in BASIC as well.

I have need for some help in doing such: I need to make a prebuffer for my sprites that has the ability to scan a folder within the REALbasic project file, count how many items there are, and find their names, and load them all, prior to their usage. i have tried to implement it in a progress bar, but my code isn't getting what i want, i can only seem to figure out how to grab contents from an outside folder, and then i can't seem to buffer them, but i have the ability to find how many and what their names are.

Also i need some more help in the sprite animation itself, I have use for multiframe objects, say a walking-left set of 3-6 frames or jumping set of 3 frames for example. I need some more in running this. Also can masks be applied to sprites/spriteframes.

Another question, i need to know how one can change the users monitor settings, such as in a games options window. Also I need to know how I can fade screens, and not the quicktime effect of crossfading between two pictures, i need to be able to fade the desktop to black to transition into the program opening, and then use this again for game transitions. Is it possible to tap into the other monitor settings to do this as well, such as dropping screen brightness? Or maybe there is a better means of doing so.

I have a lot of things drawn already, although hundreds more graphics are necessary. I have worked out much for gameplay, and statistic settings and character creation, but i have a long way to go, and i am learning as i go, trying to apply pieces of knowledge from tutorials as i move ahead, but it is frustrating especially when what I've learned isn't enough and I keep trying to jump ahead, and then going backwards...

Thanks for all your help. This game will be a task of all tasks, but i'm trying to work from a small point and work outward.

(in the future i may be asking you to help with the interaction with worldmap and collision detections, because a lot of it cannot be based on what pixels touch what. and also the inventory system which involves the ability to select an icon by cursor and drag it (becoming the cursor/or at least attached to it) and dropping it into an equipment slot (i.e. hand, torso, head, etc.) and have it bring along all of its statistical information and character modification data.)

Thank you for all your help, it will be greatly appreciated.

-Sev Gerk

About my sprite lesson not working: I've heard there are problems with sprites in Mac OS X, so that could be it. There may also have been changes to sprites in more recent versions of RB that cause problems with my older code. I'll revisit sprites again one of these days and get those projects working again.

To your questions: you first ask about pre-buffering and bringing in pictures. I had a detailed answer to a question along similar lines regarding pictures from an external source recently. It was not for sprites, but the principals are the same (since sprites just need a picture object to define what they look like). Read my answer to Charles, in Lesson 043 and see if that helps get you going.

Next, can masks be applied to sprites? You can either set whites to be transparent, or you can apply a mask to a picture and the assign the picture to the sprite. (See the picture.mask in online help for more on masking.)

Finally, your question about controlling the screen settings of a user. You can do this via a Declare statement, but you're probably better off using a plug-in. I don't know where one of these is off the top of my head, but I know I've seen them, so they're available. I'd do a Google search and see what you can come up with. (If another reader knows of a plug-in that does this, let me know and I'll post it here next week.)

As to your future questions on collision detection and such, you're getting mighty sophisticated, and beyond the scope of REALbasic University. I suggest you subscribe to REALbasic Developer magazine, which will have room to cover more advanced topics than I can do here. RBD has a question-and-answer column which will be perfect for those kinds of issues.


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
is an author, philosopher, graphic designer, photographer, film director, soccer fanatic, and programmer (among other things). He writes for MacOpinion, runs his own software company, Stone Table Software, which sells the revolutionary Z-Write word processor, and is Publisher and Editor of REALbasic Developer. He lives in Northern California with his cats, Mischief and Mayhem, and is rapidly running out of free time.

See the REALbasic University Archives


REALbasic University contents ©2001-2004 by Marc Zeedar and REALbasic Developer. All Rights Reserved.

.

.