Lesson 8:

Detecting hits on the Homescreen

In the previous lesson, we learned how to make an X move around the screen and stop at the borders. This is the simplest form of hit detection there is. In this lesson, I will show you how to use strings, lists, and matrices to use true hit detection, along with a dynamic event script.

Matrices



This is the simplest way to create hit detection, since we can make it fit the boundaries of the screen with very little effort.

First, you need to determine the size of the screen that we will occupy. For this tutorial, we will use the entire 8x16 screen. Now, a Matrix cannot store letters, so we will have to create an interpreter to take numerical values and place a letter designation on the screen. Since we will need to know what will equal what, we will do that first. Here is a list of numbers to letters that I will be using: 1=X; 2= ; 3=V; 4=T

To help simplify things, I will also show you how to use this system to create different areas, or maps. We will need two variables for that, one for horizontal and one for vertical map data. I will designate L as the horizontal map data, and M as the vertical map data. Below is the data that you need, place it in a program called YLVL.

prgmYLVL


:ClrHome
:If L=1:Then
:If M=1
:[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1][1,1,2,2,2,2,1,1,2,2,2,2,2,2,2,2][1,2,2,1,1,2,2,2,2,1,1,1,2,1,2,1][1,2,2,1,1,1,1,1,1,1,1,1,2,1,1,1][1,3,2,2,
1,1,1,1,1,1,1,1,2,1,1,1][1,1,1,2,1,1,2,2,2,2,2,1,2,1,1,1][1,1,2,2,1,1,2,1,1,1,2,1,2,1,1,1][1,2,2,1,1,1,2,1,1,1,2,1,2,1,1,1]]→[A]
:If M=2
:[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1][2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1][1,2,2,2,1,2,2,2,2,2,2,2,2,2,2,1][1,2,2,2,1,2,2,2,2,1,1,1,1,2,2,1][1,1,1,1,
1,1,1,2,2,1,2,1,2,1,2,1][1,2,1,1,1,2,1,2,2,1,2,1,2,1,2,1][1,2,2,2,2,2,1,1,1,1,2,2,2,1,2,1][1,2,2,2,2,2,1,2,2,2,2,2,2,1,2,1]]→[A]
:End
:If L=2:Then
:If M=1
:[[1,2,2,1,1,1,2,1,1,1,2,1,2,1,1,1][1,2,2,2,1,2,2,1,1,1,2,2,2,2,2,2][1,2,2,1,2,2,2,1,1,2,2,1,1,1,2,1][1,2,1,1,2,2,2,1,1,2,1,1,1,1,2,1][1,1,2,1,
2,2,2,1,1,2,1,1,1,1,2,1][1,2,2,1,2,2,2,1,1,1,2,2,2,2,2,1][1,2,2,2,2,2,2,1,1,1,2,2,2,2,2,1][1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]→[A]
:If M=2
:[[1,2,2,2,2,2,1,2,2,2,2,2,2,1,2,1][2,2,2,2,2,2,2,2,1,1,1,2,2,1,2,1][2,2,1,1,1,2,1,1,1,1,1,2,2,1,2,1][1,2,1,1,1,2,1,1,1,1,2,2,1,1,2,1][1,2,1,1,
1,2,1,1,1,1,2,1,1,1,2,1][1,2,2,2,2,2,1,1,2,2,2,2,2,2,2,1][1,2,2,2,2,4,1,1,2,2,2,2,2,2,2,1][1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]→[A]
:End
:For(H,1,8
:For(I,1,16
:Output(H,I,sub(Str5,[A](H,I)),1
:End
:End

The above code will set up a 2x2 area for exploration. If you want, you can make it larger, it is up to you. The way I am showing you allows for great flexibility in making maps, so you can do as you like.

Now, we need to set up a program to set up the variables. Create a new prgm, call it 'B' for simplicity's sake, and insert the following code:

prgmB


:3→W:2→L:4→C:2→M:2→D
:"X VT→Str5
:prgmYLVL
:prgmYGA

Now you are probably asking what all the numbers are. We set 3 to W for the program's engine, L and M, as you know, are the 4 different map areas. C and D are the characters location on the screen, but also act as a guide within the matrix to determine hit detection. The string is for the interpreter, so the screen won't be full of numbers. Then it runs the level program and finishes off with the program engine.

Now we need to make the engine, so you can have the little guy walk around on the screen, and move from one section of the map to the next. Along with this, we will need a script that will check to see if the character lands on something other than an empty space, to check and see what it has to do. Create a new program called YGA and insert the following code:

prgmYGA


:While W=3
:Output(C,D,"θ
:If [A](C,D)≠2:Then:prgmYCH:End
:getKey→K
:If K=25:Then
:If C=1:Then
:L-1→L
:prgmYLVL
:8→C
:End
:If C>1:Then
:If [A](C-1,D)≠1:Then
:Output(C,D," "
:C-1→C
:End:End:End
:If K=34:Then
:If C=8:Then
:L+1→L
:prgmYLVL
:1→C:End
:If C<8:Then
:If [A](C+1,D)≠1:Then
:Output(C,D," "
:C+1→C:End
:End:End
:If K=24:Then
:If D=1:Then
:M-1→M
:prgmYLVL
:16→D:End
:If D>1:Then
:If [A](C,D-1)!=≠1:Then
:Output(C,D," "
:D-1→D:End
:End:End
:If K=26:Then
:If D=16:Then
:M+1→M:1→D
:prgmYLVL:End
:If D<16:Then
:If [A](C,D+1)≠1:Then
:Output(C,D," "
:D+1→D:End
:End:End
:End

Now after you have put in all the code above, I will explain abit on how it all works, starting from the top. You start out with the loop, then with the character being displayed. Next comes the dynamic event checker "script". This "script" looks at the matrix, in the current position of the character, and makes sure that the character is standing on a space. If it isn't on a space, it sends the program to a 'checker' program, and sees what needs to be done. Of course you need to have the getkey, and then the character movement key detection. Since they are all essentially the same, I will just discuss the generalization of the hit detection within them.

Using K=25, It attempts to determine first where on the screen the character is. This will only have 2 choices; either at the very top of the screen (C=1) or somewhere not near the top of the screen (C>1).

The C=1 script will simply look to see if the character is on the top line, and if it is, will move up the map once, move the character accordingly, and clear and display the new map area. The C>1 will first check the area above the character and make sure it is a 'non-walkable' space, then will allow the character to move.

Next comes the dynamic checker script. This script will stay completely dynamic as long as you define which letters/numbers are the walls, so you will not have to worry about dealing with that. For the sample program, we have two events that we need to define, but since this is just a sample, and it is up to you to make the events match a story line, I will just have it do something simple, and later you can add more to it.

prgmYCH:


:ClrHome
:If [A](C,D)=3:Then
:If L=1 and M=1:Then
:ClrHome
:Disp "THERE IS NO","VILLAGE
:Pause
:C-1→C
:prgmYLVL
:End:End
:If [A](C,D)=4:Then
:If L=2 and M=2:Then
:Disp "THERE IS NO","TOWER
:Pause
:prgmYLVL
:D-1→D
:End:End

Simply put, all this program does is sees if the matrix position corresponds with the event number. Now for the sample, it just clears and displays some text. You can also have multiple events in the same map segment, you just need to add the C and D variables and have it do what you want accordingly.

After you have copied this onto your calc, run program B. The calc should display the map, starting from the left corner, and working right and down. Once that is complete,it should display the little X guy, and you can move around. You can also move from screen to screen, and check out the events, to ensure that they were programmed correctly. If everything is as I say, and the program works without errors, then you did a good job. ^_^ If it screwed up somehow, then you need to go through the code, and make sure you copied it correctly. Any questions can be directed to the forums.

Using what you learned in lesson 1, check to see how much memory these programs are using. If you look at YLVL, you will notice that it takes alot of memory up. In the next part of this, I will show you how to do the same thing that the matrix program does, but take up a lot less space.

Like before, we need to create a program to store level data in. This time however, we will not be using a matrix, we will be using a string (Strn). What this means for you the programmer:

-You will have a smaller data program for the maps
-You only need a routine to display the map data if you don't plan on using the 8x16 homescreen
-The actual engine runs the same speed though the program is slightly larger
-You don't need a conversion routine to make numbers change to letters, since stings store letters and numbers, and matrices only store numbers.

We will be using the same map, we just have to convert it into different data for the calculator to use. Copy the program below to your calculator.

prgmZLVL:

:If L=1:Then
:If M=1
:"XXXXXXXXXXXXXXXXXX    XX        X  XX    XXX X XX  XXXXXXXXX XXXXV  XXXXXXXX XXXXXX XX     X XXXXX  XX XXX X XXXX  XXX XXX X XXX→Str1
:If M=2
:"XXXXXXXXXXXXXXXX               XX   X          XX   X    XXXX  XXXXXXXX  X X X XX XXX X X X X XX     XXXX   X XX     X      X X→Str1
:End
:If L=2:Then
:If M=1
:"X  XXX XXX X XXXX   X  XXX      X  X   XX  XXX  X XX   XX XXXX XXX X   XX XXXX XX  X   XXX     XX     XXX     XXXXXXXXXXXXXXXXX→Str1
:If M=2
:"X     X      X X        XXX  X X  XXX XXXXX  X XX XXX XXXX  XX XX XXX XXXX XXX XX     XX       XX T   XX       XXXXXXXXXXXXXXXXX→Str1
:End
:ClrHome
:Output(1,1,Str1

What you see above this is your sample levels. Since you already know what the levels look like, there really is no need to go over that info. The new item here is Output(. The one thing not explained before is that this command has text wrapping abilities, making situations like this very helpful. :)

Now we need to set up the variables. We don't have to worry about a string this time, though we do have to set up a variable to keep tabs on where in the map string we are at, plus we need to set where on the overall map we will start.

prgmA:

:3→W:50→T
:1→L:4→Q
:2→M:2→P
:prgmZLVL
:prgmZGA

You know what W, L, and M are and what they do, let's move on to the other 3 variables. P and Q are for the character movement, and T is used for the hit detection. Since we are using an 8x16 string, there are 128 character slots that we have to keep track of. This is done simply by having a variable know which slot the character is in, and using some commands, determine whether they can travel in a certain direction or not.

Now that that is set up, it is time to create the main gaming engine. This engine will be different from the matrix one, since this uses commands related only to strings, and has to look at hit detection in a different manner. First the code;

prgmZGA:

:While W=3
:Output(Q,P,"θ
:If sub(Str1,T,1)≠" ":Then:prgmZCH:End
:getKey→K
:If K=24:Then
:If P=1:Then
:M-1→M:T+15→T
:15+P→P
:prgmZLVL
:End
:If P>1:Then
:If sub(Str1,T-1,1)≠"X":Then
:Output(Q,P," "
:P-1→P:T-1→T
:End:End:End
:If K=25:Then
:If Q=1:Then
:L-1→L:T+112→T
:Q+7→Q
:prgmZLVL
:End
:If Q>1:Then
:If sub(Str1,T-16,1)≠"X":Then
:Output(Q,P," "
:Q-1→Q:T-16→T
:End:End:End
:If K=26:Then
:If P=16:Then
:M+1→M:T-15→T
:P-15→P
:prgmZLVL
:End
:If P<16:Then
:If sub(Str1,T+1,1)≠"X":Then
:Output(Q,P," "
:P+1→P:T+1→T
:End:End:End
:If K=34:Then
:If Q=8:Then
:L+1→L:T-112→T
:Q-7→Q
:prgmZLVL
:End
:If Q<8:Then
:If sub(Str1,T+16,1)≠"X":Then
:Output(Q,P," "
:Q+1→Q:T+16→T
:End:End:End
:End

The event checker is handled slightly different in this engine, it can directly search the map string to see if it is on a space or something else. Like the first one, you will not have to define that the calc does not have to look for wall pieces and ignore them in this script, the movement routines will do that.

The movement routines are a little bit more complex, but after you figure out one section of it, the rest is a breeze. Like in the martix style, we search for where the character is first. If the character is on the edge of the screen (left for the first case), the calculator will need to subtract from M so it will look at the next map to the left. It will also need to place the character and the hit detection variable on the same place when the screen comes back up.

(when using the full 8x16 screen...)

When it shifts one screen left: add 15 to T; one screen to the right, subtract 15.
When the screen shifts up, you have to add 112 to T, going down you need to subtract 112.

After that is set up, you need to have it send the character to its location. You need to set it up to go to the opposite edge of the screen. You can either have it add/subtract the necessary values, or you can directly store the values, your choice. If you happened to notice on the previous version, the engine makes it move an additional spot once the map loads. We can eliminate this by using another variable in between the map changer and the actual movement, where the mess is happening, that would eliminate the problem. At the begining of the loop, Delvar F, and have the map change parts of the routines store 1 to F. Then in the movement routines, have them make sure F=0 before moving. Simple, right? :)

Making the character move on the screen with the hit detection is just as simple as with the matrix system. Using the sub( command, the calc searches inside the string using an equation, depending on the circumstance. If the character needs to move one line up, then the calculator needs to look at the string, character location T-16. Moving down would need to look at T+16. Left and right are just +/- 1. And all that it is looking for is to see if the character in the travel direction is not an 'X'. And of course, if it passes that test, it moves the character (and hit detection variable) the corresponding amounts.

Now for the last part of this hit detection engine; the event checker. Similar to the matrix version, it looks to see what the character is standing on and does what ever you program it to do. Without trying to add too much more to this lesson (as it is overly huge anyways), I will say that the checker code uses the same code that sent the game to this program to see what event needs to be handled. I am sure you can figure out how to do the event detection. If not, you can always post on the forums.

Last but not least, we will discuss list hit detection. To give it to you in a nutshell, list detection is simply a cross breed of matrix and string detection. You need a variable to navigate and keep track of where the character is located; lists only hold numerical values, not letters, so it requires a conversion program; lists can take up a ton of RAM, just like matrices. Anyways, the first program will be the levels, stored into a list.

prgmXLVL:

:1→H
:ClrHome
:If L=1:Then
:If M=1
:{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,2,2,1,1,2,2,2,2,1,1,1,2,1,2,1,1,2,2,1,1,1,1,1,1,1,1,1,2,1,1,1,1,3,
2,2,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,2,2,2,2,2,1,2,1,1,1,1,1,2,2,1,1,2,1,1,1,2,1,2,1,1,1,1,2,2,1,1,1,2,1,1,1,2,1,2,1,1,1→L6
:If M=2
:{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,1,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,1,2,2,2,2,1,1,1,1,2,2,1,1,1,
1,1,1,1,1,2,2,1,2,1,2,1,2,1,1,2,1,1,1,2,1,2,2,1,2,1,2,1,2,1,1,2,2,2,2,2,1,1,1,1,2,2,2,1,2,1,1,2,2,2,2,2,1,2,2,2,2,2,2,1,2,1→L6
:End
:If L=2:Then
:If M=1
:{1,2,2,1,1,1,2,1,1,1,2,1,2,1,1,1,1,2,2,2,1,2,2,1,1,1,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,2,2,1,1,1,2,1,1,2,1,1,2,2,2,1,1,2,1,1,1,1,2,1,1,1,
2,1,2,2,2,1,1,2,1,1,1,1,2,1,1,2,2,1,2,2,2,1,1,1,2,2,2,2,2,1,1,2,2,2,2,2,2,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1→L6
:If M=2
:{1,2,2,2,2,2,1,2,2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,1,1,1,2,2,1,2,1,2,2,1,1,1,2,1,1,1,1,1,2,2,1,2,1,1,2,1,1,1,2,1,1,1,1,2,2,1,1,2,1,1,2,
1,1,1,2,1,1,1,1,2,1,1,1,2,1,1,2,2,2,2,2,1,1,2,2,2,2,2,2,2,1,1,2,2,2,2,4,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1→L6
:End
:For(J,1,8
:For(I,1,16
:Output(J,I,sub(Str5,(L6(H)),1
:H+1→H
:End:End

As you can see, the map data is similar, just not identical. Now the conversion routine, on the other hand, is a bit different. You have to have an extra variable in there, keeping track of where the for loops are at within the list. If you don't, the calc will just pull data from the first list slot over and over until the map is built. Now on to the gaming engine. (Please note, I will not be going into full detail, as stated earlier, this is a mix of matrix and string detection, you should be able to see the similarities in the program.)

prgmXGA:

:While W=3
:Output(C,D,"θ
:If L6(T)≠2:Then:prgmXCH:End
:getKey→K
:If K=25:Then
:If C=1:Then
:L-1→L
:8→C:T+112→T
:prgmXLVL
:End
:If C>1:Then
:If L6(T-16)≠1:Then
:Output(C,D," "
:T-16→T:C-1→C
:End:End:End
:If K=34:Then
:If C=8:Then
:L+1→L:T-112→T
:1→C:prgmXLVL
:End
:If C<8:Then
:If L6(T+16)≠1:Then
:Output(C,D," "
:T+16→T:C+1→C
:End:End:End
:If K=24:Then
:If D=1:Then
:T+15→T:16→D
:M-1→M:prgmXLVL
:End
:If D>1:Then
:If L6(T-1)≠1:Then
:Output(C,D," "
:D-1→D:T-1→T
:End:End:End
:If K=26:Then
:If D=16:Then
:T-15→T:1→D
:M+1→M:prgmXLVL
:End
:If D<16:Then
:If L6(T+1)≠1:Then
:Output(C,D," "
:D+1→D:T+1→T
:End:End:End
:End

Ok, after viewing the other two, you should understand the above with no problem. Next, I will show you the setup info for the program:


prgmC:

:3→W
:2→L:2→M
:128→dim(L6
:"X VT→Str5
:4→C:2→D:50→T
:prgmXLVL
prgmXGA

Ok, main difference here, you have to set up the dimension of the list, before you can store to it. Need I give the code for the event checker program? I guess I can on this one.

prgmXCH:

:ClrHome
:If L6(T)=3:Then
:If L=1 and M=1:Then
:Disp "YOU NEED TO","BUILD THE","VILLAGE.
:Pause
:D+1→D:T+1→T
:prgmXLVL
:End:End
:If L6(T)=4:Then
:If L=2 and M=2:Then
:Disp "TOWER NOT BUILT
:Pause
:D-1→D:T-1→T
:prgmXLVL
:End:End

Well, run the code for each style, see which one is fastest, which should be the string version, and decide from there how you want to make your games. Here is a screenshot of the string version in action:

If you have any questions on this, or adding to these programs, please post up on the forums.
<<Previous - Contents - Next>>