Last active
January 27, 2020 04:59
-
-
Save kevinthompson/d53548f4d3fe3053a1ddeef8e5364b73 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
-- Platformer Engine | |
-- by @kevinthompson | |
-- adapted from @enichan's platformer https://github.com/Enichan/Pico8Platformer | |
platformer={ | |
config={ | |
logfile="log", | |
precision=1, | |
tilesize=8, | |
friction=0.125, | |
gravity=0.25, | |
max_gravity=4, | |
flags={ | |
solid=0 | |
} | |
}, | |
entities={}, | |
configure=function(self, config) | |
local default_config=self.config | |
self.config=self:merge({ default_config, config }) | |
end, | |
init=function(self) | |
for entity in all(self.entities) do | |
entity:init() | |
end | |
end, | |
update=function(self) | |
for entity in all(self.entities) do | |
entity:update() | |
self.physics.update(self, entity) | |
self.animation.update(self, entity) | |
end | |
if (self.camera) self.camera.update(self) | |
end, | |
draw=function(self) | |
for entity in all(self.entities) do | |
entity:draw() | |
end | |
end, | |
entity=function(self, attributes) | |
attributes=attributes or {} | |
local default_attributes={ | |
animation="idle", | |
prev_animation=nil, | |
x=64, | |
y=64, | |
width=3, | |
height=5, | |
jumping=false, | |
frame=1, | |
color=7, | |
flip=false, | |
move_speed=0.5, | |
speed={ | |
x=0, | |
y=0 | |
}, | |
prev_collision={ | |
up=false, | |
down=false, | |
left=false, | |
right=false, | |
}, | |
collision={ | |
up=false, | |
down=false, | |
left=false, | |
right=false, | |
}, | |
animations={ | |
idle={} | |
}, | |
init=function(self) | |
end, | |
update=function(self) | |
end, | |
draw=function(self) | |
local sprite=self.animations[self.animation][self.frame] | |
if sprite~=nil then | |
spr(sprite, self.x, self.y, flr(self.width/8), flr(self.height/8), self.flip) | |
else | |
rectfill(self.x, self.y, self.x+self.width, self.y+self.height, self.color) | |
end | |
end, | |
} | |
local entity=self:merge({default_attributes, attributes}) | |
add(self.entities, entity) | |
return entity | |
end, | |
-- private | |
animation={ | |
update=function(self, entity) | |
if entity.speed.x < 0 then | |
entity.flip=true | |
elseif entity.speed.x > 0 then | |
entity.flip=false | |
end | |
end | |
}, | |
physics={ | |
update=function(self, entity) | |
self.physics.apply_gravity(self, entity) | |
self.physics.apply_friction(self, entity) | |
self.physics.resolve_collision(self, entity) | |
end, | |
apply_gravity=function(self, entity) | |
if not entity.collision.down then | |
local gravity = self.config.gravity | |
local max_gravity = self.config.max_gravity | |
local speed_y = entity.speed.y | |
entity.speed.y = min(max_gravity, speed_y + gravity) | |
entity.y += entity.speed.y | |
end | |
end, | |
apply_friction=function(self, entity) | |
if entity.collision.down and entity.speed.x ~= 0 then | |
entity.speed.x -= sgn(entity.speed.x) * min(self.config.friction, abs(entity.speed.x)) | |
end | |
end, | |
resolve_collision=function(self, entity) | |
local speed = entity.speed | |
local steps = 1 | |
local max_speed = max(abs(speed.x), abs(speed.y)) | |
if max_speed >= 0.25 then | |
steps=ceil(max_speed / 0.25) | |
end | |
for i=1, steps do | |
entity.x += speed.x / steps | |
entity.y += speed.y / steps | |
self:resolve_collision_left(entity) | |
self:resolve_collision_right(entity) | |
self:resolve_collision_up(entity) | |
self:resolve_collision_down(entity) | |
end | |
end | |
}, | |
resolve_collision_up=function(self, entity) | |
local flags = self.config.flags | |
local tilesize = self.config.tilesize | |
local min_x = entity.x | |
local min_y = entity.y | |
local max_x = entity.x + entity.width | |
local max_y = min_y | |
local tiles = self:get_tiles(min_x, min_y, max_x, max_y) | |
entity.prev_collision.up = entity.collision.up | |
entity.collision.up = false | |
for tile in all(tiles) do | |
if fget(tile.sprite, flags.solid) then | |
entity.speed.y = 0 | |
entity.y = tile.y + tilesize | |
break | |
end | |
end | |
end, | |
resolve_collision_down=function(self, entity) | |
local min_x = entity.x | |
local min_y = entity.y + entity.height + 1 | |
local max_x = entity.x + entity.width | |
local max_y = min_y | |
local tiles = self:get_tiles(min_x, min_y, max_x, max_y) | |
entity.prev_collision.down = entity.collision.down | |
entity.collision.down = false | |
for tile in all(tiles) do | |
if fget(tile.sprite, self.config.flags.solid) then | |
entity.speed.y = 0 | |
entity.y = tile.y - entity.height - 1 | |
entity.collision.down = true | |
break | |
end | |
end | |
end, | |
resolve_collision_left=function(self, entity) | |
local flags = self.config.flags | |
local tilesize = self.config.tilesize | |
local min_x = entity.x | |
local min_y = entity.y | |
local max_x = min_x | |
local max_y = entity.y + entity.height | |
local tiles = self:get_tiles(min_x, min_y, max_x, max_y) | |
entity.prev_collision.left = entity.collision.left | |
entity.collision.left = false | |
for tile in all(tiles) do | |
if fget(tile.sprite, flags.solid) then | |
entity.speed.x = 0 | |
entity.x = tile.x + tilesize | |
break | |
end | |
end | |
end, | |
resolve_collision_right=function(self, entity) | |
local flags = self.config.flags | |
local tilesize = self.config.tilesize | |
local min_x = entity.x + entity.width + 1 | |
local min_y = entity.y | |
local max_x = min_x | |
local max_y = entity.y + entity.height | |
local tiles = self:get_tiles(min_x, min_y, max_x, max_y) | |
entity.prev_collision.right = entity.collision.right | |
entity.collision.right = false | |
for tile in all(tiles) do | |
if fget(tile.sprite, flags.solid) then | |
entity.speed.x = 0 | |
entity.x = tile.x - entity.width - 1 | |
break | |
end | |
end | |
end, | |
merge=function(self, tables) | |
local result={} | |
for t in all(tables) do | |
for k,v in pairs(t) do | |
if (type(result[k])=="table" and type(v)=="table") then | |
result[k]=self:merge({result[k],v}) | |
else | |
result[k]=v | |
end | |
end | |
end | |
return result | |
end, | |
log=function(self, obj, overwrite) | |
printh(self:tostring(obj), self.config.logfile, overwrite) | |
end, | |
tostring=function(self, any) | |
if type(any)=="table" then | |
local str="{" | |
local add_comma=false | |
for k,v in pairs(any) do | |
str=str..(add_comma and ", " or " ") | |
str=str..k.."="..self:tostring(v) | |
add_comma=true | |
end | |
return str.." }" | |
else | |
return tostr(any) | |
end | |
end, | |
get_tiles=function(self, min_x, min_y, max_x, max_y) | |
local tilesize=self.config.tilesize | |
local tiles={ | |
self:tget(min_x, min_y), | |
self:tget(min_x, max_y), | |
self:tget(max_x, min_y), | |
self:tget(max_x, max_y), | |
} | |
for x = min_x + tilesize, max_x - tilesize, tilesize do | |
for y = min_y + tilesize, max_y - tilesize, tilesize do | |
add(tiles, self:tget(x, y)) | |
end | |
end | |
return tiles | |
end, | |
tget=function(self,x,y) | |
local mx=flr(x/8) | |
local my=flr(y/8) | |
local sprite=mget(mx,my) | |
return { | |
x=mx*8, | |
y=my*8, | |
mx=mx, | |
my=my, | |
sprite=sprite, | |
flags=fget(sprite) | |
} | |
end | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment