8c1e9d8e05
For the moment it doesn't add any real feature, but it allow the mainHitbox to be an external object to the actor, giving to it more power.
445 lines
11 KiB
Lua
445 lines
11 KiB
Lua
-- baseworld.lua :: the base world object, that contain just a fast implementation
|
|
-- of a 2D world. It doesn't support collision and stuff.
|
|
|
|
--[[
|
|
Copyright © 2019 Kazhnuz
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
the Software without restriction, including without limitation the rights to
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
]]
|
|
|
|
local cwd = (...):gsub('%.baseworld$', '') .. "."
|
|
|
|
local BaseWorld = Object:extend()
|
|
|
|
local Sti = require(cwd .. "libs.sti")
|
|
local CameraSystem = require(cwd .. "camera")
|
|
|
|
local PADDING_VALUE = 10/100
|
|
|
|
-- INIT FUNCTIONS
|
|
-- All functions to init the world and the map
|
|
|
|
function BaseWorld:new(scene, actorlist, mapfile)
|
|
self.scene = scene
|
|
self.actorlist = actorlist
|
|
self.mapfile = mapfile
|
|
|
|
self.cameras = CameraSystem(self)
|
|
self:initActors()
|
|
|
|
self:initPlayers()
|
|
self:setActorList(self.actorlist)
|
|
self:initMap(self.mapfile)
|
|
self:setGravity()
|
|
|
|
self:register()
|
|
|
|
self.isActive = true
|
|
end
|
|
|
|
function BaseWorld:setActorList(actorlist)
|
|
if actorlist == nil then
|
|
error("FATAL: You must set an actorlist to your world")
|
|
else
|
|
self.obj = require(actorlist)
|
|
end
|
|
end
|
|
|
|
function BaseWorld:initMap(mapfile)
|
|
self.haveMap = false
|
|
self.haveBackgroundColor = false
|
|
self.backcolor = {128, 128, 128}
|
|
self.mapfile = mapfile
|
|
end
|
|
|
|
function BaseWorld:setGravity(xgrav, ygrav, isDefault)
|
|
local xgrav = xgrav or 0
|
|
local ygrav = ygrav or 0
|
|
local isDefault = isDefault or 0
|
|
|
|
self.gravity = {}
|
|
self.gravity.xgrav, self.gravity.ygrav = xgrav, ygrav
|
|
self.gravity.isDefault = isDefault
|
|
end
|
|
|
|
function BaseWorld:register()
|
|
self.scene:registerWorld(self)
|
|
end
|
|
|
|
function BaseWorld:reset()
|
|
self:initActors()
|
|
self:initPlayers()
|
|
self:initMap(self.mapfile)
|
|
self.cameras:initViews()
|
|
collectgarbage()
|
|
|
|
self:loadMap()
|
|
end
|
|
|
|
-- ACTOR MANAGEMENT FUNCTIONS
|
|
-- Basic function to handle actors
|
|
|
|
function BaseWorld:initActors( )
|
|
self.actors = {}
|
|
self.currentCreationID = 0
|
|
end
|
|
|
|
function BaseWorld:newActor(name, x, y)
|
|
self.obj.index[name](self, x, y)
|
|
end
|
|
|
|
function BaseWorld:newCollision(name, x, y, w, h)
|
|
self.obj.collisions[name](self, x, y, w, h)
|
|
end
|
|
|
|
function BaseWorld:registerActor(actor)
|
|
actor.creationID = self.currentCreationID
|
|
self.currentCreationID = self.currentCreationID + 1
|
|
table.insert(self.actors, actor)
|
|
end
|
|
|
|
function BaseWorld:removeActor(actor)
|
|
for i,v in ipairs(self.actors) do
|
|
if v == actor then
|
|
table.remove(self.actors, i)
|
|
end
|
|
end
|
|
end
|
|
|
|
function BaseWorld:moveActor(actor, x, y, filter)
|
|
-- as the baseworld have no collision function, we return empty collision
|
|
-- datas, but from the same type than bump2D will return
|
|
return x, y, {}, 0
|
|
end
|
|
|
|
function BaseWorld:checkCollision(actor, x, y, filter)
|
|
-- as the baseworld have no collision function, we return empty collision
|
|
-- datas, but from the same type than bump2D will return
|
|
return x, y, {}, 0
|
|
end
|
|
|
|
function BaseWorld:queryRect(x, y, w, h)
|
|
local query = {}
|
|
local x2, y2 = x + w, y + h
|
|
for i,v in ipairs(self.actors) do
|
|
if (v.x >= x) and (v.x + v.w >= x1) and
|
|
(v.y >= y) and (v.y + v.h >= y1) then
|
|
|
|
table.insert(query, v)
|
|
end
|
|
end
|
|
|
|
return v
|
|
end
|
|
|
|
function BaseWorld:countActors()
|
|
return #self.actors
|
|
end
|
|
|
|
function BaseWorld:getActors()
|
|
return self.actors
|
|
end
|
|
|
|
function BaseWorld:getVisibleActors(id)
|
|
local camx, camy, camw, camh = self.cameras:getViewCoordinate(id)
|
|
local paddingw = camw * PADDING_VALUE
|
|
local paddingh = camh * PADDING_VALUE
|
|
local x = camx - paddingw
|
|
local y = camy - paddingh
|
|
local w = camw + paddingw * 2
|
|
local h = camh + paddingh * 2
|
|
|
|
local query = self:queryRect(x, y, w, h)
|
|
local returnquery = {}
|
|
|
|
for i,v in ipairs(query) do
|
|
table.insert(returnquery, v.owner)
|
|
end
|
|
|
|
return returnquery
|
|
end
|
|
|
|
-- INFO FUNCTIONS
|
|
-- Give infos about the world
|
|
|
|
function BaseWorld:isActorIndexed(name)
|
|
return (self.obj.index[name] ~= nil)
|
|
end
|
|
|
|
function BaseWorld:isCollisionIndexed(name)
|
|
return (self.obj.collisions[name] ~= nil)
|
|
end
|
|
|
|
-- PLAYER MANAGEMENT FUNCTIONS
|
|
-- Basic function to handle player actors
|
|
|
|
function BaseWorld:loadMap()
|
|
local mapfile = self.mapfile
|
|
if mapfile == nil then
|
|
self.haveMap = false
|
|
self.haveBackgroundColor = false
|
|
self.backcolor = {128, 128, 128}
|
|
else
|
|
self.haveMap = true
|
|
self.map = Sti(mapfile)
|
|
self.haveBackgroundColor = true
|
|
self.backcolor = self.map.backgroundcolor or {128, 128, 128}
|
|
self:loadMapObjects()
|
|
end
|
|
end
|
|
|
|
function BaseWorld:initPlayers()
|
|
self.players = {}
|
|
self.playerNumber = 1
|
|
end
|
|
|
|
function BaseWorld:setPlayerNumber(playerNumber)
|
|
self.playerNumber = playerNumber or 1
|
|
end
|
|
|
|
function BaseWorld:addPlayer(actor, sourceid, haveCam)
|
|
local player = {}
|
|
player.actor = actor
|
|
player.sourceid = sourceid or 1
|
|
|
|
table.insert(self.players, player)
|
|
|
|
if (haveCam) then
|
|
local xx, yy = player.actor:getViewCenter()
|
|
self.cameras:addView(xx, yy, player.actor)
|
|
end
|
|
end
|
|
|
|
function BaseWorld:sendInputToPlayers(actor)
|
|
for i,v in ipairs(self.players) do
|
|
--TODO: make the player get from a selected source inputs
|
|
local keys = self.scene.sources[v.sourceid].keys
|
|
v.actor:getInput(keys)
|
|
end
|
|
end
|
|
|
|
function BaseWorld:removePlayer(actor)
|
|
for i,v in ipairs(self.players) do
|
|
if (v.actor == actor) then
|
|
table.remove(self.players, i)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- MAP FUNCTIONS
|
|
-- All map wrappers
|
|
|
|
function BaseWorld:loadMapObjects()
|
|
self:loadMapCollisions()
|
|
self:loadMapPlayers()
|
|
self:loadMapActors()
|
|
end
|
|
|
|
function BaseWorld:loadMapCollisions()
|
|
for k, objectlayer in pairs(self.map.layers) do
|
|
if self:isCollisionIndexed(objectlayer.name) then
|
|
print("DEBUG: loading actors in " .. objectlayer.name .. " collision layer")
|
|
for k, object in pairs(objectlayer.objects) do
|
|
self:newCollision(objectlayer.name, object.x, object.y, object.width, object.height)
|
|
end
|
|
self.map:removeLayer(objectlayer.name)
|
|
end
|
|
end
|
|
end
|
|
|
|
function BaseWorld:loadMapActors()
|
|
for k, objectlayer in pairs(self.map.layers) do
|
|
if self:isActorIndexed(objectlayer.name) then
|
|
print("DEBUG: loading actors in " .. objectlayer.name .. " actor layer")
|
|
for k, object in pairs(objectlayer.objects) do
|
|
if (object.properties.batchActor) then
|
|
self:batchActor(objectlayer.name, object)
|
|
else
|
|
self:newActor(objectlayer.name, object.x, object.y)
|
|
end
|
|
end
|
|
self.map:removeLayer(objectlayer.name)
|
|
end
|
|
end
|
|
end
|
|
|
|
function BaseWorld:batchActor(name, object)
|
|
local gwidth = object.properties.gwidth or self.map.tilewidth
|
|
local gheight = object.properties.gheight or self.map.tileheight
|
|
local x = object.x
|
|
local y = object.y
|
|
local w = object.width
|
|
local h = object.height
|
|
|
|
local cellHor = math.ceil(w / gwidth)
|
|
local cellVert = math.ceil(h / gheight)
|
|
|
|
for i=1, cellHor do
|
|
for j=1, cellVert do
|
|
self:newActor(name, x + (i-1)*gwidth, y + (j-1)*gheight)
|
|
end
|
|
end
|
|
end
|
|
|
|
function BaseWorld:loadMapPlayers()
|
|
for k, objectlayer in pairs(self.map.layers) do
|
|
if (objectlayer.name == "player") then
|
|
print("DEBUG: loading actors in player layer")
|
|
local i = 1
|
|
for k, object in pairs(objectlayer.objects) do
|
|
if (i <= self.playerNumber) then
|
|
-- TODO: don't hardcode camera handling
|
|
self:addPlayer(self.obj.Player(self, object.x, object.y), i, true)
|
|
end
|
|
i = i + 1
|
|
end
|
|
self.map:removeLayer(objectlayer.name)
|
|
end
|
|
end
|
|
end
|
|
|
|
function BaseWorld:getDimensions()
|
|
if self.haveMap then
|
|
return self.map.width * self.map.tilewidth,
|
|
self.map.height * self.map.tileheight
|
|
else
|
|
return core.screen:getDimensions()
|
|
end
|
|
end
|
|
|
|
function BaseWorld:setBackgroundColor(r, g, b)
|
|
self.backcolor = {r, g, b}
|
|
self.haveBackgroundColor = true
|
|
end
|
|
|
|
function BaseWorld:removeBackgroundColor()
|
|
self.haveBackgroundColor = false
|
|
end
|
|
|
|
function BaseWorld:getBackgroundColor()
|
|
return self.backcolor[1]/256, self.backcolor[2]/256, self.backcolor[3]/256
|
|
end
|
|
|
|
-- Lock MANAGEMENT FUNCTIONS
|
|
-- Basic function to handle the lock
|
|
|
|
function BaseWorld:setActivity(activity)
|
|
self.isActive = activity
|
|
end
|
|
|
|
function BaseWorld:switchActivity()
|
|
self.isActive = (self.isActive == false)
|
|
end
|
|
|
|
function BaseWorld:getActivity()
|
|
return self.isActive
|
|
end
|
|
|
|
-- UPDATE FUNCTIONS
|
|
-- All update functions
|
|
|
|
function BaseWorld:update(dt)
|
|
self:updateMap(dt)
|
|
self:sendInputToPlayers(dt)
|
|
self:updateActors(dt)
|
|
self.cameras:update(dt)
|
|
end
|
|
|
|
function BaseWorld:updateActors(dt)
|
|
local actors = self:getActors()
|
|
for i,v in ipairs(actors) do
|
|
v:update(dt)
|
|
end
|
|
end
|
|
|
|
function BaseWorld:updateMap(dt)
|
|
if self.haveMap then
|
|
self.map:update(dt)
|
|
end
|
|
end
|
|
|
|
|
|
-- DRAW FUNCTIONS
|
|
-- All function to draw the map, world and actors
|
|
|
|
function BaseWorld:draw(dt)
|
|
self:drawBackgroundColor()
|
|
local camNumber = self.cameras:getViewNumber()
|
|
|
|
if (camNumber == 0) then
|
|
self:drawMap()
|
|
self:drawActors()
|
|
else
|
|
for i=1, camNumber do
|
|
self.cameras:attachView(i)
|
|
self:drawMap(i)
|
|
self:drawActors(i)
|
|
self.cameras:detachView(i)
|
|
self.cameras:drawHUD(i)
|
|
end
|
|
end
|
|
end
|
|
|
|
function BaseWorld:drawActors(id)
|
|
local actors
|
|
if (id == nil) then
|
|
actors = self:getActors()
|
|
else
|
|
actors = self:getVisibleActors(id)
|
|
end
|
|
|
|
table.sort(actors, function(a,b)
|
|
if (a.depth == b.depth) then
|
|
return a.creationID < b.creationID
|
|
else
|
|
return a.depth > b.depth
|
|
end
|
|
end)
|
|
|
|
for i,v in ipairs(actors) do
|
|
v:draw()
|
|
end
|
|
end
|
|
|
|
function BaseWorld:drawMap(id)
|
|
local tx, ty, scale = 0, 0, 1
|
|
if id ~= nil then
|
|
-- Du à la manière dont fonctionne STI, on est obligé de récupérer les info
|
|
-- de position de camera pour afficher la carte par rapport à ces infos
|
|
tx, ty = self.cameras:getInternalCamCoordinate(id)
|
|
scale = self.cameras:getViewScale(id) or 1
|
|
local vx, vy = self.cameras:getOnScreenViewRelativePosition(id)
|
|
tx = math.floor(tx - math.abs(vx))
|
|
ty = math.floor(ty - math.abs(vy))
|
|
end
|
|
|
|
if self.haveMap then
|
|
self.map:draw(-tx, -ty, scale, scale)
|
|
end
|
|
end
|
|
|
|
function BaseWorld:drawBackgroundColor()
|
|
if self.haveBackgroundColor then
|
|
local r, g, b = self.backcolor[1], self.backcolor[2], self.backcolor[3]
|
|
love.graphics.setColor(r/256, g/256, b/256)
|
|
love.graphics.rectangle("fill", 0, 0, 480, 272)
|
|
utils.graphics.resetColor()
|
|
end
|
|
end
|
|
|
|
return BaseWorld
|