I'll try to explain it slower (and if you have pot, send it to me, man, I explain things better when I'm weeded):
You have two kinds of coordinates: pixel-perfect coordinates and tile coordinates. Let's say our tiles are 16x16.
In this situation, our character may be whether in a tile-perfect coordinate (for example at (0,0), or (16,16), or (32,64)...) or in a non-tile-perfect coordinate (such as (123,75)...).
Since our character will collide with tiles and it is the size of a tile (16x16, if it is bigger it doesn't care, you consider it the size of a tile. That's what I made on LALA or JILL: it makes your life easier), you only have to check for collisions when your player is in a tile-perfect coordinate. Otherwise, you can move freely, 'cause you know that your player won't collide in the next frame. So you check ONLY when you are in tile-perfect coordinates.
The logics before my mapping collision techniques is: Do I collide if I move? Yes:: don't move. No:: move. I handle the vertical movement first, then the horizontal movement. In a platformer, you usually have vx, and vy to keep track of vertical/horizontal velocities, but I'll try to picture something more simple.
Let's put an example: horizontal movement. Imagine that you have detemined to advance one pixel to the right (for several methods, maybe for a vx = 1 or having pressed RIGHT CURSOR in a linear-movement engine). Those are the checks you have to do in such case:
1.- p.x and p.y are the player's pixel coodinates. xx%=p.x\16 and yy%=p.y\16 are the player's tile coordinates.
2.- We are moving right, so we have to check in the first place
wether our player is horizontally-centered on a tile, or, what is the same, (p.x MOD 16) = 0, or, making things faster, (p.x AND 15)=0.
3.- If
(p.x AND 15)<>0 then just move: p.x = p.x +1. There is no problem, we won't collide with any tile.
4.- If
(p.x AND 15)=0 then it is possible that we collide with a tile if we move right, so we have to perform more checks:
4.1.- Surely we should check the tile at right, but think on this: if the vertical coordinate is not tile-perfect, we can collide with two different tiles:
So we have to check this also:
4.1.1.
(p.y AND 15)=0 we are centered vertically:
so we just check
if map%(yy%,xx%+1)=WALKABLE. If so, we move: p.x=p.x+1
4.1.2.
(p.y AND 15)<>0, we are not centered vertically. That way we should check two map positions:
if map%(yy%,xx%+1)=WALKABLE and map%(yy%+1,xx%+1)=WALKABLE. If so, we move: p.x=p.x+1
In this simple engine, the player jumps linearly (without gravity) during a number of steps. The player advances right of left at the tap of a key, no matter if it is falling or jumping. There is no horizontal acceleration. Tiles are 16x16. Empty (walkable tile) is 0. You can adapt this stuff as long as you get the logic behind tile collision detection.
This comes inside a SUB which holds the Screen%(MAXY,MAXX) and the p AS PlayerData with x, y and stuff like that.
Code:
' easy and dumb linear jump'n run tile collision engine
SUB MovePh (p AS PlayerData, Screen%())
DEF SEG = 0
' Fall down?
oldpx% = p.x
xx% = p.x \ 16 ' Tile coordinates.
yy% = p.y \ 16
fall% = 0 ' flag
IF NOT p.jmp AND yy% < 12 THEN ' If not jumping, check if we fall
IF (p.y AND 15) = 0 THEN
IF (p.x AND 15) = 0 THEN
IF Screen%(yy% + 1, xx%) = 0 THEN
p.y = p.y + 1
fall% = -1
END IF
ELSE
IF Screen%(yy% + 1, xx%) = 0 AND Screen%(yy% + 1, xx% + 1) = 0 THEN
p.y = p.y + 1
fall% = -1
END IF
END IF
ELSE
p.y = p.y + 1
fall% = -1
END IF
END IF
' Move
yy% = p.y \ 16 ' p.y might have changed, so we recalc yy%
IF (PEEK(1047) AND 4) THEN ' Left = CONTROL key
p.facing = 1
p.ct = p.ct + 1
IF (p.x AND 15) = 0 THEN
IF xx% > 0 THEN
IF (p.y AND 15) = 0 THEN
IF Screen%(yy%, xx% - 1) = 0 THEN
p.x = p.x - 1
END IF
ELSE
IF Screen%(yy%, xx% - 1) = 0 AND Screen%(yy% + 1, xx% - 1) = 0 THEN
p.x = p.x - 1
END IF
END IF
ELSE
IF p.x > 0 THEN p.x = p.x - 1
END IF
ELSE
IF p.x > 0 THEN p.x = p.x - 1
END IF
END IF
IF (PEEK(1047) AND 8) THEN ' Right
p.facing = 0
p.ct = p.ct + 1
IF (p.x AND 15) = 0 THEN
IF xx% < 16 THEN
IF (p.y AND 15) = 0 THEN
IF Screen%(yy%, xx% + 1) = 0 THEN
p.x = p.x + 1
END IF
ELSE
IF Screen%(yy%, xx% + 1) = 0 AND Screen%(yy% + 1, xx% + 1) = 0 THEN
p.x = p.x + 1
END IF
END IF
ELSE
IF p.x < 304 THEN p.x = p.x + 1
END IF
ELSE
IF p.x < 304 THEN p.x = p.x + 1
END IF
END IF
IF (PEEK(1047) AND 1) OR (PEEK(1047) AND 2) THEN ' SHIFT=jump
IF (p.y AND 15) = 0 THEN
IF yy% < 12 THEN
IF (p.x AND 15) = 0 THEN
IF Screen%(yy% + 1, xx%) <> 0 THEN
p.jmp = -1
p.ctJmp = 0
END IF
ELSE
IF Screen%(yy% + 1, xx%) <> 0 OR Screen%(yy% + 1, xx% + 1) <> 0 THEN
p.jmp = -1
p.ctJmp = 0
END IF
END IF
ELSE
p.jmp = -1
p.ctJmp = 0
END IF
END IF
END IF
' Calculate frame: (ignore this, just to calculate which sprite should I display)
IF p.jmp OR fall% THEN
IF p.facing = 0 THEN
p.spr1 = "GH"
p.spr2 = "KL"
ELSE
p.spr1 = "AB"
p.spr2 = "EF"
END IF
ELSE
IF p.ct >= 5 THEN p.ct = 0: p.frame = NOT p.frame: AdlibFX 0
IF p.facing = 0 THEN
p.spr1 = "GH"
IF p.frame THEN p.spr2 = "IJ" ELSE p.spr2 = "KL"
ELSE
p.spr1 = "AB"
IF p.frame THEN p.spr2 = "CD" ELSE p.spr2 = "EF"
END IF
END IF
' Jump
IF p.jmp THEN
xx% = p.x \ 16
p.ctJmp = p.ctJmp + 1 ' jump counter
IF p.ctJmp = 41 THEN p.jmp = 0
IF (p.y AND 15) = 0 AND yy% > 0 THEN
IF (p.x AND 15) = 0 THEN
IF Screen%(yy% - 1, xx%) = 0 THEN
p.y = p.y - 1
END IF
ELSE
IF Screen%(yy% - 1, xx%) = 0 AND Screen%(yy% - 1, xx% + 1) = 0 THEN
p.y = p.y - 1
END IF
END IF
ELSE
IF p.y > 0 THEN p.y = p.y - 1
END IF
END IF
DEF SEG
END SUB