Part 6: Cursor Control

In which we start to give the user some control over the application, move the cursor around, and make our first guess with some coloured balls...

Principles of Movement
How It Works, Part One, Playing in the Sand
Picture a children's play pit full of sand. It is perfectly smooth. Now, assuming you were invisible how would you make a small hole appear to run from one side of the pit to the other?

One way to do it would be this. Use your finger to make a hole and let everyone see it. Then, as quickly as possible, fill the hole in and make another one just to the side of where the first one was. If you do this over and over again, really quickly, what will someone watching the sand see?

A hole moving across the sand.

And that's exactly how movement and animation work in a computer program

How It Works, Part Two, Pixelating the Play Pit
So, if we have a blank (white) screen, how do we move a black spot around the screen? Have a look at this snippet of code...

 gUSE id%(9)
 foo%=0
 DO
    gAT 200,foo%
    gCOPY id%(1),0,0,20,20,1 : rem clear the 'older' spot
    foo%=foo%+5
    gAT 200,foo%
    gCOPY id%(1),0,0,20,20,0 : rem copy the 'new' spot
 UNTIL foo%=200

This code uses the basic building block of the DO... UNTIL... loop that increases a foo% counter. The first gAT... gCOPY clears away the old picture we've copied in (the picture being whatever mbm was gLOADED with id%(1) previously), and the second gCOPYs the mbm into the new location.

And that, in a nutshell, is how things move!

(I'll leave the relatively trivial exercise of how you'd adapt this to using a Mask and a Background Image to your imagination - it's not difficult to work out if you read Tutorial 5 closely).

What sort of things can move?
Have a think through the applications and you'll see movement in many different places. As with many of the principles you're seeing in this course, the above can be used in many different places.

Think of the tile blocks moving in Vexed. Think of the moving hand choosing cards in Card Deck. Think of the cursor moving through names and addresses in Contacts. All these use movements and masks - it's not difficult and it looks good. Which always key in a good application.

Displaying the Cursor in Master
As you'll remember, we've broken the writing of our application into small areas to work on. You'll remember that on the game grid, up and down will move an on-screen cursor in the corresponding direction, selecting where to place a colour.

So in essence, we're going to write a small routine to move the cursor!

Where are We Going to Go?
Firstly, we need to know if the up and down cursor keys have been pressed. As this is reading a keyboard event, we look in PROC g_kbddrv:(.........). At the end of the procedure, add in the following code...

 ELSEIF Key&=63593 : rem Cursor Up
    cursor%=cursor%-1
    IF cursor%=0 : cursor%=4 : ENDIF
    m_show_cursor:
ELSEIF Key&=63594 : rem Cursor Down
    cursor%=cursor%+1
    IF cursor%=5 : cursor%=1 : ENDIF
    m_show_cursor:

Okay, so we've introduced a new variable here. cursor% (which we set in PROC init_game: to be equal to 1) keeps track of which row the cursor is currently in (the top row is 1, the bottom row is 4). When we move the cursor up or down, we change the value of cursor% to represent the new row, and then call the procedure that will display the cursor.

The IF... ENDIF statement in the middle checks to see if we have moved down while on the bottom row, or moved up when on the top row. If we have, the value of cursor% is set to the opposite end, so the cursor effectively wraps round the rows.

Showing The Cursor
Once we move the cursor, we call this procedure...

PROC m_showcursor:
   gUSE id%(1) : rem Make sure we are using the main window
      rem *** clear the old cursor away by blanking the square, and
      rem *** copying the ball back into the square.
   m_showball:(turn%,old_cursor%,0)
   m_showball:(turn%,old_cursor%,guess%(old_cursor%))
      rem *** Now copy the cursor mask, and the cursor itself.
   gAT (turn%*36)+5,((cursor%-1)*36)+5
   gCOPY id%(11),36,0,36,36,1 : rem *** Copy the Mask, clearing pixels
   gCOPY id%(11),72,0,36,36,0 : rem *** Copy the cursor into the pixels
   old_cursor%=cursor%
ENDP

Time to Test!
If you were writing Master yourself, then now is a good time to translate and see if the cursor moves up and down. If you're keeping up with Master, have a look at the code at the end of the tutorial and you'll see where the above fits in.

The tutorials cannot explain everything, but I'm aiming to cover the broad principles here, and then hope you look at the downloadable source code at the end of the tutorials to see how it all fits together.

What we are doing in Master is creating a 'toolbox' of techniques that you'll hopefully be able to apply to your own programs.

Making a Guess
For each turn, we are going to hold the temporary guess an array called guess%(4). Once we've guess the four balls, we'll hit enter and see how good our guess is. At the start of the turn, we'll set the four array elements to zero. This is so we can check that the player actually puts 4 colours into the guess (i.e. all four values are non zero).

Left and Right, Red or White?
We've already got our cursor moving up and down, so now we add in the left and right cursors into the PROC g_kbddrv:...

ELSEIF Key&=63591 : rem Cursor Left
   guess%(cursor%)=guess%(cursor%)-1
   IF guess%(cursor%)<1 : guess%(cursor%)=(skill_level%*2)+2 : ENDIF
   m_showball:(turn%,cursor%,guess%(cursor%))
ELSEIF Key&=63594 : rem Cursor Down
   guess%(cursor%)=guess%(cursor%)+1
   IF guess%(cursor%)>(skill_level%*2)+2 : guess%(cursor%)=1 : ENDIF
   m_showball:(turn%,cursor%,guess%(cursor%))

This is going to look pretty familiar to the movement code. You'll see you increase or decrease the value of the guess%() depending on the current cursor% value (1 through 4). Where the value of guess% is more than the number of balls to choose from, it loops back to one, and if it drops below one, then it loops to the highest value.

Remember those Skill Levels
Yes, this highest value is determined by the skill level. The easy skill level (skill%=1) gives you 4 balls to choose from. Medium skill% (2) gives 6 balls, and Hard skill% (3) gives 8 balls.

In the same way we called the show cursor routine, we do the same here with the show ball routine, which we detailed off in the last tutorial. See, it's all falling into place now.

Conclusions
So, here's the OPL code as it stands just now. Copy this onto your Communicator (or into the emulator) and see how exactly we're doing everything.

MASTER is starting to look more and more like the finished product, isn't it? When you get to this part of your own future projects, you'll get a lovely thrill, because it's all working, and on the screen. If you've followed the course up to here, well done.

We're not stopping though. The next part is going to show us how to interpret the guess we've made, and then let the user have another guess.. and another... and another...


Source Code
You can download the OPL source code for Master as it is at the end of tutorial 5 here. You can download the opo program (the runtime file) as it is at the end of tutorial 6 here.

Published by Ewan Spence at 14:44 UTC, August 25th

Section: Articles
Categories: Develop
Platforms: Series 80