Add missing auto-generated Lua files.

This commit is contained in:
Gonzalo Delgado 2024-09-02 10:37:49 -03:00
parent 4e99903be5
commit d37b54f346
7 changed files with 526 additions and 0 deletions

180
entity.lua Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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