Created
March 19, 2017 07:41
-
-
Save eevee/d468ffae641d71429be152d86958b4cd to your computer and use it in GitHub Desktop.
tile-based pico8 collision i wrote in like an hour or two
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
platscene = { | |
xaccel = 0.5, | |
xmax = 2, | |
gravity = 0.5, | |
ymax = 16, | |
} | |
function platscene:switch() | |
self.mapbbox = {0, 0, 16, 16} | |
self.playerbbox = { | |
0, 0, | |
(critter.w or 1) * 8, | |
(critter.h or 1) * 8, | |
} | |
self.vel = {x=0, y=0} | |
self.ground = false | |
self.walktimer = 0 | |
end | |
function platscene:update() | |
self.debug = {} | |
if self.ground then | |
self.walktimer += 1 | |
end | |
-- collision | |
-- tile-based | |
-- one axis at a time | |
-- only move by pixels | |
local d = { | |
x = int(self.vel.x), | |
y = int(self.vel.y), | |
} | |
self.debugd = d | |
local pbb = self.playerbbox | |
local wasground = self.ground | |
self.ground = false | |
for axis in all{"x", "y"} do | |
local move = abs(d[axis]) | |
local movedir = sgn(self.vel[axis]) | |
local idx = 1 | |
if axis == "y" then | |
idx = 2 | |
end | |
-- move to tile boundary | |
local edge = pbb[idx] | |
local mapedge = self.mapbbox[idx] | |
if movedir > 0 then | |
edge += pbb[idx + 2] | |
mapedge += self.mapbbox[idx + 2] | |
end | |
mapedge *= movedir * 8 | |
local step = min(move, edge * -movedir % 8) | |
move -= step | |
pbb[idx] += movedir * step | |
edge += movedir * step | |
-- move one tile at a time | |
-- always run this loop at | |
-- least once, so we know if | |
-- we're on the ground even | |
-- if not moving | |
local stopped | |
while edge % 8 == 0 do | |
if edge * movedir >= mapedge then | |
stopped = true | |
break | |
end | |
local blocked | |
local mx = edge / 8 | |
if movedir < 0 then | |
mx -= 1 | |
end | |
local my = mx | |
for other = flr(pbb[3 - idx] / 8), flr((pbb[3 - idx] + pbb[5 - idx] - 1) / 8) do | |
if axis == "x" then | |
my = other | |
else | |
mx = other | |
end | |
local s = mget(mx, my) | |
add(self.debug, {mx, my, fget(s, 7)}) | |
if fget(s, 7) or (fget(s, 6) and axis == "y" and movedir > 0) then | |
blocked = true | |
break | |
end | |
end | |
if blocked then | |
stopped = true | |
break | |
end | |
local step = min(8, move) | |
move -= step | |
pbb[idx] += movedir * step | |
edge += movedir * step | |
if move <= 0 then | |
break | |
end | |
end | |
-- handle solid collision | |
if stopped then | |
self.vel[axis] = 0 | |
if axis == "y" and movedir > 0 then | |
self.ground = true | |
if not wasground then | |
self.walktimer = 0 | |
sfx(59) | |
end | |
end | |
end | |
end | |
-- passive | |
self.vel.y = min(self.ymax, self.vel.y + self.gravity) | |
-- player movement | |
-- yes, after the collision! | |
-- i do this for reasons: for | |
-- example, now i can tell if | |
-- the player is trying to | |
-- move via self.vel.x | |
if btn(0) then -- \139 | |
self.vel.x = max(-self.xmax, self.vel.x - self.xaccel) | |
elseif btn(1) then -- \145 | |
self.vel.x = min(self.xmax, self.vel.x + self.xaccel) | |
else | |
self.vel.x = self.vel.x * 3/4 | |
if abs(self.vel.x < self.xaccel) then | |
self.vel.x = 0 | |
end | |
end | |
if btnp(4) then -- \142 | |
if self.ground then | |
self.vel.y = -sqrt(2 * self.gravity * 8 * 1.25) | |
sfx(58) | |
end | |
end | |
end | |
function platscene:draw() | |
cls() | |
local bb = self.mapbbox | |
map(bb[1], bb[2], 0, 0, bb[3] - bb[1], bb[4] - bb[2]) | |
critter:draw_tl( | |
self.playerbbox[1], | |
self.playerbbox[2], | |
not self.ground or (self.vel.x ~= 0 and self.walktimer % 30 > 15)) | |
rect(self.playerbbox[1], self.playerbbox[2], self.playerbbox[1] + self.playerbbox[3] - 1, self.playerbbox[2] + self.playerbbox[4] - 1, 9) | |
for d in all(self.debug) do | |
rect(d[1] * 8, d[2] * 8, d[1] * 8 + 7, d[2] * 8 + 7, d[3] and 8 or 11) | |
end | |
print(""..self.playerbbox[1]..","..self.playerbbox[2].."/"..self.playerbbox[3]..","..self.playerbbox[4], 0, 0, 9) | |
print(self.vel.x..","..self.vel.y, 0, 6, 8) | |
if self.debugd then | |
print(self.debugd.x..","..self.debugd.y, 0, 12, 7) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment