Add missing auto-generated Lua files.
This commit is contained in:
parent
4e99903be5
commit
d37b54f346
180
entity.lua
Normal file
180
entity.lua
Normal file
@ -0,0 +1,180 @@
|
||||
local Object = require("object")
|
||||
local Vector = require("vector")
|
||||
local Tile = require("tile")
|
||||
local helpers = require("helpers")
|
||||
local inspect = require("inspect/inspect")
|
||||
|
||||
local Entity = Object:extend()
|
||||
|
||||
function Entity:init(x, y, w, h, gravity, max_jump_height, horizontal_acc, friction, map)
|
||||
Entity.__super.init(self, x, y, w, h)
|
||||
self.gravity = gravity
|
||||
self.pos = Vector:new(x, y)
|
||||
self.vel = Vector:new(0, 0)
|
||||
self.maxvel = Vector:new(8*8, 8*24)
|
||||
self.width = w
|
||||
self.height = h
|
||||
self.grounded = false
|
||||
self.horizontal_acc = horizontal_acc
|
||||
self.max_jump_height = max_jump_height
|
||||
self.friction = friction
|
||||
self.map = map
|
||||
end
|
||||
|
||||
function Entity:get_rect()
|
||||
return {x=self.pos.x - self.width/2, y=self.pos.y - self.height/2, w=self.width, h=self.height}
|
||||
end
|
||||
|
||||
function Entity:draw()
|
||||
local rect = self:get_rect()
|
||||
love.graphics.setColor(0, 0, 0.8)
|
||||
love.graphics.rectangle("fill", helpers.round(rect.x), helpers.round(rect.y), rect.w, rect.h)
|
||||
love.graphics.setColor(1, 0, 0)
|
||||
love.graphics.circle("fill", self.pos.x, self.pos.y, 1)
|
||||
end
|
||||
|
||||
function Entity:copy()
|
||||
local new = Entity:new(self.pos.x, self.pos.y, self.width, self.height, self.gravity, self.max_jump_height, self.horizontal_acc, self.friction, self.map)
|
||||
new.vel.x = self.vel.x
|
||||
new.vel.y = self.vel.y
|
||||
new.grounded = self.grounded
|
||||
return new
|
||||
end
|
||||
|
||||
-- TODO: check if not grounded and allow air control
|
||||
function Entity:move_horizontally(movement, dt)
|
||||
local x_accel = 0
|
||||
local next_state = self:copy()
|
||||
if movement.right or movement.left then
|
||||
if movement.right then
|
||||
x_accel = self.horizontal_acc
|
||||
else
|
||||
x_accel = -self.horizontal_acc
|
||||
end
|
||||
else
|
||||
if self.vel.x < 0 then
|
||||
x_accel = self.friction
|
||||
elseif self.vel.x > 0 then
|
||||
x_accel = -self.friction
|
||||
end
|
||||
end
|
||||
next_state.vel.x = helpers.bound(self.vel.x + x_accel*dt, -self.maxvel.x, self.maxvel.x)
|
||||
next_state.pos.x = helpers.normalize(self.pos.x + next_state.vel.x*dt, self.width/2, self.map.max_pixel.x + self.width*1.5)
|
||||
|
||||
if self.vel.x < 0 and next_state.vel.x > 0 or self.vel.x > 0 and next_state.vel.x < 0 then
|
||||
next_state.vel.x = 0
|
||||
end
|
||||
|
||||
return next_state
|
||||
end
|
||||
|
||||
function Entity:jump(dt)
|
||||
local next_state = self:copy()
|
||||
next_state.grounded = false
|
||||
next_state.vel.y = -math.sqrt(2*self.max_jump_height*self.gravity)
|
||||
next_state.pos.y = helpers.bound(next_state.pos.y + next_state.vel.y*dt, 0, self.map.max_pixel.y - self.height/2)
|
||||
return next_state
|
||||
end
|
||||
|
||||
function Entity:fall(dt)
|
||||
local next_state = self:copy()
|
||||
next_state.grounded = false
|
||||
next_state.vel.y = self.vel.y + self.gravity*dt
|
||||
next_state.pos.y = helpers.bound(next_state.pos.y + next_state.vel.y*dt, 0, self.map.max_pixel.y - self.height/2)
|
||||
return next_state
|
||||
end
|
||||
|
||||
function Entity:ground()
|
||||
local next_state = self:copy()
|
||||
next_state.grounded = true
|
||||
next_state.vel.y = 0
|
||||
return next_state
|
||||
end
|
||||
|
||||
function Entity:adjust_for_collisions(old_state, dt, frame)
|
||||
local next_state = self:copy()
|
||||
local top_left_tile = self.map:get_tile_from_pixel(next_state.pos)
|
||||
local bottom_left_tile = self.map:get_tile_from_pixel(next_state.pos + Vector:new(0, self.map.tileheight))
|
||||
local bottom_right_tile = self.map:get_tile_from_pixel(next_state.pos + Vector:new(self.map.tilewidth, self.map.tileheight))
|
||||
local top_right_tile = self.map:get_tile_from_pixel(next_state.pos + Vector:new(self.map.tilewidth, 0))
|
||||
|
||||
local next_rect = next_state:get_rect()
|
||||
|
||||
if old_state.grounded and self.vel.y >= 0 then
|
||||
if
|
||||
self.vel.x < 0 and not bottom_left_tile.solid
|
||||
or self.vel.x > 0 and not bottom_right_tile.solid
|
||||
then
|
||||
next_state = next_state:fall(dt)
|
||||
end
|
||||
end
|
||||
if not self.grounded then
|
||||
if self.vel.y < 0 and (
|
||||
top_left_tile.solid and rectangles_overlap(next_rect, top_left_tile.pixel_rect)[2]
|
||||
or
|
||||
top_right_tile.solid and rectangles_overlap(next_rect, top_right_tile.pixel_rect)[2]
|
||||
) then
|
||||
next_state.pos.y = top_right_tile.y + top_right_tile.h - self.height/2
|
||||
next_state.vel.y = 0
|
||||
print(frame, "CEILING BUMP!")
|
||||
elseif self.vel.y >= 0 and (
|
||||
bottom_left_tile.solid and rectangles_overlap(next_rect, bottom_left_tile.pixel_rect)[3]
|
||||
or
|
||||
bottom_right_tile.solid and rectangles_overlap(next_rect, bottom_right_tile.pixel_rect)[3]
|
||||
) then
|
||||
next_state = next_state:ground()
|
||||
print(frame, "GROUNDED BECAUSE OF LANDING")
|
||||
next_state.pos.y = bottom_right_tile.pixel_rect.y - self.height/2
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if old_state.vel.x < 0 then
|
||||
if top_left_tile.solid and rectangles_overlap(next_rect, top_left_tile.pixel_rect)[2] then
|
||||
print(frame, "DETECTED COLLISION WHEN MOVING LEFT TOWARDS", top_left_tile.pixel_rect.x + top_left_tile.pixel_rect.w, "NEXT X:", next_state.pos.x, "CURRENT VEL.X", old_state.vel.x)
|
||||
next_state.vel.x = 0
|
||||
next_state.pos.x = math.ceil(top_left_tile.pixel_rect.x + top_left_tile.w + next_state.width/2) -1
|
||||
print(frame, "ADJUSTED X", next_state.pos.x)
|
||||
end
|
||||
elseif old_state.vel.x > 0 then
|
||||
if top_right_tile.solid and rectangles_overlap(next_rect, top_right_tile.pixel_rect)[2] then
|
||||
next_state.vel.x = 0
|
||||
next_state.pos.x = top_right_tile.pixel_rect.x - self.width*1.5
|
||||
end
|
||||
end
|
||||
|
||||
if next_state.grounded and next_state.vel.y ~= 0 then
|
||||
print(frame, "GROUNDED WITH VERTICAL VELOCITY", next_state.vel.y, "THIS SHOULD NOT HAPPEN")
|
||||
next_state.vel.y = 0
|
||||
end
|
||||
|
||||
return next_state
|
||||
end
|
||||
|
||||
function Entity:move(movement, dt, frame)
|
||||
local wasright = self.vel.x > 0
|
||||
local wasleft = self.vel.x < 0
|
||||
local justjumped = false
|
||||
local accel = Vector:new(0, self.gravity)
|
||||
|
||||
local next_state = self:move_horizontally(movement, dt)
|
||||
|
||||
if self.grounded then
|
||||
if movement.jump then
|
||||
next_state = next_state:jump(dt)
|
||||
end
|
||||
else
|
||||
next_state = next_state:fall(dt)
|
||||
end
|
||||
|
||||
if not (next_state.pos == self.pos) then
|
||||
if distance(self.pos, next_state.pos) > 8 then
|
||||
print(frame, "ENTITY MOVING TOO FAST!", inspect(self.pos), inspect(next_state.pos))
|
||||
-- swept AABB
|
||||
else
|
||||
next_state = next_state:adjust_for_collisions(self, dt, frame)
|
||||
end
|
||||
end
|
||||
return next_state
|
||||
end
|
||||
return Entity
|
47
helpers.lua
Normal file
47
helpers.lua
Normal file
@ -0,0 +1,47 @@
|
||||
local helpers = {}
|
||||
|
||||
function helpers.sign(n)
|
||||
if n == 0 then
|
||||
return 0
|
||||
end
|
||||
return math.abs(n)/n
|
||||
end
|
||||
|
||||
function helpers.round(num)
|
||||
return num >= 0 and math.floor(num + 0.5) or math.ceil(num - 0.5)
|
||||
end
|
||||
|
||||
function helpers.bound(value, min, max)
|
||||
if value and value < min then
|
||||
return min
|
||||
elseif value and value > max then
|
||||
return max
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
function helpers.map(tbl, fun)
|
||||
local result = {}
|
||||
for i, v in ipairs(tbl) do
|
||||
result[i] = fun(v)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function helpers.filter(tbl, fun)
|
||||
local result = {}
|
||||
for i, v in ipairs(tbl) do
|
||||
if fun(v) then
|
||||
table.insert(result, v)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function helpers.normalize(n, min, max)
|
||||
local range = max - min
|
||||
return ((n - min) % range + range) % range + min
|
||||
end
|
||||
|
||||
return helpers
|
53
map.lua
Normal file
53
map.lua
Normal file
@ -0,0 +1,53 @@
|
||||
local Object = require("object")
|
||||
local Tile = require("tile")
|
||||
local helpers = require("helpers")
|
||||
local inspect = require("inspect/inspect")
|
||||
|
||||
local Map = Object:extend()
|
||||
|
||||
function Map:init(filename)
|
||||
Map.__super.init(self)
|
||||
local map = dofile(filename) -- love.filesystem.load(filename)
|
||||
local platform_layers = helpers.filter(map.layers, function (layer) return layer.name == "platforms" end)
|
||||
self.width = map.width
|
||||
self.height = map.height
|
||||
self.tilewidth = map.tilewidth
|
||||
self.tileheight = map.tileheight
|
||||
self.data = platform_layers[1].data
|
||||
self.max_pixel = {x=map.width*map.tilewidth, y=map.height*map.tileheight}
|
||||
end
|
||||
|
||||
function Map:itertiles()
|
||||
local function iterator(map, index)
|
||||
index = index + 1
|
||||
local value = map.data[index]
|
||||
if value ~= nil then
|
||||
local tx = ((index - 1) % map.width) + 1
|
||||
local ty = math.floor((index - 1) / map.width) + 1
|
||||
local tile = Tile:new(tx, ty, map.tilewidth, map.tileheight, value)
|
||||
return index, tile
|
||||
end
|
||||
end
|
||||
return iterator, self, 0
|
||||
end
|
||||
|
||||
function Map:draw()
|
||||
for i, tile in self:itertiles() do
|
||||
love.graphics.setColor(0.9, 0.8, 0.7)
|
||||
if tile.solid then
|
||||
love.graphics.setColor(0.2, 0.2, 0.2)
|
||||
end
|
||||
love.graphics.rectangle("fill", tile.pixel_rect.x, tile.pixel_rect.y, tile.w, tile.h)
|
||||
love.graphics.setColor(0.9, 0.1, 0.3)
|
||||
love.graphics.rectangle("line", tile.pixel_rect.x, tile.pixel_rect.y, tile.w, tile.h)
|
||||
end
|
||||
end
|
||||
|
||||
function Map:get_tile_from_pixel(pixel)
|
||||
local tile_x = math.floor(pixel.x/self.tilewidth) + 1
|
||||
local tile_y = math.floor(pixel.y/self.tileheight) + 1
|
||||
local value = self.data[tile_x + (tile_y - 1)*self.width]
|
||||
return Tile:new(tile_x, tile_y, self.tilewidth, self.tileheight, value)
|
||||
end
|
||||
|
||||
return Map
|
28
object.lua
Normal file
28
object.lua
Normal file
@ -0,0 +1,28 @@
|
||||
local inspect = require("inspect/inspect")
|
||||
local Object = {}
|
||||
Object.__index = Object
|
||||
|
||||
function Object:new(...)
|
||||
local object = setmetatable({__index=self}, self)
|
||||
object.__class = self
|
||||
object:init(...)
|
||||
return object
|
||||
end
|
||||
|
||||
function Object:init(...)
|
||||
self.__args = {...}
|
||||
end
|
||||
|
||||
function Object:extend(SubClass)
|
||||
SubClass = SubClass or {}
|
||||
for k, v in pairs(self) do
|
||||
if k:match("^__") then
|
||||
SubClass[k] = v
|
||||
end
|
||||
end
|
||||
SubClass.__index = SubClass
|
||||
SubClass.__super = self
|
||||
return setmetatable(SubClass, self)
|
||||
end
|
||||
|
||||
return Object
|
115
states.lua
Normal file
115
states.lua
Normal file
@ -0,0 +1,115 @@
|
||||
local Object = require("object")
|
||||
local Entity = require("entity")
|
||||
local Map = require("map")
|
||||
local helpers = require("helpers")
|
||||
|
||||
local GameState = Object:extend()
|
||||
|
||||
function GameState:init()
|
||||
GameState.__super.init(self)
|
||||
self.input = {
|
||||
start=false,
|
||||
right=false,
|
||||
left=false,
|
||||
up=false,
|
||||
down=false,
|
||||
jump=false,
|
||||
}
|
||||
self.ended = false
|
||||
self.next = nil
|
||||
end
|
||||
|
||||
function GameState:updateInput(dt)
|
||||
self.input.start = love.keyboard.isDown("return")
|
||||
self.input.right = love.keyboard.isDown("d", "right")
|
||||
self.input.left = love.keyboard.isDown("a", "left")
|
||||
self.input.up = love.keyboard.isDown("w", "up")
|
||||
self.input.down = love.keyboard.isDown("down", "s")
|
||||
self.input.jump = love.keyboard.isDown("space")
|
||||
end
|
||||
|
||||
function GameState:update(dt)
|
||||
self:updateInput(dt)
|
||||
end
|
||||
|
||||
function GameState:draw()
|
||||
end
|
||||
|
||||
local Play = GameState:extend()
|
||||
|
||||
function Play:init()
|
||||
Play.__super.init(self)
|
||||
self.map = Map:new("assets/map.lua")
|
||||
self.current_frame = 0
|
||||
self.physics = {
|
||||
gravity=self.map.tileheight*9.8, -- somewhat exagerated gravity (3x)
|
||||
maxdx=self.map.tilewidth*8, -- max horizontal speed
|
||||
maxdy=self.map.tileheight*24, -- max vertical speed
|
||||
jump=self.map.tileheight*512, -- instant jump impulse
|
||||
}
|
||||
self.physics.horizontal_acc = self.physics.maxdx*2 -- horizontal acceleration
|
||||
self.physics.friction = self.physics.maxdx*1.5 -- horizontal friction
|
||||
-- TODO: replace x, y (180, 100) with player position from Tiled map
|
||||
self.player_entity = Entity:new(180, 100, 4, 8, self.physics.gravity, 2*8, self.physics.horizontal_acc, self.physics.friction, self.map)
|
||||
end
|
||||
|
||||
function Play:updatePlayer(dt)
|
||||
self.player_entity = self.player_entity:move(self.input, dt, self.current_frame)
|
||||
end
|
||||
|
||||
function Play:updateCamera(dt)
|
||||
end
|
||||
function Play:updateItems(dt)
|
||||
end
|
||||
function Play:updateEnemies(dt)
|
||||
end
|
||||
function Play:updateChirps(dt)
|
||||
end
|
||||
|
||||
function Play:update(dt)
|
||||
Play.__super.update(self, dt)
|
||||
self.current_frame = self.current_frame + 1
|
||||
self:updatePlayer(dt)
|
||||
self:updateCamera(dt)
|
||||
self:updateItems(dt)
|
||||
self:updateEnemies(dt)
|
||||
self:updateChirps(dt)
|
||||
end
|
||||
|
||||
function Play:draw()
|
||||
love.graphics.setColor(0.2, 0.2, 0.2)
|
||||
self.map:draw()
|
||||
love.graphics.setColor(0, 0.8, 0.1)
|
||||
self.player_entity:draw()
|
||||
end
|
||||
|
||||
local Title = GameState:extend()
|
||||
|
||||
function Title:update(dt)
|
||||
Title.__super.update(self, dt)
|
||||
if self.input.start then
|
||||
print("PRESSED START ENDING THIS STATE")
|
||||
self.ended = true
|
||||
self.next = Play:new()
|
||||
end
|
||||
end
|
||||
|
||||
function Title:draw()
|
||||
Title.__super.draw(self)
|
||||
local font = love.graphics.getFont()
|
||||
local height = font:getHeight()
|
||||
local width = font:getWidth("MICHI")
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
love.graphics.print("MICHI", 320/2, 24, 0, 2, 2, width/2, height/2)
|
||||
width = font:getWidth("DRAGON")
|
||||
love.graphics.print("DRAGON", 320/2, 64, 0, 2, 2, width/2, height/2)
|
||||
width = font:getWidth("START")
|
||||
love.graphics.print("START", 320/2, 128, 0, 1, 1, width/2, height/2)
|
||||
end
|
||||
|
||||
|
||||
|
||||
return {
|
||||
Play=Play,
|
||||
Title=Title,
|
||||
}
|
30
tile.lua
Normal file
30
tile.lua
Normal file
@ -0,0 +1,30 @@
|
||||
local inspect = require("inspect/inspect")
|
||||
local Vector = require("vector")
|
||||
local helpers = require("helpers")
|
||||
|
||||
local default_w = 8
|
||||
local default_h = 8
|
||||
|
||||
local Tile = Vector:extend()
|
||||
|
||||
function Tile:init(x, y, w, h, value)
|
||||
Tile.__super.init(self, x, y)
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.pixel_rect = {
|
||||
x=(x - 1)*self.w,
|
||||
y=(y - 1)*self.h,
|
||||
w=self.w,
|
||||
h=self.h,
|
||||
}
|
||||
self.value = value
|
||||
self.solid = not (value == 0 or value == nil)
|
||||
end
|
||||
|
||||
function Tile:from_pixel(pixel, w, h)
|
||||
w = w or default_w
|
||||
h = h or default_h
|
||||
return Tile:new(math.floor(pixel.x/w) + 1, math.floor(pixel.y/h) + 1, w, h)
|
||||
end
|
||||
|
||||
return Tile
|
73
vector.lua
Normal file
73
vector.lua
Normal file
@ -0,0 +1,73 @@
|
||||
local inspect = require("inspect/inspect")
|
||||
local Object = require("object")
|
||||
|
||||
local Vector = Object:extend()
|
||||
|
||||
function Vector:init(x, y)
|
||||
Vector.__super.init(self, x, y)
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.angle = math.atan2(self.x, self.y)
|
||||
end
|
||||
|
||||
function Vector:__add(v)
|
||||
return self.__class:new(self.x + v.x, self.y + v.y)
|
||||
end
|
||||
|
||||
function Vector:__sub(v)
|
||||
return self.__class:new(self.x - v.x, self.y - v.y)
|
||||
end
|
||||
|
||||
function Vector:__mul(obj)
|
||||
if getmetatable(obj) == Vector then
|
||||
-- dot product
|
||||
return self.x*obj.x + self.y*obj.y
|
||||
else
|
||||
-- scalar product
|
||||
return self.__class:new(self.x*obj, self.y*obj)
|
||||
end
|
||||
end
|
||||
|
||||
function Vector:__eq(v)
|
||||
return self.x == v.x and self.y == v.y
|
||||
end
|
||||
|
||||
function Vector:__lt(v)
|
||||
return self.x < v.x and self.y < v.y
|
||||
end
|
||||
|
||||
function Vector:__le(v)
|
||||
return self.x <= v.x and self.y <= v.y
|
||||
end
|
||||
|
||||
function Vector:__gt(v)
|
||||
return self.x > v.x and self.y > v.y
|
||||
end
|
||||
|
||||
function Vector:__ge(v)
|
||||
return self.x >= v.x and self.y >= v.y
|
||||
end
|
||||
|
||||
function Vector:__unm()
|
||||
return self.__class:new(-self.x, -self.y)
|
||||
end
|
||||
|
||||
function Vector:__len() -- magnitude
|
||||
return math.sqrt(self.x^2 + self.y^2)
|
||||
end
|
||||
|
||||
function Vector:normalize()
|
||||
return self.__class:new(self.x/#self, self.y/#self)
|
||||
end
|
||||
|
||||
-- Method to get the clockwise normal of the vector
|
||||
function Vector:normal_cw()
|
||||
return self.__class:new(self.y, -self.x)
|
||||
end
|
||||
|
||||
-- Method to get the counterclockwise normal of the vector
|
||||
function Vector:normal_ccw()
|
||||
return self.__class:new(-self.y, self.x)
|
||||
end
|
||||
|
||||
return Vector
|
Loading…
Reference in New Issue
Block a user