Merge branch 'new-cameras' of game-projects/gamecore into master

This commit is contained in:
Kazhnuz 2019-06-29 21:53:57 +02:00 committed by Gitea
commit ce48e451c1
6 changed files with 158 additions and 22 deletions

View file

@ -23,6 +23,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **world:** Add a way to automatically load hitbox from a file - **world:** Add a way to automatically load hitbox from a file
- **utils:** Add basic table functions
- **camera:** Add two new camera types: "middle" and "zoom".
### Changed ### Changed
- **world2D:** Use a list for bodies (hitboxes, etc) and one other for actors - **world2D:** Use a list for bodies (hitboxes, etc) and one other for actors
@ -35,6 +39,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **world:** Make object creation more customizable by worlds - **world:** Make object creation more customizable by worlds
- **camera:** Make mode configuration configurable
### Fixed ### Fixed
- **world:** Remove a forgotten camera debug function - **world:** Remove a forgotten camera debug function

View file

@ -225,17 +225,14 @@ function BaseWorld:setPlayerNumber(playerNumber)
self.playerNumber = playerNumber or 1 self.playerNumber = playerNumber or 1
end end
function BaseWorld:addPlayer(actor, sourceid, haveCam) function BaseWorld:addPlayer(actor, sourceid)
local player = {} local player = {}
player.actor = actor player.actor = actor
player.sourceid = sourceid or 1 player.sourceid = sourceid or 1
table.insert(self.players, player) table.insert(self.players, player)
if (haveCam) then self.cameras:addTarget(player.actor)
local xx, yy = player.actor:getViewCenter()
self.cameras:addView(xx, yy, player.actor)
end
end end
function BaseWorld:sendInputToPlayers(actor) function BaseWorld:sendInputToPlayers(actor)
@ -319,7 +316,7 @@ function BaseWorld:newCollisionFromMap(objectlayer, object)
end end
function BaseWorld:addPlayerFromMap(object, i) function BaseWorld:addPlayerFromMap(object, i)
self:addPlayer(self.obj.Player(self, object.x, object.y), i, true) self:addPlayer(self.obj.Player(self, object.x, object.y), i)
end end
function BaseWorld:loadMapPlayers() function BaseWorld:loadMapPlayers()
@ -361,6 +358,13 @@ function BaseWorld:getBackgroundColor()
return self.backcolor[1]/256, self.backcolor[2]/256, self.backcolor[3]/256 return self.backcolor[1]/256, self.backcolor[2]/256, self.backcolor[3]/256
end end
function BaseWorld:resizeMap(w, h)
if self.haveMap then
local w, h = utils.math.floorCoord(w, h)
self.map:resize(w, h)
end
end
-- Lock MANAGEMENT FUNCTIONS -- Lock MANAGEMENT FUNCTIONS
-- Basic function to handle the lock -- Basic function to handle the lock
@ -412,8 +416,8 @@ function BaseWorld:draw(dt)
self:drawActors() self:drawActors()
else else
for i=1, camNumber do for i=1, camNumber do
self.cameras:attachView(i)
self:drawMap(i) self:drawMap(i)
self.cameras:attachView(i)
self:drawActors(i) self:drawActors(i)
self.cameras:detachView(i) self.cameras:detachView(i)
self.cameras:drawHUD(i) self.cameras:drawHUD(i)
@ -448,10 +452,12 @@ function BaseWorld:drawMap(id)
-- Du à la manière dont fonctionne STI, on est obligé de récupérer les info -- 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 -- de position de camera pour afficher la carte par rapport à ces infos
tx, ty = self.cameras:getInternalCamCoordinate(id) tx, ty = self.cameras:getInternalCamCoordinate(id)
scale = self.cameras:getViewScale(id) or 1 scale = self.cameras:getViewScale(id) or 2
local vx, vy = self.cameras:getOnScreenViewRelativePosition(id) local vx, vy = self.cameras:getOnScreenViewRelativePosition(id)
tx = math.floor(tx - math.abs(vx)) tx = math.floor(tx - math.abs(vx))
ty = math.floor(ty - math.abs(vy)) ty = math.floor(ty - math.abs(vy))
local w, h = core.screen:getDimensions()
end end
if self.haveMap then if self.haveMap then

View file

@ -37,11 +37,19 @@ function CameraSystem:new(world)
self.scene = world.scene self.scene = world.scene
self.world = world self.world = world
self.mode = "split"
self.verticalSplit = SPLITSCREEN_ISVERTICAL self.verticalSplit = SPLITSCREEN_ISVERTICAL
self.targets = {}
self:initViews() self:initViews()
end end
function CameraSystem:setMode(mode)
self.mode = mode
print("Camera system mode set to " .. mode)
return mode
end
function CameraSystem:initViews() function CameraSystem:initViews()
self.views = {} self.views = {}
@ -143,6 +151,18 @@ end
-- WRAPPER and UTILS -- WRAPPER and UTILS
-- Access data from the views -- Access data from the views
function CameraSystem:addTarget(target)
if (#self.views < SCREEN_LIMIT) then
if (#self.views.list == 0) or (self.mode == "split") then
local x, y = target:getViewCenter()
self:addView(x, y, target)
table.insert(self.targets, target)
elseif (self.mode == "middle") or (self.mode == "zoom") then
table.insert(self.targets, target)
end
end
end
function CameraSystem:addView(x, y, target) function CameraSystem:addView(x, y, target)
if (#self.views.list < SCREEN_LIMIT) then if (#self.views.list < SCREEN_LIMIT) then
local id = #self.views.list + 1 local id = #self.views.list + 1
@ -203,13 +223,14 @@ end
function CameraSystem:getViewCoordinate(id) function CameraSystem:getViewCoordinate(id)
local view = self:getView(id) local view = self:getView(id)
local cam = self:getViewCam(id)
local viewx, viewy, vieww, viewh local viewx, viewy, vieww, viewh
viewx = view.pos.x - (self.views.width/2) viewx = view.pos.x - ((self.views.width/2) / cam.scale)
viewy = view.pos.y - (self.views.height/2) viewy = view.pos.y - ((self.views.height/2) / cam.scale)
vieww = self.views.width vieww = self.views.width / cam.scale
viewh = self.views.height viewh = self.views.height / cam.scale
return viewx, viewy, vieww, viewh return viewx, viewy, vieww, viewh
end end
@ -218,10 +239,12 @@ function CameraSystem:getInternalCamCoordinate(id)
local cam = self:getViewCam(id) local cam = self:getViewCam(id)
local viewx, viewy, vieww, viewh local viewx, viewy, vieww, viewh
viewx = cam.x - (self.views.width/2) viewx = cam.x - ((self.views.width/2) / cam.scale)
viewy = cam.y - (self.views.height/2) viewy = cam.y - ((self.views.height/2) / cam.scale)
vieww, viewh = core.screen:getDimensions() vieww, viewh = core.screen:getDimensions()
vieww = vieww / cam.scale
viewh = viewh / cam.scale
return viewx, viewy, vieww, viewh return viewx, viewy, vieww, viewh
end end
@ -287,8 +310,12 @@ end
function CameraSystem:update(dt) function CameraSystem:update(dt)
for i,v in ipairs(self.views.list) do for i,v in ipairs(self.views.list) do
if (self.mode == "middle") or (self.mode == "zoom") then
self:followAllActors(i)
else
self:followActor(i) self:followActor(i)
end end
end
end end
function CameraSystem:moveView(id, x, y) function CameraSystem:moveView(id, x, y)
@ -321,6 +348,53 @@ function CameraSystem:followActor(id)
end end
end end
function CameraSystem:followAllActors(id)
local view = self:getView(id)
local PADDING = 16
-- TODO: make all the padding and stuff part of object definition instead ?
-- It would especially allow better work in future fake3D worlds
if (#self.targets > 0) then
local minX, minY, maxX, maxY
for i, target in ipairs(self.targets) do
local xx, yy = target:getViewCenter()
-- If start by initializing the value at the first found value
if (minX == nil) then minX = xx - (target.w/2) end
if (maxX == nil) then maxX = xx + (target.w/2) end
if (minY == nil) then minY = yy - (target.h/2) end
if (maxY == nil) then maxY = yy + (target.h/2) end
minX = math.min(minX, xx - (target.w/2))
maxX = math.max(maxX, xx + (target.w/2))
minY = math.min(minY, yy - (target.h/2))
maxY = math.max(maxY, yy + (target.h/2))
end
-- Add padding
minX = minX - PADDING
minY = minY - PADDING
maxX = maxX + PADDING
maxY = maxY + PADDING
local x, y
x = (minX + maxX) / 2
y = (minY + maxY) / 2
local scale = 1
if (self.mode == "zoom") then
local ww, hh = core.screen:getDimensions()
local scalex = (maxX-minX)/ww
local scaley = (maxY-minY)/hh
scale = math.max(scale, scalex, scaley)
view.cam.scale = 1/scale
self.world:resizeMap(ww * 3, hh * 3)
end
self:moveView(id, x, y)
end
end
-- DRAW FUNCTIONS -- DRAW FUNCTIONS
-- Basic callback to draw stuff -- Basic callback to draw stuff

View file

@ -82,10 +82,7 @@ function World2D:addPlayer(actor, sourceid, haveCam)
table.insert(self.players, player) table.insert(self.players, player)
if (haveCam) then self.cameras:addTarget(player.actor)
local xx, yy = player.actor:getViewCenter()
self.cameras:addView(xx, yy, player.actor)
end
end end
-- MAP LOADING FUNCTIONS -- MAP LOADING FUNCTIONS
@ -119,7 +116,7 @@ function World2D:newCollisionFromMap(objectlayer, object)
end end
function World2D:addPlayerFromMap(object, i) function World2D:addPlayerFromMap(object, i)
self:addPlayer(self.obj.Player(self, object.x, object.y), i, true) self:addPlayer(self.obj.Player(self, object.x, object.y), i)
end end
-- BODIES MANAGEMENT FUNCTIONS -- BODIES MANAGEMENT FUNCTIONS

View file

@ -27,5 +27,6 @@ local cwd = (...):gsub('%.init$', '') .. "."
return { return {
math = require(cwd .. "math"), math = require(cwd .. "math"),
graphics = require(cwd .. "graphics"), graphics = require(cwd .. "graphics"),
filesystem = require(cwd .. "filesystem") filesystem = require(cwd .. "filesystem"),
table = require(cwd .. "table")
} }

52
gamecore/utils/table.lua Normal file
View file

@ -0,0 +1,52 @@
-- loveutils.table : simple functions for table manipulation and computation.
-- TODO: could be a part of loveutils.math ?
--[[
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 Table = {}
function Table.reduce(list, fn)
local acc
for k, v in ipairs(list) do
if 1 == k then
acc = v
else
acc = fn(acc, v)
end
end
return acc
end
function Table.sum(table)
local sum = 0
for _, v in pairs(table) do
sum = sum + v
end
return sum
end
function Table.average(table)
return Table.sum(table) / #table
end
return Table