How to make a plateform game

So You Want to Build a Plateform Game ?

0. Topic

Thoses page topic is how to build a plateform game like X-out.
I don't said you must act like this for making a game, it's only how I made...

1. Prerequisites

  • Enough VB knowledge
  • Know how to manage array

2. Philosofy

I use a matrix to store all item on memory. see picture/explanations for details

Q : why a matrix ? can't you use directly pictures in GamePlay ?
A : no, pictures are only for eyes, I can't make the movment test with pictures

3. Vocabulary

Here is the term I use in my explanations
GamePlay | is the screen where you play
matrix | is a two dimension array where are stored items

4. How Levels are build

4.1 Items in GamePlay

Every item are an image object (prefer image as picture because it's smaller in memory)
As you don't know how many item is needed, you will need to load them dynamicly...

4.2 ItemObject template

At design mode (in VB IDE) create ONE template of each item..
change his INDEX property to 0.

At Runtime Mode (running) when you need to popup an item, simply use LOAD statement.

See here for more details
So there are one template for each kind of item : Key, Button, Gem..

4.3 Special items

Some items are not on the matrix but are loaded as other objects, it's
  • Lifts
  • enemies
Q : why ?
A : they can be over an other item (key, bonus..) and in the matrix there is only one item in one cell

4.4 Player

Other special item is the "player"
the player is an image object on the screen (picture of a litle blue-robot).
This item is not on the matrix, when you press arrow key it move the object itself directly.

To know where is the "player", it's easy, at any moment you can use left and top property.
See example/more information here.

ID in the matrix

In the matrix I use integer
I have gouped all same kind of item together..

The main reason is :
when all kind of bonus stand in a special range ( 60 to 80 ) I just need one test to know if there is a bonus or not.. and if yes, I simply run a function for analysing it and take action. that's easy to maintain.

note : I call "bonus" every item you can take, for example, dollar,key, gem, jumper-option...

See here for more details

Level File

The level file contains all elements described above...
special items... and item for the matrix

see here in details how level file are build and how to read it...

Movments

See here for :
  • key trapping
  • player movments

Case studie : Green Bloc

lets talk about Green bloc in xout

Greend bloc are movable (you can push them)
take a look on "how to manage it with matrix"

Case studie : Bonus

Some words about how to manage bonus

Others things

other items

Tips

instead of using "/" for division, you can use "\" which is faster (integer division) example :
x = player.left \ 16

You can use this file for Free.
Trademarks are registrer to their respective trademarks
I can't be responsible of anything you do with this document.

you are not allowed to sales, or change anything in this document
hpfx.


Managing Array ?
Difficulty Level : very-easy

Managing Arrays

to build a plateform game like xout, I use a MATRIX which is simply a two dimension array.
in this matrix, I put items which are on the screen.

knowledge on array

create a one dimension array of integer
' declaration
Dim abc (8) as Integer

'fill with one value
abc(2)=555

'get one value
v=abc(2)
this declaration will produce in memory one array like this :
abc(0) | abc(1) | abc(2) | abc(3) | abc(4) | abc(5) | abc(6) | abc(7) | abc(8)
0 | 0 | 555 | 0 | 0 | 0 | 0 | 0 | 0

create a two dimension array of integer
' declaration of an array of 20x10 items
Dim abc (20,10) as Integer

'fill with one value
abc(15,6)=555

'get one value
v=abc(18,2)
I wont draw a matrix of 20x10 item, but I think you can imagine a table with 11 rows and 21 cols.

Q : why 11 and 21?
A : because the array are zero-based (start at zero, not one)

Warning : when you create big array, a lot of memory is required, for example if you create a matrix of 100x100, you will enough memory to store 10000 items.. now imagine thoses items are doubles or strings you probably will have problem.
That's why I use a matrix of Integer.

Using

You know how to create a matrix.
advice : you can put the declaration of the matrix in a BAS module as public, in this way you can access your matrix everywhere. example :
Public Matrix (30,20) as Integer
At begining my levels files was 30x20.

Going further

Difficulty Level : easy/medium
If you don't know the size of your matrix at design time, but only durring the play, you can't put static declaration.
use those declaration instead :
Public matrix() As Integer
and when you know the width(row) and height(cols), you can do that :
ReDim  matrix(cols,row)
By this way I can make matrix of the good size at good moment.

example of xout

The size of a level is inside the level file, at first line
So, when I read 1st line of the the level file (.lvl) I know at this moment some informations,
for example : I read this : #XNLF3:B:lck:N I know that the B means BIG so I know I will make a 40x25 :
ReDim matrix(40,25)

The code can be like this
...
Dim mx as Integer, my as Integer 'size of level
line input #ff , L 'read 1st line
levelsize=GetElement(L,2) 'get the second element of the
                          'string L ..  see split function
GetLevelSizes(levelsize,mx,my)
ReDim matrix(mx,my)
...

Sub GetLevelSizes(byval LS,byref x as integer, byref y as integer)
Select case LS
 Case "S" 'standart
  x=30 : y=20
 Case "B" 'big
  x=40 : y=25
 Case "T" 'tall
  x=30 : y=30
 ...
End Select
End Sub

Q :Why I use a sub GetLevelSizes instead of doing the select case directly inside.
A :Because I know I will use this function elsewhere : LevelEditor

Q :what is GetElement()
A : GetElement is a function that you give you one of the elements inside a string (separated by ":") it's easy to make such function yourself by using SPLIT build-in function, see VB Help...
...Or if you want, take a look at my split function [you will need to replace Getelement by recht(2,L)]

=> go back to the help menu


HPhilosofy

Matrix representation

Look carefully at this picture

This mean, there are TWO representation of an item :
- in the screen (gameplay) only for your eyes
- in memory (matrix) for testing movments

How do you fill the matrix ?

Matrix is filled at Level Loading, exactly at the same time the objects are displayed on the screen.
See code example here

What is a matrix ?

a matrix is a two-dimension-array of integer.
(see related topic of Array if you don't know what is it)


Item template

using LOAD to popup template
Difficulty Level : medium/+

Design time

Go in your GamePlay form.
take the IMAGE object (in your toolbox)
draw a new object on the form.

In the property of this object, go to :
NAME | key
INDEX | 0
PICTURE | (load your picture of the key)
VISIBLE | False

this is a sample for a KEY..

You have made the template of the key...

What is a template

A template is the object which will be used to create all other object...

to create 10 keys (imagine 10 keys are required for a levels) the template of the key will be used (picture..)

Q : But why a template ?
A : Because you don't know how many you will need keys/doors/lifts... in the level.. If you create at design time 10 keys you can't have level with 11 keys.. So it's better to create only one (template) and to duplicate it when needed!

Load

LOAD statment is used to load with a template.
key(0) is the name of the tempate, to load a new key, do like this :
Load key(1)
this will create a new object wich name is key(1).

to display it on the GamePlay-Screen, simply make his visible-property to True.
key(1).Visible=True

Q : And if you want create 3 keys ?
A : You must create key 1 first, the 2 and the 3. you can do like this :
Load key(1) : Load key(2) : Load key(3)

Unload

Every object loaded must be unloaded.. that's a rule...
otherwise, if you don't unload key of first level, they will be still here for the second level !

to unload an object :
Unload key(1)

how to use load in the pratic

You can know how many key are loaded by this code :
print key.UBound

Ok, now if you want to add a key, you simply need to do like this :
n=key.UBound 'nb of key
Load key(n+1) 'load a new key
key(n+1).Visible=True

After that you need to place you new key at the good place...
key(n+1).left=...
key(n+1).top=...

Q : what is UBound ?
A : In fact , Ubound means UperBound, that's the higher index of object loaded. if you respect the rule, it's the number of object loaded.
Q : How can I not respect the rules? and what are the rules ?
A : If you do such things :
Load key(1)   'Ubound=1 , number of key=1 : ok
Load key(2)   'Ubound=2 , number of key=2 : ok
Unload key(1) 'Ubound=2 , number of key=1 : warning!
So, when you unload an object you must : delete ALL or delete the last!

When to use LOAD

LOAD must be use at level loading, when the level file is read.

In the level File, there is a special section (start just after a single D)
this section contain one char for each item,
example the Key is a "C", the Door a "I"...

When you read the level file, at this moment, you must take each char, and create a new key when a "C" occurs(like shown previously), and a new Door when "I" occurs..

Q : Don't understand..
A : You know how to create a new key (Load) from the key template and it's the same for other items (doors,gems,buttons..). In the level file, you will read each char one by one, if you found a "C" you must create a key, if it's a "I" a door...
Q : Yes, but how do you know where is the position of this new obect in the screen ??
A : take the position in the level file : first line in the file, will be first line at the screen, and the 10th char in the line will be the 10th object in this line on the screen.

Example

This is an example to illustrate the explanations
Dim L as string, ff as integer
ff=freefile
open .... as ff
...
Y=0   ' line number in the screen
while not EOF(ff)
 line #ff input L   ' L is the line
 for i=1 to len(L)
  newitem(mid(L,i,1),Y,i-1) ' call a sub
 next i
 Y=Y+1
wend
close #ff
End sub

Sub newitem(char,y,x)
 select case char
   case "I" 'door
     n=door.UBound + 1
     load door(n+1)
     door(n+1).visible=True
     door(n+1).left=x*16
     door(n+1).top=y*16
   case "C" 'key
  ...
 end select
End sub

Q : why you multiply by 16 the X and Y ?
A : Because objects I use are 16x16 pixels (I use 16x16 picture for templates)

Optimizing !

Difficulty Level : hard
Of course you can optimize this code to :
Dim L as string, ff as integer
Dim obj as object
ff=freefile
open .... as ff
...
Y=0
while not EOF(ff)
 line #ff input L   ' L is the line
 for i=1 to len(L)
  set obj=  newitem(mid(L,i,1),Y,i-1) ' call a funct.
  obj.Visible=True
  obj.left=Y*16
  obj.top= (i-1)*16
 next i
 Y=Y+1
wend
close #ff
End sub

Function newitem(char,y,x) as object
 select case char
   case "I" 'door
     newitem = load door(door.UBound + 1)
   case "C" 'key
     newitem = load key(key.UBound + 1)
  ...
 end select
End function

Loading objects and..

Objects are only for eyes, don't forget to store something in the matrix,
this will help you to know what item stand at this place...

you can do like this :
(using a matrix of string)
...
while not EOF(ff)
 line #ff input L   ' L is the line
 for i=1 to len(L)
  newitem(mid(L,i,1),Y,i-1) ' call a sub to load object in the screen
  matrix(i-1,Y)= mid(L,i,1)
 next i
 Y=Y+1
wend
...
where mid(L,i,1) is the char taken from the file
Q : why do you use i-1 as X and not i in matrix(i-1,Y)= ?
A : because my matrix is zero-based : the item at top-left is at (0,0).

Personatly I use a matrix of Integer... I don't store String (for many reason I will explain later)

So I build a TO_NumBer function who translate string into number like this :
Function tonb(byval s as String) as Integer
select case s
 case "#"
  tonb=5
 case "1"
  tonb=6
 case "I"
  tonb=35
  ...
 end select
End Function
So the modification is :
...
for i=1 to len(L)
  newitem(mid(L,i,1),Y,i-1) ' load object in the screen
  matrix(i-1,Y)=tonb(mid(L,i,1)) ' fill the matrix
next i
...

an overview of loading level is here if you want.


Player

The Player

coordonate of the player

player item

the player is an IMAGE object
the name is for example : "player"
the VISIBLE property is alway TRUE. there is no INDEX=0 property because we don't load any new player (one player is enough !)

position

simply use left and top property to know where the player is in the matrix..
dim x as integer, y as integer
x= player.left /16
y= player.top /16
'the player is at (x,y) in the matrix !

Q : why /16 ?
A : because the screen resolution is PIXEL and the matrix resolution is ITEM, and one ITEM is 16 pixels ! (top and left are in screen resolution, by the don't forget to check your screen resolution is NOT TWIPS but PIXELS !!!!)

Position, ok but what for ?

Now you know where the player is on the matrix, this is very usefull.. look at this samples :

matrix ()=
 | 0 | 1 | 2 | 3 | 4 | 5
0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 0 | 61 | 0 | 0 | 5 | 0
2 | 5 | 5 | 5 | 5 | 5 | 0
imagine '5' is wall/bloc
and '61' is a bonus

now, if you know the player is at (1,1)
you know you must earn money (bonus)
and you should not fall (bloc under you)

You see, it's easy..

What's next?

you should remove the '61' in the matrix (otherwise you will be able to take it many times.. that's too easy!)

and you should think about object of the screen : you must hide the bonus image..
how to do ?

easy.. you know it's a bonus..
simply look in all bonus object the one who stand at this location (x*16,y*16)
you can do it like this :
n= bonus.UBound
for i=1 to n
if bonus(i).left = x*16 and bonus(i).top = y*16 then
 ' you have found the good bonus !
 good=n
end if

bonus(good).Visible=False
note : in this sample I take "bonus(i)", but if it's a key, you must use "key(i)" of course..


Matrix IDs

Matrix ID

Matrix is a array of ...

you can make matrix of what you want.. string, integer.. object..
I choose Integer because it make my life easier..

Mind game !

Group

The grouping method is the key !
this is difficult, you must think very carfully before starting everything...

Why grouping ?

Because it will be easier to make the test..
for examle, you want to know if the player is under a bloc or not (otherwise he must fall down)
if you make a good job when grouping, on only need to test the value is between 5 and 50... for example.

How to well group

Think about all feature you will propose in your game...
think about making group and subgroup...
  • can stand on item ? yes, group them (usual bloc)
  • can go through item (magma)?
  • can take item (bonus) ?
  • can grabb on item (solid blocs)?
  • can active (buttons) ?
  • can move some item ?
  • dangerous item (fire,laser) ?
  • ...

it's difficult

Trust me, it's not so easy..
don't forget to let empty numbers for extension

think about all kind of test you must do in the game..
about jumping, grabbing, taking things.. falling...

myself, I have change 3 times the ID from the beginig of xout, it's hard to do, it generate a lot of bug, it long...

trust me, take care to this point.

functions

Once you have finish grouping, you need simply make functions...
for example

Function Solid(x,y) as boolean
Solid=false
if matrix(x,y)>=5 and matrix(x,y)<=50 then Solid=true
End Function
 This function returns True or False is there is something solid or not at (x,y)

And After to know if you are on a 'solid' bloc you simply need to do that :
...
x= player.left /16
y= player.top /16

if solid(x,y+1) then
 'ok don't fall
else
 'nothing under you !
 call fall()
end if
...
For more informations about player position see here.


Level file

introduction

the levels are into LVL\ directory
the list of level is stored into levels.lst file (not studied here)

structure of level file

a level is constitued by :
  • an header (facultative)
  • special items
  • matrix items

exemple :
#XNLF3:S:lck:J01  <== this is the header (1 line)
% X-Out is made by HpFx  <== some comments

G:2:2:100:8:14 <== "G" start Special items
%Objects Data
E:2:7:2:13
E:2:8:7:14
A:19:2:19
M:10:3:8:8
M:2:11:17:17

%Begin Data Array  <== some comments
D                  <== "D" start Matrix items

 #    C      $
 ########  ###   #####X##
 CCC I
 FFFFFF  ########44444

     #   I
     ##### # #

The header section

the header is build like this :
#version:size:option:background
those informations are used for LevelEditor and Gameloading

the purpose of this help is not the LevelEditor, so we will only see what's interresting for Game loading :
  • size is a letter which indicate the size of the gameplay (see how to manage it)
  • background : simply used for displaying a picture in background.. not the purpose of this doc.

Special Items section

contents

G:6:1:200:7:3
%Objects Data
E:1:0:18:10
E:1:0:8:9
E:1:2:6:8
E:1:15:0:21
E:1:27:8:17
E:1:19:15:27
A:18:1:7
M:15:6:16:13
the 1st line start with G that means General Data..
There are the number of enemies, the number of lift, then bonus time and the starting position of the player

the following lines are the detailed information of each items
  • E lines stand for enemies, data are : speed, start up position and end position
  • A lines stand for the automatized lift, data are : start up position and end position
  • M lines stand for manual lifts, data are : start up position, max and min limits

Reading

things to do for reading such things :
read the 1st line (G)
get the number of lift/enemies (for checking) and get the player position, and put it on the gameplay (player.left=x*16 : player.top=y*16)

Reading enemies or lifts is about the same :
Read the parameters (x,y,x-end...)
Popup a NEW object, by using LOAD (the same as usual object)
But you will have to keep some extra data somewhere (like the limits..)
There are 2 possibilities
  • 1. hacker solution : you can put thoses informations in extra properties (not used), for example, you can use the .TAG property to store the lower limits and use .WhatThisHelpID to store upperlimit of a lift...
    example :
    ...
'x and y contain the start up position
'y1 and y2 contain the Y-limits of the lift
n=lift.UBound
Load lift(n+1) ' create a new lift
lift(n+1).left = x*16
lift(n+1).top = y*16
lift(n+1).tag = y1
lift(n+1).whatThisHelpId = y2
lift(n+1).visible = True
  • 2. clean solution : you can store it into an array
    example: :
    'declaration
Public Type liftData
 ymin As Integer
 ymax As Integer
End Type
dim LiftInfo(20) as liftData

...
'x and y contain the start up position
'y1 and y2 contain the limits of the lift
n=lift.UBound
Load lift(n+1) ' create a new lift
lift(n+1).left = x*16
lift(n+1).top = y*16
liftInfo(n+1).ymin = y1
liftInfo(n+1).ymax = y2
lift(n+1).visible = True
thoses two solutions works very well
myself I use one for enemies and the second for lifts !!!!!!!!!

Q : and why it's usefull to store thoses data ?
A : when you will make move your lift you will have to check you not exceed limits!

Q : is one solution easier ?
A : no, it's the same, once you know the lift number, it the same to use lift(n).tag than liftInfo(n).ymin

Q : is one solution better ?
A : yes, the second of course..

Q : and how do you get the x,y,y1 and y2 value from the string "M:15:6:16:13" ??
A : you can use the split function of VB6, or mine

Q : About "2. clean solution" what is Public Type liftData ???
A : It's the way to use array of customized data. You already know array of integer.. and now it's array of LiftData. and LiftData is defined via the TYPE statment!

Matrix section

contents

D                  <== "D" start Matrix items

 #    C      $
 ########  ###   #####X##
 CCC I
 FFFFFF  ########44444

     #   I
     ##### # #
there is one char for each items.

Reading

When reading the file at this section,
you must read char one by one
and for each char you must :
  • create the corresponding item in the screen
  • fill the matrix
a sample of code is here

Conclusion

Reading a level file can be like this :
1. opening the file
2. reading header
3. reading general data and special item
4. reading matrix data
5. closing the file

make it !

this is a litle sample of what you can do :
' step 1 : opening
dim ff as freefile
Open "thefilename.lvl" For input access read as ff

dim L as string,special as boolean

line input #ff, L

' step 2 : header
header(L) 'call a sub for work on header

special=true

while special
 line input #ff, L
 if not left(L,1)="%" then
  if L="D" then special=false 'no more special, now it's matrix
  if left(L,1)="G" then generalData(L) ' step 3 : general data
  if left(L,1)="M" then NewLift(L) ' step 3 : lift
  if left(L,1)="E" then NewEnemy(L) ' step 3 : enemy
  if left(L,1)="A" then AutoLift(L) ' step 3 : autolift
 end if
wend

Y=0
' step 4 : matrix
while not EOF(ff)
 line input #ff, L
 for i=1 to len(L)
  newitem(mid(L,i,1),Y,i-1) ' draw new item on screen
  matrix(i-1,Y)= tonb(mid(L,i,1)) ' fill the matrix
 next i
 Y=Y+1
wend

close ff ' step 5 : close
note : it's not the way I made for xout, there is a lot more of checking in xout, it's too complicated to explain.

Q : And about header(), generalData(), NewLift(), NewEnemy() and AutoLift() functions ???
A : Read carefully the corresponding section in the top of this page....


How to make a plateform game

Movments

Prerequisites

Topics you must read before :
  • Player position
  • Philosofy of Matrix
  • Matrix : ID in the matrix
But if you read this doc chronologicly, you should have already read that.

key trap

Handle keys

All key events are sent to the form.
it raise : form_KeyDown() function.
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Keycode and Shift give you status of the keyboard.

Personalty, I prefer transform it like this :
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Dim dir As Integer, jump As Boolean
 Call determine(KeyCode, Shift, dir, jump)
 ' it take the keycode pressed and give me back the direction
 ' and if he want to jump
 ...
The determine function is here :
Static Sub determine(ByVal k As Integer, ByVal s As Integer, ByRef dir As
Integer, ByRef j As Boolean)
j = False
dir = 0
Select Case k
 Case 38
  dir = 1
 Case 39
  dir = 2
 Case 40
  dir = 3
 Case 37
  dir = 4
 Case 32
 Case 27 'ESC
  die()  'game-over
 Case 112 'F1
 Case 113 'F2
 Case 115 'F4
End Select
If s > 0 Then
 j = True  ' shift or ctrl : jump
End If
End Sub
Now, let go back to Form_KeyDown , after the call to determine, you know the direction, and if he pressed shift/ctrl...
determine returns dir like this :
value | direction
1 | up
2 | right
3 | down
4 | left

you can manage it like this..
...
Call determine(KeyCode, Shift, dir, jump)

select case dir
 case 1 'up
  ...
 case 2, 4 'left/right
  ...
 case 3 'down
  ...
end select

Warning

If you want the form handle (trap) all the keys.. you must be sure there are no other object which can get the focus...

Advice : My solution is easy : remove all objects who can get the focus on the game-play form.
this means : no button, no textbox...

player movments

introduction

You know :
  • where the player is (see position)
  • where the player want to go (see dir here)
You must look what is on the matrix at this position...

Checking

Before moving you must check :
  • possible to move or not ? (bloc)
  • door here ?
After moving you must check :
  • bonus to take ?
  • button under you ?
  • danger here ? (if yes : die)
  • something under you ? (if not : fall)
All of these are checked in the matrix.

Example : Solid checking

we will studie the Left/Right movments (dir=4 or 2)
with out jumping (to keep it simple)
X = player.left / 16
Y = player.top /16

' calculate destination position
nX=X+3-dir
nY=Y

' possible to move or not ?
if solid(nX,nY) then exit sub
(nX,nY) is the position of destination cell in the matrix
Imagine you made a function Solid(x,y) which tell you if there is something solid (bloc) at this position...

Move Left | Move Right
dir=4 | dir=2
 | nX | X |
 | 0 | 0 | 0
Y,nY | 0 | 0 | 0
 | 5 | 5 | 5

 |  | X | nX
 | 0 | 0 | 0
Y,nY | 0 | 0 | 0
 | 5 | 5 | 5

Example : door checking

' possible to move or not ?
if solid(nX,nY) then exit sub
if door(nX,nY) then exit sub
door(x,y) is a function that return TRUE if there is a door and not enough key.

example:
Function Door(x,y) as Boolean
if matrix(x,y)<>35 then Door=False : exit sub
' Door value is 35 in the matrix.

' ok, a door is here... now we check if there are enough keys...
if OwnedKeys>0 then
 ' yes !
 OwnedKeys = OwnedKeys-1
 hide_the_door_at(x,y)
 matrix(x,y)=0 ' remove door in the matrix
 Door= False
else
 ' no key..
 Door=True
End if
End Function
Q : What is hide_the_door_at(x,y) ?
A : is a function to hide the object at this position on the screen, you can see here how to hide an object on screen

Q : What is OwnedKeys ?
A : It can be a variable for counting key you get...

Example : Moving

the move can be made like this..
player.left=nX*16
player.top=nY*16

Example : bonus checking

A simple call to a function can be made...
call BonusChk(nX,nY)
See here how you can build such function.

Example : Button Checking

Same as bonus, you can do like that :
call ButtonChk(nX,nY+1)
Q : what nY+1 ?
A : because buttons are under the player..

Example : under...

After all that, you must check if the player shall fall or not.
simply check if there is something Solid under the player.
if not Solid(nX,nY+1) then call fall()
fall() is a function that make the player falling.. you will see later.

Moving : Going further

Of course you must think about jumping
Have a look at the "key trap" function to get the jump variable : j
Jumping Left Jumping Right
nX=X+(3-dir)*2
sX=X+3-dir
nY=Y
sY=Y
dir=4 j=True dir=2 j=True
 | nX | sX | X |
 | 0 | 0 | 0 | 0
Y,nY,sY | 0 | 0 | 0 | 0
 | 5 | 5 | 5 | 5

 |  | X | sX | nX
 | 0 | 0 | 0 | 0
Y,nY,sY | 0 | 0 | 0 | 0
 | 5 | 5 | 5 | 5
Now you have :
  • (nX,nY) for the destination cell
  • (sX,sY) for the skiped cell
Make the same check for the destination cell.
About the skiped cell,only check about doors and solid.

Conclusion

This is just a sample, I show you only easy things, if you want to manage green movable bloc, you must do it here too.

Falling

introduction

To make the player fall, it's easy, move his picture to down until nothing solid stand under him.

Example : falling function.

Sub fall()
x=player.left /16
y=player.top /16
While not solid(x,y)
 y=y+1
 player.top=y*16
Wend
End Sub
This is a very simple fall sub.

But instead of checking Solid(x,y), you will need to check if you are on a lift too. (remember lift are not on matrix)
You can do like this :
Sub fall()
x=player.left /16
y=player.top /16
While onthefly(x,y)
 y=y+1
 player.top=y*16
Wend
End Sub

Function onthefly(x,y) as Boolean
 onthefly=true
 if solid(x,y) then onthefly=false
 if lift_at(x,y) then onthefly=false
end function
The onthefly function is used for stop falling.
Q : what is lift_at()
A : it's a function that check all lifts to know if one of them is at this position.

Bonus checking when falling

when the player fall, you must check if he take bonus, you can do it after the "y=y+1"
...
y=y+1
call BonusChk(x,y)
...

General overview

sample of code
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Dim dir As Integer, jump As Boolean
 Call determine(KeyCode, Shift, dir, jump)
 ' it take the keycode pressed and give me back the direction
 ' and if he want to jump
 select case dir
 case 1 'up
    ...
 case 2, 4 'left/right
    X = player.left / 16
    Y = player.top / 16

    ' calculate destination position
    nX=IIF( jump , X+(3-dir)*2 , X+3-dir )
    sX=X+3-dir
    nY=Y
    sY=Y

    ' possible to move or not ?
    if solid(nX,nY) then exit sub
    if door(nX,nY) then exit sub

    if jump then
      if solid(sX,sY) then exit sub
      if door(sX,sY) then exit sub
    end if

    'move it babe
    player.left=nX*16
    player.top=nY*16

    call BonusChk(nX,nY)
    call ButtonChk(nX,nY)
    if not Solid(nX,nY+1) then call fall()

 case 3 'down
    ...
End select
End function


How to make a plateform game

case studie : green-bloc

Introduction

We will studie now how green-blocs are managed into the matrix.

Vocabulary : I call "GD" the green-bloc (Movable is Deplacable in french)

GD can move in 4 directions :
- left/right : if player push it
- down : when it falls
- up : when it is on an electric door

Matrix

See this example :
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 0 | 0 | 0 | 62 | 22 | 0 | 0 | 0
2 | 0 | 5 | 5 | 5 | 5 | 5 | 5 | 0
The GD is at (4,1), if the player go to left, he will push the GD OVER the key

What can we do ?
Save and restore...

Events

we must formalize a litle :
There are TWO events :
  • Entering in a cell
  • Leaving a cell
What shall we do :
Every time a GD enter in a cell, the content of the cell must be save into the GD.
Every time a GD leave a cell, the GD must restore it's contents.

The Rule

So EVERY kind of movment for a GD must be done like this :
  • leaving previous cell : restoring
  • moving physicaly (in the screen)
  • entering a new cell : saving

Saving/Restoring

where to save ?
you can save into the TAG property of the GD object.

for example :
'x,y are old position
'x1,y1 are the new ones

n=GetGDObject(x,y) ' to get the object of the screen

matrix(x,y) = GD(n).tag 'leaving : restoring

GD(n).left = x2 * 16 'moving
GD(n).top = y2 * 16

GD(n).tag= matrix(x2,y2) 'entering new cell
matrix(x2,y2)=22
Q : What is the GetGDObject() function ?
A : it's a function that return of index of the GD-object at this position... example of code :
Function GetGDObject(byval x,byval y) as integer
dim n as integer, i as integer
n=GD.UBound
for i=1 to n
 if GD(i).left / 16 = x and GD(i).top / 16 = y then GetDGObject=i : exit function
next i
End Function

Draw

Step 1
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 0 | 0 | 0 | 62 | 22 | 0 | 0 | 0
2 | 0 | 5 | 5 | 5 | 5 | 5 | 5 | 0
 The player want to move at left

GD(n).tag=0 'was 0 at (4,1)
Step 2
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 0 | 0 | 0 | 22 | 0 | 0 | 0 | 0
2 | 0 | 5 | 5 | 5 | 5 | 5 | 5 | 0
 The player is moving : it push GD

GD(n).tag= 62
'the key is in the GD
Step 3
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 0 | 0 | 0 | 22 | 0 | 0 | 0 | 0
2 | 0 | 5 | 5 | 5 | 5 | 5 | 5 | 0
 The player has moved
The player want to move again at left !

GD(n).tag= 62
Step 4
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 0 | 0 | 22 | 62 | 0 | 0 | 0 | 0
2 | 0 | 5 | 5 | 5 | 5 | 5 | 5 | 0
 The player is moving : it push the GD

GD(n).tag=0 'was matrix(2,1)
Step 5
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 0 | 0 | 22 | 0 | 0 | 0 | 0 | 0
2 | 0 | 5 | 5 | 5 | 5 | 5 | 5 | 0
 The player has moved.
he took the key (62)

GD(n).tag=0

Going further..

Maybe you ask yourself this question :
Shall I hide the key image while it's inside the GD ??

I answer no : if you use Zorder property you will be able to tell to VB : " this picture in behind this one", by this way it will be naturaly hidden by the GD, and you don't need to alter Visible property of the key!

It work's like this in xout !

the order of object in xout is like this :
bonus, bloc ,GD ,lift ,player, enemies
It means : Enemies are over the player which is over lifts...


Bonus

Case studie : Bonus

Prerequisites

  • matrix : grouping
  • position of the player : sample with bonus

What a bonus is ?

Definition

the definition of a bonus is :
  • you can take it
  • once you have took : it desapear
  • you can move throught
  • can be stored into a Green-Bloc

samples

in xout thoses item are bonus :
key,gem, teleport-in, jumper-option, higher-option, dollards, big-dollards.

playing with bonus

Group

All bonus have number from 60 to 70 in the matrix.

Testing

Each time the player change of cell, we must test if in the new cell there is a bonus..
to do that you can call such a function :
call BonusChk(x,y)
it's small, and easy.

the BonusChk function must check if it's a bonus or not, so the first thing to do is to leave if there is no bonus.
Sub BonusChk(x,y)
i=matrix(x,y)
if i<60 or i>70 then exit sub
...
After that what you can do is switching to the good sub..
...
Select case i
 case 61
  ...
 case 62
  ...

End select
matrix(x,y)=0
end sub
Q : what is matrix(x,y)=0 ???
A : we said in definition, after taking, an option must disapear, so I clean the matrix... for hiding object it self, you can do it in "case" statments..(see Prerequisites : sample with bonus)

So you see it's easy !

Going further..

Working with buttons is the same !
Simply call ButtonChk(x,y+1) at good places and dont clear the matrix (matrix()=0) !
you should find your self..

Q : "at good places" ??
A : yes, when the player move or when a green bloc move !


Other items...

introduction

There are lot of thing I don't speak about: enemies, lifts...

That's normal, the purpose of this doc is not to give you all sources of xout otherwise I give you directly the xout sources files...

no no, the purpose is to give you tips, to show you interresting parts of sources.. answering some of your questions if you have problem, and for next problems, if you keep the same philosofy, you should find the solutions by yourself..
Nobody explained me anything, sometimes solutions I found was not so good, but at begining it was ok.. in next release I have changed and changed...

So I just give you a litle help for other item, and you will do it yourself.

Enemies

use a timer.
in timer event : move each enemies in direction, and check if player is here.
the direction, and the limits can be stored into an array as shown here.
example :
if enemy(n).left /16 < enemyList(n).min then enemyList(n).dir = - enemyList(n).dir
if enemy(n).left /16 > enemyList(n).max then enemyList(n).dir = - enemyList(n).dir
enemy(n).left = enemy(n).left + enemyList(n).dir * 16
don't forget to initialise dir with 1 or -1

Lifts

Lifts are not in the matrix
when you move on a lift, the fall() sub is called
so, in the fall() sub you must make thoses test for stoping to fall :
- arrived on a solid bloc
- arrived on a lift

Automatic lift :
is the same as enemies for movments.

Grabbing

When player is grabbed, there is a pipe from the player to the next upper solid item.

When the player want to move (left/right) in this mode, you must check if there is something all along the pipe, if there is something, the pipe is broke and the player must fall.

Jumping

Nothing special to says..

When you jump (at right) you must check what's on the matrix at (x+2,y) and at (x+1,y)..
but you know all that, now you are a guru !


My sources !

You want to use pieces of my sources...

function to split string into elements

In VB6 you can do it your self by using split function
My recht function is an very old function to do the same as split (didn't exist at this time), I know it's not optimized, but there is one advantage if you ask for item number 10 and there are no 10 item, my function still work and give back an empty string.(split function raise an error!!)

How to use :
recht(3,"item0:item1:item3:item4") returns "item3"
recht(2,"item0:::item3") returns ""
recht(5,"item0:item1") returns ""
Q : why the separator is ":" ?
A : because!

here is the code :
Function recht(ByVal n As Integer, ByVal t As String) As String
Dim d As Long, m As Long, nb As Long, f As Long
Dim v As String

If Len(t) < 2 Then recht = "": Exit Function

If n = 0 Then
 d = InStr(1, t, ":")
 If d > 0 Then recht = Mid(t, 1, d - 1) Else recht = ""
 Exit Function
End If

d = 0
m = Len(t)

While d < m And nb < n
 d = InStr(d + 1, t, ":")
 If d = 0 Then d = m
 nb = nb + 1
Wend

' tester la sortie

If d > m - 1 Then recht = "": Exit Function
f = InStr(d + 1, t, ":")
If (f = 0) Then v = Mid(t, d + 1) Else v = Mid(t, d + 1, f - 1 - (d))
recht = v

End Function