2019-04-08 19:58:41 +02:00
|
|
|
-- 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.
|
|
|
|
]]
|
|
|
|
|
2019-04-07 14:03:44 +02:00
|
|
|
local cwd = (...):gsub('%.baseworld$', '') .. "."
|
|
|
|
|
2019-04-01 08:08:54 +02:00
|
|
|
local BaseWorld = Object:extend()
|
|
|
|
|
2019-04-29 11:21:41 +02:00
|
|
|
local Sti = require(cwd .. "libs.sti")
|
|
|
|
local CameraSystem = require(cwd .. "camera")
|
2019-04-07 14:03:44 +02:00
|
|
|
|
2019-06-16 10:00:05 +02:00
|
|
|
local PADDING_VALUE = 10/100
|
|
|
|
|
2019-04-07 13:22:23 +02:00
|
|
|
-- INIT FUNCTIONS
|
|
|
|
-- All functions to init the world and the map
|
|
|
|
|
2019-04-07 14:03:44 +02:00
|
|
|
function BaseWorld:new(scene, actorlist, mapfile)
|
2019-04-01 08:08:54 +02:00
|
|
|
self.scene = scene
|
2019-04-07 17:15:27 +02:00
|
|
|
|
2019-04-29 16:40:44 +02:00
|
|
|
self.cameras = CameraSystem(self)
|
2019-05-01 16:25:44 +02:00
|
|
|
self:initActors()
|
2019-04-29 11:21:41 +02:00
|
|
|
|
2019-04-07 17:15:27 +02:00
|
|
|
self:initPlayers()
|
2019-04-07 13:43:24 +02:00
|
|
|
self:setActorList(actorlist)
|
2019-05-01 14:36:40 +02:00
|
|
|
self:initMap(mapfile)
|
2019-05-02 19:51:43 +02:00
|
|
|
self:setGravity()
|
2019-05-28 19:28:05 +02:00
|
|
|
|
|
|
|
self:register()
|
2019-05-30 13:37:55 +02:00
|
|
|
|
|
|
|
self.isActive = true
|
2019-04-01 08:08:54 +02:00
|
|
|
end
|
|
|
|
|
2019-04-07 13:35:49 +02:00
|
|
|
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
|
|
|
|
|
2019-05-01 14:36:40 +02:00
|
|
|
function BaseWorld:initMap(mapfile)
|
|
|
|
self.haveMap = false
|
|
|
|
self.haveBackgroundColor = false
|
|
|
|
self.backcolor = {128, 128, 128}
|
|
|
|
self.mapfile = mapfile
|
2019-04-07 14:03:44 +02:00
|
|
|
end
|
|
|
|
|
2019-05-02 19:51:43 +02:00
|
|
|
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
|
|
|
|
|
2019-05-28 19:28:05 +02:00
|
|
|
function BaseWorld:register()
|
|
|
|
self.scene:registerWorld(self)
|
|
|
|
end
|
|
|
|
|
2019-04-07 13:22:23 +02:00
|
|
|
-- ACTOR MANAGEMENT FUNCTIONS
|
|
|
|
-- Basic function to handle actors
|
|
|
|
|
2019-05-01 16:25:44 +02:00
|
|
|
function BaseWorld:initActors( )
|
|
|
|
self.actors = {}
|
2019-06-16 10:08:59 +02:00
|
|
|
self.currentCreationID = 0
|
2019-05-01 16:25:44 +02:00
|
|
|
end
|
|
|
|
|
2019-04-07 13:46:08 +02:00
|
|
|
function BaseWorld:newActor(name, x, y)
|
|
|
|
self.obj.index[name](self, x, y)
|
|
|
|
end
|
|
|
|
|
2019-04-29 16:40:44 +02:00
|
|
|
function BaseWorld:newCollision(name, x, y, w, h)
|
|
|
|
self.obj.collisions[name](self, x, y, w, h)
|
|
|
|
end
|
|
|
|
|
2019-04-01 13:09:21 +02:00
|
|
|
function BaseWorld:registerActor(actor)
|
2019-06-16 10:08:59 +02:00
|
|
|
actor.creationID = self.currentCreationID
|
|
|
|
self.currentCreationID = self.currentCreationID + 1
|
2019-04-01 13:09:21 +02:00
|
|
|
table.insert(self.actors, actor)
|
2019-04-01 08:08:54 +02:00
|
|
|
end
|
|
|
|
|
2019-04-07 13:36:21 +02:00
|
|
|
function BaseWorld:removeActor(actor)
|
2019-04-07 13:31:25 +02:00
|
|
|
for i,v in ipairs(self.actors) do
|
|
|
|
if v == actor then
|
|
|
|
table.remove(self.actors, i)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-04-07 13:36:21 +02:00
|
|
|
function BaseWorld:moveActor(actor, x, y, filter)
|
2019-04-07 13:31:25 +02:00
|
|
|
-- 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
|
|
|
|
|
2019-05-05 13:01:00 +02:00
|
|
|
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
|
|
|
|
|
2019-04-07 13:36:21 +02:00
|
|
|
function BaseWorld:queryRect(x, y, w, h)
|
2019-04-07 13:31:25 +02:00
|
|
|
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
|
|
|
|
|
2019-04-01 13:09:21 +02:00
|
|
|
function BaseWorld:countActors()
|
|
|
|
return #self.actors
|
2019-04-01 12:47:08 +02:00
|
|
|
end
|
|
|
|
|
2019-04-07 13:36:21 +02:00
|
|
|
function BaseWorld:getActors()
|
2019-04-07 13:31:25 +02:00
|
|
|
return self.actors
|
|
|
|
end
|
|
|
|
|
2019-06-16 10:00:05 +02:00
|
|
|
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
|
|
|
|
return self:queryRect(x, y, w, h)
|
|
|
|
end
|
|
|
|
|
2019-04-29 16:40:44 +02:00
|
|
|
-- 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
|
|
|
|
|
2019-04-07 17:15:27 +02:00
|
|
|
-- PLAYER MANAGEMENT FUNCTIONS
|
|
|
|
-- Basic function to handle player actors
|
|
|
|
|
2019-05-01 14:36:40 +02:00
|
|
|
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
|
|
|
|
|
2019-04-07 17:15:27 +02:00
|
|
|
function BaseWorld:initPlayers()
|
|
|
|
self.players = {}
|
2019-05-01 17:21:38 +02:00
|
|
|
self.playerNumber = 1
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseWorld:setPlayerNumber(playerNumber)
|
|
|
|
self.playerNumber = playerNumber or 1
|
2019-04-07 17:15:27 +02:00
|
|
|
end
|
|
|
|
|
2019-04-29 15:03:28 +02:00
|
|
|
function BaseWorld:addPlayer(actor, sourceid, haveCam)
|
2019-04-07 17:15:27 +02:00
|
|
|
local player = {}
|
|
|
|
player.actor = actor
|
|
|
|
player.sourceid = sourceid or 1
|
|
|
|
|
|
|
|
table.insert(self.players, player)
|
2019-04-29 15:03:28 +02:00
|
|
|
|
|
|
|
if (haveCam) then
|
|
|
|
local xx, yy = player.actor:getViewCenter()
|
|
|
|
self.cameras:addView(xx, yy, player.actor)
|
|
|
|
end
|
2019-04-07 17:15:27 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function BaseWorld:sendInputToPlayers(actor)
|
|
|
|
for i,v in ipairs(self.players) do
|
|
|
|
--TODO: make the player get from a selected source inputs
|
2019-04-07 22:46:28 +02:00
|
|
|
local keys = self.scene.sources[v.sourceid].keys
|
|
|
|
v.actor:getInput(keys)
|
2019-04-07 17:15:27 +02:00
|
|
|
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
|
|
|
|
|
2019-04-07 14:03:44 +02:00
|
|
|
-- MAP FUNCTIONS
|
|
|
|
-- All map wrappers
|
|
|
|
|
2019-04-29 16:40:44 +02:00
|
|
|
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
|
2019-06-15 11:50:53 +02:00
|
|
|
if (object.properties.batchActor) then
|
|
|
|
self:batchActor(objectlayer.name, object)
|
|
|
|
else
|
|
|
|
self:newActor(objectlayer.name, object.x, object.y)
|
|
|
|
end
|
2019-04-29 16:40:44 +02:00
|
|
|
end
|
|
|
|
self.map:removeLayer(objectlayer.name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-06-15 11:50:53 +02:00
|
|
|
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
|
|
|
|
|
2019-04-29 16:40:44 +02:00
|
|
|
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
|
2019-05-01 17:21:38 +02:00
|
|
|
if (i <= self.playerNumber) then
|
2019-04-29 16:40:44 +02:00
|
|
|
-- TODO: don't hardcode camera handling
|
2019-05-01 17:21:38 +02:00
|
|
|
self:addPlayer(self.obj.Player(self, object.x, object.y), i, true)
|
|
|
|
end
|
2019-04-29 16:40:44 +02:00
|
|
|
i = i + 1
|
|
|
|
end
|
|
|
|
self.map:removeLayer(objectlayer.name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-04-07 14:03:44 +02:00
|
|
|
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
|
|
|
|
|
2019-05-30 13:37:55 +02:00
|
|
|
-- 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
|
|
|
|
|
2019-04-07 13:22:23 +02:00
|
|
|
-- UPDATE FUNCTIONS
|
|
|
|
-- All update functions
|
|
|
|
|
2019-04-01 08:08:54 +02:00
|
|
|
function BaseWorld:update(dt)
|
2019-04-07 14:03:44 +02:00
|
|
|
self:updateMap(dt)
|
2019-04-07 17:15:27 +02:00
|
|
|
self:sendInputToPlayers(dt)
|
2019-04-07 14:06:04 +02:00
|
|
|
self:updateActors(dt)
|
2019-04-29 15:03:28 +02:00
|
|
|
self.cameras:update(dt)
|
2019-04-07 14:06:04 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function BaseWorld:updateActors(dt)
|
2019-04-22 09:36:29 +02:00
|
|
|
local actors = self:getActors()
|
|
|
|
for i,v in ipairs(actors) do
|
2019-04-01 08:08:54 +02:00
|
|
|
v:update(dt)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-04-07 14:03:44 +02:00
|
|
|
function BaseWorld:updateMap(dt)
|
|
|
|
if self.haveMap then
|
|
|
|
self.map:update(dt)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2019-04-07 13:22:23 +02:00
|
|
|
-- DRAW FUNCTIONS
|
|
|
|
-- All function to draw the map, world and actors
|
|
|
|
|
2019-04-01 08:08:54 +02:00
|
|
|
function BaseWorld:draw(dt)
|
2019-04-07 14:03:44 +02:00
|
|
|
self:drawBackgroundColor()
|
2019-04-29 11:21:41 +02:00
|
|
|
local camNumber = self.cameras:getViewNumber()
|
|
|
|
|
|
|
|
if (camNumber == 0) then
|
|
|
|
self:drawMap()
|
|
|
|
self:drawActors()
|
|
|
|
else
|
|
|
|
for i=1, camNumber do
|
2019-05-02 17:21:48 +02:00
|
|
|
self.cameras:attachView(i)
|
2019-04-29 11:21:41 +02:00
|
|
|
self:drawMap(i)
|
|
|
|
self:drawActors(i)
|
2019-05-02 17:21:48 +02:00
|
|
|
self.cameras:detachView(i)
|
2019-06-13 22:23:23 +02:00
|
|
|
self.cameras:drawHUD(i)
|
2019-04-29 11:21:41 +02:00
|
|
|
end
|
|
|
|
end
|
2019-04-07 14:06:04 +02:00
|
|
|
end
|
|
|
|
|
2019-04-29 11:21:41 +02:00
|
|
|
function BaseWorld:drawActors(id)
|
2019-06-16 10:00:05 +02:00
|
|
|
local actors
|
|
|
|
if (id == nil) then
|
|
|
|
actors = self:getActors()
|
|
|
|
else
|
|
|
|
actors = self:getVisibleActors(id)
|
|
|
|
end
|
2019-04-22 09:36:29 +02:00
|
|
|
for i,v in ipairs(actors) do
|
2019-04-07 14:06:04 +02:00
|
|
|
v:draw()
|
2019-04-01 08:08:54 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-04-29 11:21:41 +02:00
|
|
|
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:getViewCoordinate(id)
|
|
|
|
scale = self.cameras:getViewScale(id) or 1
|
2019-05-02 17:34:35 +02:00
|
|
|
local vx, vy = self.cameras:getOnScreenViewRelativePosition(id)
|
2019-05-02 16:21:24 +02:00
|
|
|
tx = math.floor(tx - math.abs(vx))
|
|
|
|
ty = math.floor(ty - math.abs(vy))
|
2019-04-29 11:21:41 +02:00
|
|
|
end
|
|
|
|
|
2019-04-07 14:03:44 +02:00
|
|
|
if self.haveMap then
|
2019-04-29 11:21:41 +02:00
|
|
|
self.map:draw(-tx, -ty, scale, scale)
|
2019-04-07 14:03:44 +02:00
|
|
|
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
|
|
|
|
|
2019-04-01 08:08:54 +02:00
|
|
|
return BaseWorld
|