From a60058522b224c1acbab56a2c723cc6306c7be4b Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sun, 30 Jun 2019 17:07:03 +0200 Subject: [PATCH 01/16] chore(baseworld): make drawing reordering part of getVisibleActors(id) --- gamecore/modules/world/baseworld.lua | 46 +++++++++++++++------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/gamecore/modules/world/baseworld.lua b/gamecore/modules/world/baseworld.lua index 858cbf1..52a5487 100644 --- a/gamecore/modules/world/baseworld.lua +++ b/gamecore/modules/world/baseworld.lua @@ -144,15 +144,30 @@ 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 actors = {} + if (id ~= nil) then + 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:getActorsInRect(x, y, w, h) + actors = self:getActorsInRect(x, y, w, h) + else + actors = self:getActors() + 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) + + return actors end -- BODIES MANAGEMENT FUNCTIONS @@ -426,20 +441,7 @@ function BaseWorld:draw(dt) 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) + local actors = self:getVisibleActors(id) for i,v in ipairs(actors) do v:draw() From 2004efa558b7a7f31b306e4cb7bf0e9090d99d4e Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sun, 30 Jun 2019 17:07:58 +0200 Subject: [PATCH 02/16] feat(world): add initial fake3D world implementation --- CHANGELOG.md | 2 + gamecore/modules/world/actors/actor3D.lua | 209 ++++++++++++++++++ .../modules/world/actors/utils/hitbox3D.lua | 129 +++++++++++ gamecore/modules/world/world3D.lua | 144 ++++++++++++ 4 files changed, 484 insertions(+) create mode 100644 gamecore/modules/world/actors/actor3D.lua create mode 100644 gamecore/modules/world/actors/utils/hitbox3D.lua create mode 100644 gamecore/modules/world/world3D.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 84d802a..181810d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **camera:** Add two new camera types: "middle" and "zoom". +- **world:** Add a fake 3D world, à la Zelda or BeatThemAll + ### Changed - **world2D:** Use a list for bodies (hitboxes, etc) and one other for actors diff --git a/gamecore/modules/world/actors/actor3D.lua b/gamecore/modules/world/actors/actor3D.lua new file mode 100644 index 0000000..2ae451f --- /dev/null +++ b/gamecore/modules/world/actors/actor3D.lua @@ -0,0 +1,209 @@ +-- actor3D.lua :: the implementation of a 2D actor. It contain every element +-- needed to create your own 2D actors. + +--[[ + 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('%.actor3D$', '') .. "." +local BaseActor = require(cwd .. "baseactor") +local Actor3D = BaseActor:extend() + +local Hitbox = require(cwd .. "utils.hitbox3D") + +-- INIT FUNCTIONS +-- Initialise the actor and its base functions + +function Actor3D:new(world, type, x, y, z, w, h, d, isSolid) + Actor3D.super.new(self, world, type, x, y, z, w, h, d, isSolid) + self:initHitboxes() +end + +function Actor3D:destroy() + self.world:removeActor(self) + self.mainHitbox:destroy() + self.isDestroyed = true +end + +-- PHYSICS FUNCTIONS +-- Handle movement and collisions. + +function Actor3D:autoMove(dt) + self:updateHitboxes() + self.onGround = false + self:applyGravity(dt) + + local dx, dy, dz = self:getFuturePosition(dt) + local newx, newy, newz, cols, colNumber = self:move(dx, dy, dz) + + -- apply after the movement the friction, until the player stop + -- note: the friction is applied according to the delta time, + -- thus the friction should be how much speed is substracted in 1 second + + self:solveAllCollisions(cols) + + self:applyFriction(dt) +end + +function Actor3D:changeSpeedToCollisionNormal(normal) + local xsp, ysp, zsp = self.xsp, self.ysp, self.zsp + local nx, ny, nz = normal.x, normal.y, normal.z + + if (nx < 0 and xsp > 0) or (nx > 0 and xsp < 0) then + xsp = -xsp * self.bounceFactor + end + + if (ny < 0 and ysp > 0) or (ny > 0 and ysp < 0) then + ysp = -ysp * self.bounceFactor + end + + if (nz < 0 and zsp > 0) or (nz > 0 and zsp < 0) then + zsp = -zsp * self.bounceFactor + end + + self.xsp, self.ysp, self.zsp = xsp, ysp, zsp +end + +function Actor3D:move(dx, dy, dz) + local cols, colNumber = {}, 0 + if (self.isDestroyed == false) then + self.x, self.y, self.z, cols, colNumber = self.mainHitbox:checkCollision(dx, dy, dz, self.filter) + self.mainHitbox:updatePosition() + end + return self.x, self.y, self.z, cols, colNumber +end + +function Actor3D:checkCollision(dx, dy, dz) + local x, y, z, cols, colNumber = dx, dy, dz, {}, 0 + if (self.isDestroyed == false) then + x, y, z, cols, colNumber = self.mainHitbox:checkCollision(dx, dy, dz, self.filter) + end + return self.x, self.y, self.z, cols, colNumber +end + +-- GRAVITY SYSTEM FUNCTIONS +-- All functions related to gravity + +function Actor3D:applyGravity(dt) + self.zsp = self.zsp - (self.grav * dt) + + if utils.math.sign(self.zsp) == utils.math.sign(self.grav) then + self:checkGround( ) + end +end + +function Actor3D:checkGround() + local dx, dy, dz = self.x, self.y, self.z + utils.math.sign(self.grav) + local newx, newy, newz, cols, colNumber = self:checkCollision(dx, dy, dz) + + for i, col in ipairs(cols) do + if (col.type == "touch") or (col.type == "bounce") or (col.type == "slide") then + if not (self.grav == 0) then + if col.normal.z ~= utils.math.sign(self.grav) then self.onGround = true end + end + end + end +end + +-- COORDINATE/MOVEMENT FUNCTIONS +-- Handle coordinate + +function Actor3D:getViewCenter() + local x, y, z = self:getCenter() + return x, y - (self.d/2) +end + +-- HITBOXES FUNCTIONS +-- Functions related to actor hitboxes + +function Actor3D:addHitboxFromFrameData(framedata, animationID, frameID, hitboxID) + local sx, sy = self:getSpriteScalling() + local type = framedata[1] + local ox = framedata[2] + local oy = framedata[3] + local oz = framedata[4] + local w = framedata[5] + local h = framedata[6] + local d = framedata[7] + local isSolid = framedata[8] or false + local anim = animationID or "null" + local frame = frameID or 0 + local id = hitboxID or 0 + if (sx < 0) then + ox = self.w - ox - w + end + if (sy < 0) then + oz = self.d - oz - d + end + + if (type == "main") then + self.mainHitbox:modify(ox, oy, oz, w, h, d) + else + local hitboxName = anim .. frame .. type .. id + self:addHitbox(hitboxName, type, ox, oy, oz, w, h, d, isSolid) + return hitboxName + end +end + +function Actor3D:initMainHitbox() + self.mainHitbox = Hitbox(self, self.type, 0, 0, 0, self.w, self.h, self.d, self.isSolid) + self.mainHitbox:advertiseAsMainHitbox() +end + +function Actor3D:addHitbox(name, type, ox, oy, oz, w, h, d, isSolid) + if (self.hitboxes[name] ~= nil) then + print("ERROR:", "The hitbox " .. name .. " already exists") + else + local hitbox = Hitbox(self, type, ox, oy, oz, w, h, d, isSolid) + self.hitboxes[name] = hitbox + return hitbox + end +end + +function Actor3D:checkHitboxCollisions(name, filter) + self:checkHitboxCollisionsAtPoint(name, self.x, self.y, self.z, filter) +end + +function Actor3D:checkHitboxCollisionsAtPoint(name, dx, dy, dz, filter) + local x, y, z, cols, colNumber = dx, dy, dz, {}, 0 + local filter = filter or self.filter + if (self.isDestroyed == false) and (self.hitboxes[name] ~= nil) then + x, y, z, cols, colNumber = self.hitboxes[name]:checkCollision(dx, dy, dz, filter) + local type = self.hitboxes[name].type + + for i, col in ipairs(cols) do + self:hitboxResponse(name, type, col) + end + end + + return x, y, z, cols, colNumber +end + +-- DRAW FUNCTIONS +-- Draw the actors. + +function Actor3D:draw() + self:drawStart() + local x, y = math.floor(self.x), math.floor(self.y - self.z) + self:drawSprite(x, y) + self:drawEnd() +end + +return Actor3D diff --git a/gamecore/modules/world/actors/utils/hitbox3D.lua b/gamecore/modules/world/actors/utils/hitbox3D.lua new file mode 100644 index 0000000..61d444c --- /dev/null +++ b/gamecore/modules/world/actors/utils/hitbox3D.lua @@ -0,0 +1,129 @@ +-- hitbox3D.lua :: a basic 3D hitbox object. It's used by the actors to check +-- collisions and to handle different type of responses. + +--[[ + 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 Hitbox3D = Object:extend() + +-- INIT FUNCTIONS +-- Initialise the actor and its base functions + +function Hitbox3D:new(owner, type, ox, oy, oz, w, h, d, isSolid) + self.owner = owner + self.world = owner.world + + self.type = type + self.ox = ox + self.oy = oy + self.oz = oz + self.x, self.y, self.z = self:getPosition() + self.w = w + self.h = h + self.d = d + self.isSolid = isSolid + + self.isMainHitBox = false + + self:setDebugColor(0,0,0) + self:register() +end + +function Hitbox3D:advertiseAsMainHitbox() + self.isMainHitBox = true +end + +function Hitbox3D:modify(ox, oy, oz, w, h, d) + self.ox = ox + self.oy = oy + self.oz = oz + self.x, self.y, self.z = self:getPosition() + self.w = w + self.h = h + self.d = d +end + +function Hitbox3D:setDebugColor(r,g,b) + self.debug = {} + self.debug.r = r + self.debug.g = g + self.debug.b = b +end + +function Hitbox3D:register() + self.world:registerBody(self) +end + +function Hitbox3D:destroy() + self.world:removeBody(self) +end + +-- COORDINATE FUNCTIONS +-- Handle Hitbox position + +function Hitbox3D:updatePosition() + self.x, self.y, self.z = self:getPosition() + self.world:updateBody(self) + return self.x, self.y, self.z +end + +function Hitbox3D:getPosition() + return self.ox + self.owner.x, self.oy + self.owner.y, self.oz + self.owner.z +end + +function Hitbox3D:getOwnerPosition() + return self.x - self.ox, self.y - self.oy, self.z - self.oz +end + +function Hitbox3D:getNewOwnerPosition(x, y, z) + return x - self.ox, y - self.oy, z - self.oz +end + +function Hitbox3D:getCenter() + return self.x + (self.w/2), self.y + (self.h/2), self.z + (self.d/2) +end + +-- COLLISION FUNCTIONS +-- Handle Hitbox position + +function Hitbox3D:checkCollision(dx, dy, dz, filter) + self:updatePosition() + + local dx, dy = self.ox + dx, self.oy + dy, self.oz + dz + local x, y, z, cols, colNumber = self.world:checkCollision(self, dx, dy, dz, filter) + local newx, newy, newz = self:getNewOwnerPosition(x, y, z) + + return newx, newy, newz, cols, colNumber +end + +-- DRAW FUNCTIONS +-- Just some debug function to draw hitbox + +function Hitbox3D:draw() + local x, y, z = self:getPosition() + love.graphics.setColor(self.debug.r, self.debug.g, self.debug.b, 1) + utils.graphics.box(x, (y-z) - (self.d), self.w, self.h) + love.graphics.setColor(self.debug.r/2, self.debug.g/2, self.debug.b/2, 1) + utils.graphics.box(x, (y-z) - (self.d) + (self.h), self.w, self.d) + utils.graphics.resetColor() +end + +return Hitbox3D diff --git a/gamecore/modules/world/world3D.lua b/gamecore/modules/world/world3D.lua new file mode 100644 index 0000000..4a68d9c --- /dev/null +++ b/gamecore/modules/world/world3D.lua @@ -0,0 +1,144 @@ +-- world3D.lua :: a basic fake3D world based on bump-2dpd. + +--[[ + 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('%.world3D$', '') .. "." + +local BaseWorld = require(cwd .. "baseworld") +local World3D = BaseWorld:extend() + +local Sti = require(cwd .. "libs.sti") +local Bump = require(cwd .. "libs.bump") +local Bump3D = require(cwd .. "libs.bump-3dpd") +local CameraSystem = require(cwd .. "camera") + +function World3D:new(scene, actorlist, mapfile) + World3D.super.new(self, scene, actorlist, mapfile) +end + +-- ACTORS FUNCTIONS +-- Add support for bodies in Actor functions + +function World3D:initActors() + self.currentCreationID = 0 + self.actors = {} + self.bodies = Bump3D.newWorld(50) +end + +function World3D:newActor(name, x, y, z) + self.obj.index[name](self, x, y, z) +end + +function World3D:newCollision(name, x, y, z, w, h, d) + self.obj.collisions[name](self, x, y, z, w, h, d) +end + +function World3D:moveActor(actor, x, y, z, filter) + return self.bodies:move(actor.mainHitbox, x, y, z, filter) +end + +function World3D:getActorsInRect(x, y, w, h) + -- Just a placeholder before adding a better algorythm + World3D.super.getActorsInRect(x, y, w, h) +end + +function World3D:getVisibleActors(id) + + return self.actors +end + +-- PLAYER FUNCTIONS +-- Load player stuff + +function World3D:addPlayer(actor, sourceid, haveCam) + local player = {} + player.actor = actor + player.sourceid = sourceid or 1 + + table.insert(self.players, player) + + self.cameras:addTarget(player.actor) +end + +-- MAP LOADING FUNCTIONS +-- Handle loading of actors from map + +function World3D:batchActor(objectlayer, object) + local name = objectlayer.name + 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 z = object.properties.z or 0 + 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, z) + end + end +end + +function World3D:newActorFromMap(objectlayer, object) + local z = object.properties.z or 0 + self:newActor(objectlayer.name, object.x, object.y, z) +end + +function World3D:newCollisionFromMap(objectlayer, object) + local z = object.properties.z or 0 + local d = object.properties.d or 16 + self:newCollision(objectlayer.name, object.x, object.y, z, object.width, object.height, d) +end + +function World3D:addPlayerFromMap(object, i) + local z = object.properties.z or 0 + self:addPlayer(self.obj.Player(self, object.x, object.y, z), i) +end + +-- BODIES MANAGEMENT FUNCTIONS +-- Basic function to handle bodies. Wrappers around Bump2D functions + +function World3D:registerBody(body) + return self.bodies:add(body, body.x, body.y, body.z, body.w, body.h, body.d) +end + +function World3D:updateBody(body) + return self.bodies:update(body, body.x, body.y, body.z, body.w, body.h, body.d) +end + +function World3D:removeBody(body) + return self.bodies:remove(body) +end + +function World3D:checkCollision(body, x, y, z, filter) + return self.bodies:check(body, x, y, z, filter) +end + +function World3D:getBodiesInRect(x, y, w, h) + return {} --self.bodies:queryRect(x, y, w, h) +end + +return World3D From 0687bc4cfe04591003b452106f1bb8d78f3a6d14 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sun, 30 Jun 2019 17:10:16 +0200 Subject: [PATCH 03/16] feat(examples): add an initial fake3D example based on moveplayer --- .../gameplay/moveplayer3D/actors/init.lua | 13 + .../gameplay/moveplayer3D/actors/parent.lua | 13 + .../gameplay/moveplayer3D/actors/player.lua | 39 ++ .../gameplay/moveplayer3D/actors/wall.lua | 14 + .../gameplay/moveplayer3D/assets/arena.lua | 380 ++++++++++++++++++ .../gameplay/moveplayer3D/assets/arena.tmx | 108 +++++ .../moveplayer3D/assets/overworld.png | Bin 0 -> 13788 bytes .../moveplayer3D/assets/overworld.tsx | 4 + examples/gameplay/moveplayer3D/init.lua | 40 ++ 9 files changed, 611 insertions(+) create mode 100644 examples/gameplay/moveplayer3D/actors/init.lua create mode 100644 examples/gameplay/moveplayer3D/actors/parent.lua create mode 100644 examples/gameplay/moveplayer3D/actors/player.lua create mode 100644 examples/gameplay/moveplayer3D/actors/wall.lua create mode 100644 examples/gameplay/moveplayer3D/assets/arena.lua create mode 100644 examples/gameplay/moveplayer3D/assets/arena.tmx create mode 100644 examples/gameplay/moveplayer3D/assets/overworld.png create mode 100644 examples/gameplay/moveplayer3D/assets/overworld.tsx create mode 100644 examples/gameplay/moveplayer3D/init.lua diff --git a/examples/gameplay/moveplayer3D/actors/init.lua b/examples/gameplay/moveplayer3D/actors/init.lua new file mode 100644 index 0000000..9d67a55 --- /dev/null +++ b/examples/gameplay/moveplayer3D/actors/init.lua @@ -0,0 +1,13 @@ +local Obj = {} + +-- On charge toutes les différentes types d'acteurs +local cwd = (...):gsub('%.init$', '') .. "." +Obj.Player = require(cwd .. "player") + +Obj.index = {} +Obj.index["player"] = Obj.Player + +Obj.collisions = {} +Obj.collisions["wall"] = require(cwd .. "wall") + +return Obj diff --git a/examples/gameplay/moveplayer3D/actors/parent.lua b/examples/gameplay/moveplayer3D/actors/parent.lua new file mode 100644 index 0000000..2a43c98 --- /dev/null +++ b/examples/gameplay/moveplayer3D/actors/parent.lua @@ -0,0 +1,13 @@ +local Base = require "gamecore.modules.world.actors.actor3D" +local Parent = Base:extend() + +function Parent:new(world, type, x, y, z, w, h, d, isSolid) + self.scene = world.scene + Parent.super.new(self, world, type, x, y, z, w, h, d, isSolid) +end + +function Parent:draw() + self:drawMainHitbox() +end + +return Parent diff --git a/examples/gameplay/moveplayer3D/actors/player.lua b/examples/gameplay/moveplayer3D/actors/player.lua new file mode 100644 index 0000000..ea3875a --- /dev/null +++ b/examples/gameplay/moveplayer3D/actors/player.lua @@ -0,0 +1,39 @@ +local cwd = (...):gsub('%.player$', '') .. "." +local Parent = require(cwd .. "parent") +local Player = Parent:extend() + +function Player:new(world, x, y, z, id) + Player.super.new(self, world, "player", x, y, 0, 16, 16, 24, true) + self:setGravity(480) +end + +function Player:updateStart(dt) + self.xfrc, self.yfrc = 480*3, 480*3 + + if self.keys["up"].isDown then + self.ysp = -120 + end + if self.keys["down"].isDown then + self.ysp = 120 + end + if self.keys["left"].isDown then + self.xsp = -120 + end + if self.keys["right"].isDown then + self.xsp = 120 + end + + if self.keys["A"].isDown then + self.zsp = 280 + end +end + +function Player:draw() + Player.super.draw(self) +end + +function Player:drawHUD(id) + love.graphics.print(id .. " test", 4, 4) +end + +return Player diff --git a/examples/gameplay/moveplayer3D/actors/wall.lua b/examples/gameplay/moveplayer3D/actors/wall.lua new file mode 100644 index 0000000..1706f85 --- /dev/null +++ b/examples/gameplay/moveplayer3D/actors/wall.lua @@ -0,0 +1,14 @@ +local Base = require "gamecore.modules.world.actors.actor3D" +local Wall = Base:extend() + +function Wall:new(world, x, y, z, w, h, d) + Wall.super.new(self, world, "wall", x, y, z, w, h, d, true) + self:setDebugColor(0,0,0) +end + +function Wall:draw() + self:drawMainHitbox() + utils.graphics.resetColor( ) +end + +return Wall diff --git a/examples/gameplay/moveplayer3D/assets/arena.lua b/examples/gameplay/moveplayer3D/assets/arena.lua new file mode 100644 index 0000000..f7ac116 --- /dev/null +++ b/examples/gameplay/moveplayer3D/assets/arena.lua @@ -0,0 +1,380 @@ +return { + version = "1.2", + luaversion = "5.1", + tiledversion = "1.2.2", + orientation = "orthogonal", + renderorder = "right-down", + width = 30, + height = 30, + tilewidth = 16, + tileheight = 16, + nextlayerid = 5, + nextobjectid = 18, + properties = {}, + tilesets = { + { + name = "overworld", + firstgid = 1, + filename = "overworld.tsx", + tilewidth = 16, + tileheight = 16, + spacing = 0, + margin = 0, + columns = 32, + image = "overworld.png", + imagewidth = 512, + imageheight = 240, + tileoffset = { + x = 0, + y = 0 + }, + grid = { + orientation = "orthogonal", + width = 16, + height = 16 + }, + properties = {}, + terrains = {}, + tilecount = 480, + tiles = {} + } + }, + layers = { + { + type = "tilelayer", + id = 1, + name = "Calque de Tile 1", + x = 0, + y = 0, + width = 30, + height = 30, + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + properties = {}, + encoding = "lua", + data = { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 399, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 400, 3, + 3, 339, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 402, 337, 3, + 3, 339, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 339, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 337, 3, + 3, 431, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 432, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 + } + }, + { + type = "tilelayer", + id = 2, + name = "Rochers", + x = 0, + y = 0, + width = 30, + height = 30, + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + properties = {}, + encoding = "lua", + data = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, 0, 0, 0, 84, 85, 0, 0, 0, 0, 116, 117, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 116, 117, 0, 0, 0, 0, 0, 0, 0, 0, 116, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 117, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 116, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, 0, 116, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 116, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + } + }, + { + type = "objectgroup", + id = 3, + name = "player", + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + draworder = "topdown", + properties = {}, + objects = { + { + id = 1, + name = "", + type = "", + shape = "rectangle", + x = 48, + y = 80, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = { + ["id"] = 1 + } + }, + { + id = 2, + name = "", + type = "", + shape = "rectangle", + x = 416, + y = 80, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = { + ["id"] = 1 + } + }, + { + id = 3, + name = "", + type = "", + shape = "rectangle", + x = 48, + y = 416, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = { + ["id"] = 3 + } + }, + { + id = 4, + name = "", + type = "", + shape = "rectangle", + x = 416, + y = 416, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = { + ["id"] = 4 + } + } + } + }, + { + type = "objectgroup", + id = 4, + name = "wall", + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + draworder = "topdown", + properties = {}, + objects = { + { + id = 5, + name = "", + type = "", + shape = "rectangle", + x = 0, + y = 0, + width = 480, + height = 64, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 6, + name = "", + type = "", + shape = "rectangle", + x = 448, + y = 64, + width = 32, + height = 416, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 7, + name = "", + type = "", + shape = "rectangle", + x = 32, + y = 448, + width = 416, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 8, + name = "", + type = "", + shape = "rectangle", + x = 0, + y = 64, + width = 32, + height = 416, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 9, + name = "", + type = "", + shape = "rectangle", + x = 112, + y = 128, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 10, + name = "", + type = "", + shape = "rectangle", + x = 272, + y = 128, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 12, + name = "", + type = "", + shape = "rectangle", + x = 368, + y = 112, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 13, + name = "", + type = "", + shape = "rectangle", + x = 192, + y = 224, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 14, + name = "", + type = "", + shape = "rectangle", + x = 352, + y = 272, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 15, + name = "", + type = "", + shape = "rectangle", + x = 256, + y = 368, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 16, + name = "", + type = "", + shape = "rectangle", + x = 128, + y = 384, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 17, + name = "", + type = "", + shape = "rectangle", + x = 80, + y = 288, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + } + } + } + } +} diff --git a/examples/gameplay/moveplayer3D/assets/arena.tmx b/examples/gameplay/moveplayer3D/assets/arena.tmx new file mode 100644 index 0000000..29dee38 --- /dev/null +++ b/examples/gameplay/moveplayer3D/assets/arena.tmx @@ -0,0 +1,108 @@ + + + + + +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,399,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,400,3, +3,339,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,337,3, +3,339,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,434,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,339,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,337,3, +3,431,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,306,432,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,84,85,0,0,0,0,0, +0,0,0,0,0,0,0,84,85,0,0,0,0,0,0,0,0,84,85,0,0,0,0,116,117,0,0,0,0,0, +0,0,0,0,0,0,0,116,117,0,0,0,0,0,0,0,0,116,117,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,84,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,116,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,84,85,0,0,0,0,0,0, +0,0,0,0,0,84,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,116,117,0,0,0,0,0,0, +0,0,0,0,0,116,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,84,85,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,84,85,0,0,0,0,0,0,116,117,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,116,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/gameplay/moveplayer3D/assets/overworld.png b/examples/gameplay/moveplayer3D/assets/overworld.png new file mode 100644 index 0000000000000000000000000000000000000000..7823efb868ab0a710e42844253ab1e0933999b10 GIT binary patch literal 13788 zcmbWe`9D-|{62o4GY2!a8DvRfWbI|mPL@Hovb9-?jI2pnD#YN}N+l^m)=^4}tq5fs zBC812IVwBrw7^-0F?w-DS*|71_D4M5?Ew=7OgxG zsP=(CmVFnbN(@O2j$83*-o#X$DMe2RLCjdlXb;$TcSk7#uYwDQ(o!r2eC*OQN zal!vhe?-02$zy+#b6Bi_!F>(J_74@`3>);`dQfG3GhHUn6d;mUMPfH`uyOh4|2Vo2GNQ zRJk;`-|c+NaPN>K2~;M0ra3l)5A{15Q7$b9k|ty26}{@oifvokqi!A1 z6@+QVOQLZ=uWXYRbkUq2c2OQP_2X29X#7No+c1gbkS^NZ5&Z(oywe!m3Z6{Y&Ho{y zLhCr8H*=Gjct4N{p5tE!)rD8Tz3+k&-MRi8;W_W1`N3?P`A7(1!o5+OPP;VT^Q`EoO?lxPL9l z;A8W{d;zM9SyO6mo$ExSvFLjJJ48&I!|oiYvFQTh(}EB)%xr0iX=j6mJy7c&KE6HM zALB0v(vicZQDkIa#QLMdBK7m z9E=f~J5~OsE#HP_bU0+EuZDeC2Y(^e#K*z$3k&(#%s=ZCZMEpr(YiM#C%^2HT{^7R zc04jGpfkhui1b+aXH+&lLsVRT$Y99Xezb?dOs$yu{2{`IHn{LS1P7516)5xa{s@Bg zlN+ms#Tysaj_?^aww-Q6kI{q;Clf%$!Ilc{KGMp`A2I2|R2=I;EhqS~%?~G;kKg<_ zry}tbXa9Bd?lx25`K?o4G$9DP{p&n$BC8pE#H4;x*hkxoqgp5|MB`&eq-pWE?mQ^8N^#y@x5tstlguD9K*vpi5EO4O#D2 zz6Pj>ydE@rGSid1YP9`g;1rgz3*+?FZ7)=L0*g8wgjF$x`1ZVjNViVB@7L9mv6Hj^ z!AZ863zuU$E6)#ZpM>QxgsqdjL`akwz((6vBvA&HK;i}==QN;4S2cgUb1eLB^hCN`_S)Yx zKxYWUF5i&M0`8`S(uuIq=2^j@ZEj4d*O^;ho}%ZW%bPTL*pPR4sbqe5566(+na>x^ zFlkMCy3T{J_aJ1A=9);ACq(~uIPvI7+SuMhJOHzB5^KNS=sTY9W(uG#qjMG72!knr z>FAS#8J2H+5Y(2ZT%EW4O5Jl;8&J+_N{Zs%{v=Ae^XYQ}?VC)SkvvPjrXPLRNFYD7 z0>4x~unTN}PP)oiU<@1kM}u+fa?S!~EJil{8W?1&;l%U}OQ(ALjQ*s2BJE6=hXBwc znU_Hw++Y0A2%VH)8Yj$2Wme0#p53b!gebd(GPzbJY_3EVLy2I(K2T18dlgc-!wTgC z2cA4u5GOcp)XT`mC%Z#AR~ix|F7$1*L7Pko1s)Lk0{VuudqdM4_pU$7(B<^d!!nq~ zlB7O+i~zOEHRBE@m+>%mqVsC)XZKr)EOm04`_1NprZ#11FrwgW&V5yKLT^-?7fd}h zJ$g58`H3Vttzim0;41G}IM$gfjC4Q`#?HkM_DuTV>{V+|3)o|cQ5Pd*`4fORC#3p2 zJCUDUDgt&xqiVe9fM?c=`=2)~fmCP~dwjq%@7RVIev+Iw&9}T(u4ZG6Hn=u{$Sdpe z0p{PE*M_Id&4k8rKVPNXe|QH0`)K-Km>9F3T|=Q7kf}=6^sR+ZbQ`1L(hZvx=}->gy$s2iE6h(W?2jXl!+vtKgM8EJ4*)=%@wU z#c6bnz4*(LY!JFHsB%^*;IPx}?~+$?Og5|en78kG?ek!n?^(HfCx*h_IPpeo{oL_X zk%PMnAAhUewoDdl&X;{&vQaT{@{Pv{F^iTcp>YJ5NSKce9DrmuYE0om{*vwaJ;i@O4F(gW2xO{lIz+hzajGs0!f%J+U_T6mu>K`yuI{eDnRn}HX& zJas74e0#1(ta;nvDi3At1+I@6bBAaSqtlB|K`=bkeCM2RzxbQ$o%He^aw=~L1;mxk zns;-A-30d6^VH!PnV8yr4+ie~>dy6c3Q?$@PitD=Nip0{AE3$Xaxf$B7H-R zp|F<{dRy__Da6NV0sCzY^ylx~%mP)aRiPJ=suQ8PvDpi95OL0~le=MP!}FF@-WFPO zVFTfjE02k`0Ukt<1|A~U9(M*Ucea;%I!U5!ZoB(>ILeWs%8lt+AG(k9Qy-4ml15n< z<&!h7#a1ULeCJayyhHrgk=HoiX1DSSzCbcjw(#i5KZ47z(!eLjBR~J9+D!W z6wuO`izmOWGoAJ6$#ah>%U=9yoPpChgr;}TFF{$-WXJM-qzL9Dl7h>x64kw_q4!$h zMa3`vT`=XNS#*E)>;Jt&pD`*(+OpSf6>P4{0T1eXt9UltE+l|)PH$1_EbNJ-kdJyP zn@>x+y0Nic|HJr~AjL|}Oc^?piYFnyzcC1m#5F z?@(m*g>TV~n*UL2Vjr;kX2m1`Ny3S@G>d2%A$zrJpEl1o+B^QF`HUxk^K0M`>TQV1 zfyyQyX({GW%pv|m@F(f^MfPHL)JKE%b}OI->Ti^^EW)Abct*?P8>YOeOkkaK@HVDrkCo zkOPc?xd1Dn6xn-8)-R1+G?e?aF~(fmZf@xSx5$}EpsGudZLX*vI4j{KKzO0f?|GiX z&JTUQ)#t&|{sk`9+5k*ZQq)O|b(ksT0{icPPuX!uBEq_k3!?{M15X*!s;Ybc=`$wo zufClg?iO#mN6g+^i7j`q9S;2({SgdDk?;^LDdND~_`qi*<)p_?-d<$=Rcxc;w%l)w zf5e6bHihrQ;Kup18r~BVy5rCZWa=f0!tNo% zE-Iy8Uy!`G4(MGeiNG6vvTKuY2cE#$Lzs zTe~B|1>rDu`R#xsK!fX~A=o9?I|&scQwtbd4aj4k*M;c&K+v&JG(i17E#ijq!BF(Y zuM(t26b5_hiHshE-0-$LR|Dr<nef1XAESo0ZnKpzNQqY)69nUq;xxnP$eIM>x zK#?%%IdZ*aH`##b@grD{fL0i93fxDCt7#R(4qLm%zmCPf(D1ueK))K*j=|10e&-+) z)j7~b=szB!%~?Z|F1@u}-i=G%PCW3uZ!*Nkl2I8Ufa0ZmKJvL+##p?|sYVmjwGEds z)DPYfmVn7dz#WYL1m+Xs)X5=|lp%by5}`l#ay-2?W6azoKz#h~AU{#5ZT%+rA;vM( z!I6jzb#chAOZ4&hQX)5FxZS~#?fo*OSF6r+V!JLvQ@^kpK2lbCI}_#EFghQg?+!ot zV7{!Tje?#4UY?7Oisx|(Dc~2PR{w2punRY-a}QU6G^j#nJs(rb86XDmZ!C@Q==Q9AP#Rj><+#bZECPYueGHaC>*fLKEHek`doQIZ|z;0T*LJnI{khUM{~jvQHF$+Nma6l&m#0 zv|>u3Y#x0%Kr-=r?sztJE6FDgbg!hXp7)My*tFY6`s?Dj#MUFaC3LSqFF5?zAD`2R z?`sLqUvh$_n||<#S4UaT$MlsZCZ&Y+ELHD(H$=PiTfYB{{M++9y=8?*f;_SLG3W1j z)dxjPAVb|A$IBKjuB8aziyF5@tAnClx4Ez=Cg<9l-ZyVPD5B_ zivu>Gr{Y1V06H7_N=XadM9aVb6NI1YUl_VDw*7YJTymrk{TA2e!aWDC!95-wHfJ|z z7Dw_g1Zi(TLA4nO)_3H;UkVcgI0mO&U`Go9WuFm+0;kluk|sk3B4ra+>C>`@;GE> zOR7(w%U6Il!xBU+?=O)<-W-^1g(w~~8#w#-^@bW%c#7q0!|?Bw#&0Wk!Q{VmAR`=+ z0A8_Xu_^lU_so}eRfU}^9PHNWf(M~dS(?9XNCI%rYkYlSnAIUMMQl2F4utoN-kc1T zd);BtvT~wFgT@YB_MAj&UW0}!GZJag6O1Fx=nHcB9_a)T^L-IIyOBYlPbt#2l!~(7 zf^no!%8)=$$53jo%&6SC)t73(wkd}zH-SH-6eO5*XBM!#Lmy|NwPEYjPFds_2wJu) zhV`)J`-V5JPXzG=zuL_#zp#V1?`+NA5%9O!aQMcGf)ABNzZUbl6uriq?mr&-zcf+A z7~;cE=G!p5Tl|bbt~ad)^1{!Kl~(E+F5QZ_apFi*z4H1QfgL8GE_Z0z>!8jai6ubU zhzARiA{8%e?t+1mH0g zPaNSF#}BKWsb0q@Yi8~D^*vFf&W3=!Dghajn4CwDgEeVdC65ZFaHYziUGHxFh;jRh z8QtA4OB>Ea%?-giFvQa;qhr`nbqbmT7DYy`K9S1^DF}@XY@g1>^|f=zS4Zy&-K`UT ztPKkMn$2G43|nFQ{MQfj5VI0{rcdK&ZWk0jw$F#bDDt-gmRjA5Qc5=qKSejh)) z5hY5Y!z+B?Se&Q$>FSpf#)@{6j4Sir@J`vrwm;k@w*k@t9SgRQcH1`nO5gL*=i>0W z;SunZA6*FgrARh3rB~{Z%s`UG4cWX~=lhSK(nHY|h|>?ZZ*)nln6E%!Y+zce`)%$*)Fj+DXz-TQcX&@6~87$g|$)qA<)133Jfm z4a|aTmP!nYe1STb$hH3liX-+jcEQ}n zk+2s!v@>5jgt5)^zMx zzOeOmd<~rL<)U6hWJv7tPB2J+85zdO)Ls1d?=iwW3v<7m=SEK>I^vv${xGqyfgN_T zVdUW2m!RjHXrDN)eEjH-KBQ2O+V$xJ2N53e%&Ch9Zhjyhm`)wMv|kXa!v{8>?URH_ zxpKLDWEEWV*TOY$B?=8FLx>-6RJ#`~D+QESlt?}{@Z$sTmy^GjtFV29waxcYe)kDr zhrCAf;qUv{YwlE6|MU+#RsH(*ta}Q_pP#wAD2H-)$vdNtqONP6Yn*38WEiUi;vJ** zN$r*6FS0;(hy?ZVbctt{u~pybwTcI?Cg_*14pj=nQ|dy@ngqP*{-tq|&z7!Qu8YX% z{bB;~ezy)SjmSNS6wenqY*>R&qlQxFo#=l}B3|I$TGN)0KDoj~VWv9{#DD_pMo#A! z-IJc$P!*EV_JlE6^0On#@3Y-U;0${@ja^i>6?!CYMa>3I-%E6(L!7WFZK@$0K<*)Kjy~a@!ACERn zg;!@9X#a2CU9jiL{$7s6;i0^E|At1BzW3Z=XN2thxr)WF#sVQ-%Z}qRKHV_+`|xDA zICHTh!u9n?;%VL6UuWn^4Rb>5bvpybHWU`16x9cz_Y&p;@MkdcgGQ!kl4Vs?g;dcW z8D@@hbY0R|_?vqHI%Zwj>~=BVE>g-e2QKZ_b-BfKTlKveq^ROi)*+qt znp34MruCcsw-OA}qhmn@KkXXz-P5khCWXJf+1=e;@jV(3wI{hcKT-H%ed@g{g**1Dt4P3U zFR%Rzc6vS&F5A1(So9`VJ6CMk{jpcZ<1Y;|RxxiK6-7>MG$164sqk(}w!Guau&94Z z{%G(n`R;6ltl2L=xd=3V+&w7;xm^86FG|eKIybvVfL_2n-m7)rm~bUC<43Sv8cp?t zAbWC*LR)3d;Z*QolK`ElT$vm(+I1=FBcgv|LmVE@j7w?ai?jc%_rsBSi7_qtK6qbk zSJ?7K!v~IbEZK2+ldzQ+eo6MeKn;P~2@@e|^T-WJ_Qjr0Ctpfk)Oa#sy%M(gafy}Z zO!62>5Hu)zX=f7X^;1YC}qx9TM_{g}u4RZj8d&H|a*FmkvcUjY_v3jj(=R zdMwzpRT^#}(2JKvgIHy$xx6m3r82*8d~;n}sr7L`ZqPZU{pI>!J+S=tWiN9KioDue z)Vm96x0s#(-^|#ew`H$DJgALCPmTHTXYbjik*?}F@v*NZYT6Ca$p`itw8ED=xujpG z*CjIv8t=v@K`J}`{`@jVmu*7-=5?oU8Xdv!OY402(WCp^Miai>cnEag1Pp59%I9^$ zWrITOe*vKo#kBe_P7U{p^0+rHpQ;(L;mqSxl$rB@jb4tVtmdO1@A_a$mTCBOb-Z>kVoS*s*~kuw7S_E?Ws9~Jtzn7{W7)f|33vhlT|6;xiH zVsqOYcy5am3fbG1!>Pli`qZ}l*xrW?iH6kU&;uoGdaU`zlugtl#hUEJvV68WNyyW} z?xwi_%l7Nlc;@Zs7=apmjShP+5jE`8f++pcxGwJ6k30(k+xngE@Qfc16s=*YfOCFo{*Muh=%P3w7`4)uc(G`T~$@?v9E-f&9 ziD?(!tX+ASG2wtB-haWh)wo>EU%SdG>B7qbOKSOLO7oY-&N5c*Y(Y?nI=riM*cepx zt-O0H8W=lmIID9PT)Jw<{Zx-S6%}qs2yj9KMQdX1h(s0(D<1r=@_KR zPFCSI_=tWW`UM(6-j9$d9K_s~l12-F%hot!p@HMyNpmOio99Q9JK-_h0O|I5ks+nA zf3Gzt5EM0v<3_-SY4tO9y0dW*yn&``k{U(EG3$HQfV(C&?M@bYV_`leVbM+}<}?y^ zP%h;mPhfx_$Q6P~mqFW0KIm9u&nI5?Z`%~G2dAHoPa&Wknkt--_e{=J)0(~fs8tFd z?Spq$qYe5#Nc7(xq;JtdjCu;^tHi;7^w)F{&^jSw<7Xdn8}-IyFG|aj$jS#8UW)-@ zsDdu^5YiF>XE4PCDztnN7Srhwf(FNc$7K*v9NUXKcn=@=377L}^|)Ja-7b^9cp5)B z7gA+uBIxZMD)9YR+oJ;SnkeX)E%m=`ubHI_w>Ho243wBd=KOgN#BBl~Y4u&3Z`GFQ9w^0tB7$@x=0S0UkF>o1L?!_*|`Vbb=O(Y-5L3O&!!T!fr~ zvi1e;B*GCJ9)8{HLQt}pPb0f(5L(b2cJkM>%Fne+Yv6s$i;gco=`MHpsjo$rZ(+;D zIi`#w@lsmZ`8jy%aZ-vV{apVSK?&+*&)=->gV>a)sK*Uvs8riC2h3{7AIY6z6&Y@b z>cx2d4saszO3Go{5A~e~iTFa43jKc(#U43gF( zeTJ^g+Yd%1g5J%X()xiTyskgX1fqZB<*UC}v75k%o#GPN1qL@AKx^6OuXT^bjXmF zr$gF86K~{z!5wO|g-zadJxAc_VY)w@_J^yyp!sfZwwYAoQb0g|`ddv{@&5b$v`(uY z((hf}Ui6RAughelm+d!}p!JCJN|J}RWG%oXa^{Wz-Cu%!bNR|8k*p7CY^5(<5P6aJ zrzeX-Enp&EMxh*g#_qSwwST!;AnGRJ&o8_~NJ-iy>xhFdUW(0N10xSWjB?ROH%?Jk zPdSzT+CG4>X7J13Xe}t1UxV<68%@CAq0o00`mNFgO%bUSe0aW~KJyeqTzt+iL*VNe z#(P05df@~{YsREf zINEdbh+bk_zBd#eK|2a3zR&P_B;yl$w}=7^ZK}hsUOC$BDbM*|YO!p)XpD(XIMrXZ zfa;zsqfxtZk`(0Qp+=0AJM$wmQ>{&A+5H{LM++m?N4 zLM{ozl*rrDV&Hn0HiFYP2O+>WdI4UrPXHOMI3oMyU&{M>FKZ|WzkOmOPFmUI4Q}R# zxeIUjwwEPQLibt2S0_S+DE@l(TlNy#J?o3kR6dhWaF43GX4sc}qYkh?jt65s=W`$_ z+~BRq^0`%vz)tqjirX=$6#to(MtdXn!I>Yb>tH^r5<(H)majYG*v#zwA>Z0(8{!~b zc{F*k?MU%c(L)FJ=L;w!wE>e6?^@Y(-inFg>|J(*?g2xf0-j>XQ~t3kL6|+4W+Km0 zULW|%_dKNJSE(iK(&{{0W(3@RiG8nqY~vHmj1ATbOI3FK2tqyJ-_sD`c7wS3i}uE^ z19K%Se0WapY5Iddr$==i(&QiL@8e(7-oU%~u2{2$Y8Q$t#K(VS5JSIwzTRfk4la+Y_|pBJfQcRJ5Q|0oqw zlmsdP3cZ|p#ID4xA1{KY4}Y;Lu;Zs+N(B?!22)ZXV)5h`+LZ*LCpcz5!`K*9Dj*Fyek6HBIE4T%AXSnF&$?-2>FXyhdCF_X zhY^e(*z~Rb8cAaxbtY3U&Lxk1VR<}w!BK=HZ=V662>BBUIbixkU-F}IzfYU&SXmg8 z=T4i~*WFnS{w?688ts%lfsrQcgvh!dAxAJQ0$x_{#O(LG&Fj${t8mw3@{@SiE1Oa@ zy#%c&Vqo+A_}H;_JIxqpuD}XJkQ;gMl(B=O7C+lxi@t{^*EKop1fIO}ha>7X^bb6I zM>t&@cVQfp8K6lJKf~+2r5v6o!SiS?#u|Q7--|u`YbP@GDNRX{>eKH{VnlqvofDIo z<)Vo5Rc+I~9DyR@QHG=~my~^en-AD6cU&jvD9H@{bS#s+$qs2`b>6LW zmyw`_C`R@vcCW4sKQA1MJbns~6K#|Dz(ErW=b{uOOtSR_Gj?VGQO4+CRT~F=^VD2U z$d04x$$fm^aKPW(tg;QwTSvR@YAr&+x>6Eoj=|nZM`w(=FllN*AJULx=s?dc&!|g) zRXx=nZ&C>}PLr|Q`19MBZ(jYQprYN2;pT?4L&oIK8#+*mzVY0^UjbX{-fbUWATV@4 zLgv&O7^%?PwUvGRNi5$$hv<$X9o`(@)><}!IbqO*wA-DxFa#orLGK_*XB6e41uE)l7f))8N{(Zg>O(v7^8)&44GhIO4hQ|tP?K|D zyJ>XWKhoT~A>j$TQ!l5G{yAPz74B5O_B$36jrZ{OdN~;b$>U92=6#%=02=` zVLz{#Gg|2wr0_4`9$xj|jUiTprE2vpWM~ok_2u_ogWa1Suf1M`y42`9z#~Ij7#no@ z!=Z;pIg@{*{1oPn8$tf&mbtxd5lfM?ze3_puP5%tExLSP0>w(C*v#w$=GAOE8KD29 zm8)-fM7v*i$;FSpyzE;OpVuEg-I6_;DNuB{^OzB%X2H*Bo?*7|Ft{fo%sewy-p zspFD9*r)?5B5aHU1W4~;%+2e|Z&cWpdFWPxk!RcnvWAtS%v|Z51sl>o25m$7p=y2*V#=O4moUps;RX*<{Sw!sb$rK&I%P zzC*O6&F%f@Uyqp(rJ3gZ-Q^Fz1qg2Mx#tT~I^RVL4Ls|gTd7j*MZa+)Jms3Xf6qHc z@*1VzAduqH5>;~ZX4(58Pnoc--lyAh|LFa#ffaq1Vs_IGwov`%Zau`-YT@CpJ(NaX`EO*o*kg}<4q~Cc zpL@-O87?JvK*}&`g$qxMmxt$OTb5Jf zN2izt)?7|ju2Rh+ca2}&0pY6yys)+2T;VDYG;&#w+IuA#1f2~#fYhYT6AJ|wJ~%Au z?t(K@)LYa9K**!;aPLXb(!hY;*SMZ1oClmd*mG z4C%0=Ct6C_D}(Z0x>|6wF%D=gzfgz*n+n34PM{1!+D(6bSsMb;`^mo!>_>?H7q5{^ zg9(BcuB{`Y3%VCr)UpjU*N~Jtpo$MFAJ%1cqB<9x|WM zh0&qyB%nRN>|8`OL$k|?1bVQ5=v2-}0o3rkN8>UrAhZw^zFNU@SuTYV& zvqF8c=vK}b@VWbG(h8E=%+Y+)FY)v>=HD=LjG{Mc9`O+Bdwpr|wH3;}H`Ue%8;PTa zi(S?6Y3|RP3y=x{E!##erA{ZT+KW8zfZtZEt?a!TJ8uj$C(PM0-5tjEn0p#+n}8>u zHEiH8Y4i^F&2T#`nW4>{=yh9kbh)+|ezWt|CkeiY69)4T^8A?8fAEb0c3gg1B#ttNJr5HjQ<(JZif4Zrh@zcEhWuM|gE^@;*r0VuyC=Yqe;&Nnk2Hn$YC)%c%O zk8HsJI~+owPvgq9)=yWU2W2)HSY;J23pFlZ-56u$%_ld+UKVZ|i7zgsu)^ApZ8zfA ze&C(^KkX<25yYghkL?4Z5Ji=#54TMGpy-Ow4z)AI@#5yW%xHBeY+O#1Zh-}d;d$f~ zT!`9eLKY`R~QN>)Va&(4ueF`2yv#^}U| zP>+g1RhlkaZYOI=lJ!^8I&lZ(XS0@4cwtNVFtvfC(oeP96wt`6vGBe5t%&rOD1%hc$+`)!A+lb*cmn-lyIsF25!HkJTOj2aNZ0_i z!@lv~8RY6WdM3pJ-FUxsju^B$HoLp`#X}kHvsmJt(BWlhI^+TmAriRCYpAi(*nKCr zA~qvn zbn<(3uvxF;LSxgETUn{)HCK=Ly87@lIi_gDd0plg0rHPv#&5n=0g~6Tp({yte$A#I z=MtSF=;!9zX&2YQmD*AYIy(HW@isUaH)Kd4@>!tWV`eIAIGXa1XS zP0t13s6mi=Z*~Yjt&IJT@$TrG(%Z*iX(2ihN-t$HcL+j5j*PsaHzS9$f@#(rmlKLa z+?1XQ)Wm_;(~Y~e5;=#4-G3R6m6BMHeFd*I$2i)-9X0?t)vo zYR2k!Wa&+uq3%&A;^0iJnIi|^pYXdrvNq`KigkKQp|LE-%CIByywv&Q1By-=d2F?|J z`tLd`4D0sl&(2Zajf*dhQC&HZO1F}re?~;YvGlY?p0~lbJ&_BpeXYq`qRg7VvpC`? ziyg|#XZzHA%h(!(tY-oj!y6!j^GfUYL9$rj-`Ix&-_+RrAFqTAg?6gQ(r)L_ECEZ( zR!_HJB1szL^)Iq63VR`k?#MA+0jTZ|Ioxjq)$!cf*{KxMkpUWc;EqTx@t1aNJ$Vv z&by38UV;NT92+&{z7e^5!)ez#O1S#%sw^6m=4Z?2(;MT#g&VWg@?^O cKfMvWJlp%A)DhnKe+vLBGuuO@Cgj-v2R?!O*Z=?k literal 0 HcmV?d00001 diff --git a/examples/gameplay/moveplayer3D/assets/overworld.tsx b/examples/gameplay/moveplayer3D/assets/overworld.tsx new file mode 100644 index 0000000..9b3f454 --- /dev/null +++ b/examples/gameplay/moveplayer3D/assets/overworld.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/examples/gameplay/moveplayer3D/init.lua b/examples/gameplay/moveplayer3D/init.lua new file mode 100644 index 0000000..7475f1d --- /dev/null +++ b/examples/gameplay/moveplayer3D/init.lua @@ -0,0 +1,40 @@ +-- scenes/moveplayer3D :: a basic player movement example in fake3D + +--[[ + 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 Scene = require "gamecore.modules.scenes" +local MovePlayer = Scene:extend() + +local World = require "gamecore.modules.world.world3D" + +function MovePlayer:new() + MovePlayer.super.new(self) + + World(self, "examples.gameplay.moveplayer3D.actors", "examples/gameplay/moveplayer3D/assets/arena.lua") + + self.world:setPlayerNumber(1) + + self.world:loadMap() + self.world.obj.collisions["wall"](self.world, 0,0,-16,1000, 1000, 16) +end + +return MovePlayer From 30a0d59a41219ac58176eb8a4bcd6f30a1cb9fde Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sun, 30 Jun 2019 17:10:29 +0200 Subject: [PATCH 04/16] improvement(examples): register the fake3D example --- examples/init.lua | 1 + examples/mainmenu/init.lua | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/init.lua b/examples/init.lua index cde2dfe..df649cb 100644 --- a/examples/init.lua +++ b/examples/init.lua @@ -6,5 +6,6 @@ return { Inventory = require "examples.menus.inventory", Options = require "examples.menus.options", MovePlayer = require "examples.gameplay.moveplayer", + MovePlayer3D = require "examples.gameplay.moveplayer3D", Plateformer = require "examples.gameplay.plateform" } diff --git a/examples/mainmenu/init.lua b/examples/mainmenu/init.lua index aefc793..7811b23 100644 --- a/examples/mainmenu/init.lua +++ b/examples/mainmenu/init.lua @@ -46,7 +46,7 @@ function MainMenu:new() self:addSubMenu("gameplay", "gameplay") self:addScene("gameplay", examples.MovePlayer, "movable") self:addScene("gameplay", examples.Plateformer, "plateform") - + self:addScene("gameplay", examples.MovePlayer3D, "movable3D") self.menusystem:setSoundFromSceneAssets("navigate") From fc32ce43f545e7a452a6057f13c597f288a95dd8 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sun, 30 Jun 2019 22:04:01 +0200 Subject: [PATCH 05/16] fix(actor3D): fix checkGround not trying the right coordinate --- examples/gameplay/moveplayer3D/actors/parent.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/gameplay/moveplayer3D/actors/parent.lua b/examples/gameplay/moveplayer3D/actors/parent.lua index 2a43c98..b71c7e0 100644 --- a/examples/gameplay/moveplayer3D/actors/parent.lua +++ b/examples/gameplay/moveplayer3D/actors/parent.lua @@ -7,6 +7,7 @@ function Parent:new(world, type, x, y, z, w, h, d, isSolid) end function Parent:draw() + Parent.super.draw(self) self:drawMainHitbox() end From 5f5b4da9c520c7f0042e6e584ebd2d93ef76827d Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sun, 30 Jun 2019 22:04:30 +0200 Subject: [PATCH 06/16] fix(actor3D): fix checkGround not trying the right coordinate --- gamecore/modules/world/actors/actor3D.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gamecore/modules/world/actors/actor3D.lua b/gamecore/modules/world/actors/actor3D.lua index 2ae451f..1cb4d3a 100644 --- a/gamecore/modules/world/actors/actor3D.lua +++ b/gamecore/modules/world/actors/actor3D.lua @@ -102,21 +102,21 @@ end -- All functions related to gravity function Actor3D:applyGravity(dt) - self.zsp = self.zsp - (self.grav * dt) + local grav = self.grav * -1 + self.zsp = self.zsp + (grav * dt) - if utils.math.sign(self.zsp) == utils.math.sign(self.grav) then + if utils.math.sign(self.zsp) == utils.math.sign(grav) then self:checkGround( ) end end function Actor3D:checkGround() - local dx, dy, dz = self.x, self.y, self.z + utils.math.sign(self.grav) + local dx, dy, dz = self.x, self.y, self.z - utils.math.sign(self.grav) local newx, newy, newz, cols, colNumber = self:checkCollision(dx, dy, dz) - for i, col in ipairs(cols) do if (col.type == "touch") or (col.type == "bounce") or (col.type == "slide") then if not (self.grav == 0) then - if col.normal.z ~= utils.math.sign(self.grav) then self.onGround = true end + if col.normal.z == utils.math.sign(self.grav) then self.onGround = true end end end end From 1ee0b77b509ad57547c4081d241a22050ba08211 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sun, 30 Jun 2019 22:05:02 +0200 Subject: [PATCH 07/16] feat(examples): add sprite support in moveplayer3D --- .../gameplay/moveplayer3D/actors/parent.lua | 1 + .../gameplay/moveplayer3D/actors/player.lua | 27 ++++++++++++++++++- examples/gameplay/moveplayer3D/init.lua | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/examples/gameplay/moveplayer3D/actors/parent.lua b/examples/gameplay/moveplayer3D/actors/parent.lua index 2a43c98..b71c7e0 100644 --- a/examples/gameplay/moveplayer3D/actors/parent.lua +++ b/examples/gameplay/moveplayer3D/actors/parent.lua @@ -7,6 +7,7 @@ function Parent:new(world, type, x, y, z, w, h, d, isSolid) end function Parent:draw() + Parent.super.draw(self) self:drawMainHitbox() end diff --git a/examples/gameplay/moveplayer3D/actors/player.lua b/examples/gameplay/moveplayer3D/actors/player.lua index ea3875a..6825838 100644 --- a/examples/gameplay/moveplayer3D/actors/player.lua +++ b/examples/gameplay/moveplayer3D/actors/player.lua @@ -5,6 +5,9 @@ local Player = Parent:extend() function Player:new(world, x, y, z, id) Player.super.new(self, world, "player", x, y, 0, 16, 16, 24, true) self:setGravity(480) + + self:setSprite("player", 8, 12) + self:cloneSprite() end function Player:updateStart(dt) @@ -23,11 +26,33 @@ function Player:updateStart(dt) self.xsp = 120 end - if self.keys["A"].isDown then + if self.keys["A"].isDown and (self.onGround) then self.zsp = 280 end end +function Player:updateEnd(dt) + self:setAnimation() +end + +function Player:setAnimation() + self:setCustomSpeed(math.abs(self.xsp) / 12) + if (self.isPunching) then + self:changeAnimation("punch", false) + else + if (self.onGround) then + if (math.abs(self.xsp) > 0) or (math.abs(self.ysp) > 0) then + self:changeAnimation("walk", false) + else + self:changeAnimation("idle", true) + end + else + self:changeAnimation("jump", true) + end + end +end + + function Player:draw() Player.super.draw(self) end diff --git a/examples/gameplay/moveplayer3D/init.lua b/examples/gameplay/moveplayer3D/init.lua index 7475f1d..55f9789 100644 --- a/examples/gameplay/moveplayer3D/init.lua +++ b/examples/gameplay/moveplayer3D/init.lua @@ -28,9 +28,9 @@ local World = require "gamecore.modules.world.world3D" function MovePlayer:new() MovePlayer.super.new(self) + self.assets:batchImport("examples.gameplay.plateform.assets") World(self, "examples.gameplay.moveplayer3D.actors", "examples/gameplay/moveplayer3D/assets/arena.lua") - self.world:setPlayerNumber(1) self.world:loadMap() From cf04a16c848b5ff24d7b099424094d300b50bef4 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Mon, 1 Jul 2019 09:57:45 +0200 Subject: [PATCH 08/16] fix(actor3D): improve sprite drawing in fake3D worlds --- gamecore/modules/world/actors/actor3D.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamecore/modules/world/actors/actor3D.lua b/gamecore/modules/world/actors/actor3D.lua index 1cb4d3a..0f255ab 100644 --- a/gamecore/modules/world/actors/actor3D.lua +++ b/gamecore/modules/world/actors/actor3D.lua @@ -201,7 +201,7 @@ end function Actor3D:draw() self:drawStart() - local x, y = math.floor(self.x), math.floor(self.y - self.z) + local x, y = math.floor(self.x), math.floor(self.y - self.z - self.d + (self.h/2)) self:drawSprite(x, y) self:drawEnd() end From ddebdba2e8bf2293c8ffcedb8b6de479099371a9 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Mon, 1 Jul 2019 10:50:21 +0200 Subject: [PATCH 09/16] fix(moveplayer3D): use ground speed instead of xsp for animations --- examples/gameplay/moveplayer3D/actors/player.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/gameplay/moveplayer3D/actors/player.lua b/examples/gameplay/moveplayer3D/actors/player.lua index 6825838..0a33ade 100644 --- a/examples/gameplay/moveplayer3D/actors/player.lua +++ b/examples/gameplay/moveplayer3D/actors/player.lua @@ -36,7 +36,8 @@ function Player:updateEnd(dt) end function Player:setAnimation() - self:setCustomSpeed(math.abs(self.xsp) / 12) + local gsp = utils.math.pointDistance(0, 0, self.xsp, self.ysp) + self:setCustomSpeed(math.abs(gsp) / 12) if (self.isPunching) then self:changeAnimation("punch", false) else From c06f1c49aa2fdd900eafd7aa0eab09832e0d237e Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Mon, 1 Jul 2019 14:13:26 +0200 Subject: [PATCH 10/16] feat(world3D): add a visible shape system to handle better visiblity Actor2D also have a shape, in order to use them in other functions. --- gamecore/modules/world/actors/actor2D.lua | 4 ++ gamecore/modules/world/actors/actor3D.lua | 7 +++ gamecore/modules/world/world3D.lua | 66 +++++++++++++++++++++-- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/gamecore/modules/world/actors/actor2D.lua b/gamecore/modules/world/actors/actor2D.lua index 292c06d..04aa065 100644 --- a/gamecore/modules/world/actors/actor2D.lua +++ b/gamecore/modules/world/actors/actor2D.lua @@ -193,6 +193,10 @@ end -- DRAW FUNCTIONS -- Draw the actors. +function Actor3D:getShape() + return (self.x), (self.y), self.w, (self.h) +end + function Actor2D:draw() self:drawStart() local x, y = math.floor(self.x), math.floor(self.y) diff --git a/gamecore/modules/world/actors/actor3D.lua b/gamecore/modules/world/actors/actor3D.lua index 0f255ab..541dbc9 100644 --- a/gamecore/modules/world/actors/actor3D.lua +++ b/gamecore/modules/world/actors/actor3D.lua @@ -34,11 +34,13 @@ local Hitbox = require(cwd .. "utils.hitbox3D") function Actor3D:new(world, type, x, y, z, w, h, d, isSolid) Actor3D.super.new(self, world, type, x, y, z, w, h, d, isSolid) self:initHitboxes() + self.world:registerShape(self) end function Actor3D:destroy() self.world:removeActor(self) self.mainHitbox:destroy() + self.world:removeShape(self) self.isDestroyed = true end @@ -86,6 +88,7 @@ function Actor3D:move(dx, dy, dz) if (self.isDestroyed == false) then self.x, self.y, self.z, cols, colNumber = self.mainHitbox:checkCollision(dx, dy, dz, self.filter) self.mainHitbox:updatePosition() + self.world:updateShape(self) end return self.x, self.y, self.z, cols, colNumber end @@ -199,6 +202,10 @@ end -- DRAW FUNCTIONS -- Draw the actors. +function Actor3D:getShape() + return (self.x), (self.y - self.z - self.d), self.w, (self.h + self.d) +end + function Actor3D:draw() self:drawStart() local x, y = math.floor(self.x), math.floor(self.y - self.z - self.d + (self.h/2)) diff --git a/gamecore/modules/world/world3D.lua b/gamecore/modules/world/world3D.lua index 4a68d9c..06813db 100644 --- a/gamecore/modules/world/world3D.lua +++ b/gamecore/modules/world/world3D.lua @@ -31,6 +31,8 @@ local Bump = require(cwd .. "libs.bump") local Bump3D = require(cwd .. "libs.bump-3dpd") local CameraSystem = require(cwd .. "camera") +local PADDING_VALUE = 10/100 + function World3D:new(scene, actorlist, mapfile) World3D.super.new(self, scene, actorlist, mapfile) end @@ -42,6 +44,7 @@ function World3D:initActors() self.currentCreationID = 0 self.actors = {} self.bodies = Bump3D.newWorld(50) + self:initShapes() end function World3D:newActor(name, x, y, z) @@ -57,15 +60,41 @@ function World3D:moveActor(actor, x, y, z, filter) end function World3D:getActorsInRect(x, y, w, h) - -- Just a placeholder before adding a better algorythm - World3D.super.getActorsInRect(x, y, w, h) + return self:getShapeInRect(x, y, w, h) end -function World3D:getVisibleActors(id) +function BaseWorld:getVisibleActors(id) + local actors = {} + if (id ~= nil) then + 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.actors + actors = self:getActorsInRect(x, y, w, h) + else + actors = self:getActors() + end + + table.sort(actors, function(a,b) + if (a.y == b.y) then + if (a.depth == b.depth) then + return a.creationID < b.creationID + else + return a.depth > b.depth + end + else + return a.y < b.y + end + end) + + return actors end + -- PLAYER FUNCTIONS -- Load player stuff @@ -141,4 +170,33 @@ function World3D:getBodiesInRect(x, y, w, h) return {} --self.bodies:queryRect(x, y, w, h) end +-- SHAPE SYSTEM +-- Handle onscreen shapes + +function World3D:initShapes() + self.shapes = Bump.newWorld(50) +end + +function World3D:registerShape(actor) + local x, y, w, h = actor:getShape() + return self.shapes:add(actor, x, y, w, h) +end + +function World3D:updateShape(actor) + local x, y, w, h = actor:getShape() + return self.shapes:update(actor, x, y, w, h) +end + +function World3D:removeShape(actor) + return self.shapes:remove(actor) +end + +function World3D:checkShapeIntersection(actor, x, y) + return self.shapes:check(actor, x, y) +end + +function World3D:getShapeInRect(x, y, w, h) + return self.shapes:queryRect(x, y, w, h) +end + return World3D From 940cb1b41f929351c2572159f8aa80bb873f7836 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Mon, 1 Jul 2019 14:15:10 +0200 Subject: [PATCH 11/16] improvement(camera): use the shape system to control the camera. --- gamecore/modules/world/camera.lua | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/gamecore/modules/world/camera.lua b/gamecore/modules/world/camera.lua index 33fe4aa..8284b44 100644 --- a/gamecore/modules/world/camera.lua +++ b/gamecore/modules/world/camera.lua @@ -357,18 +357,19 @@ function CameraSystem:followAllActors(id) if (#self.targets > 0) then local minX, minY, maxX, maxY for i, target in ipairs(self.targets) do - local xx, yy = target:getViewCenter() + local x, y, w, h = target:getShape() + local x2, y2 = x + w, y + h -- 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 + if (minX == nil) then minX = x end + if (maxX == nil) then maxX = x2 end + if (minY == nil) then minY = y end + if (maxY == nil) then maxY = y2 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)) + minX = math.min(minX, x) + maxX = math.max(maxX, x2) + minY = math.min(minY, y) + maxY = math.max(maxY, y2) end -- Add padding From cdddc799731ff3811c6b37918988ab08770c8324 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Mon, 1 Jul 2019 14:18:04 +0200 Subject: [PATCH 12/16] feat(moveplayer3D): add sprite direction --- examples/gameplay/moveplayer3D/actors/player.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/gameplay/moveplayer3D/actors/player.lua b/examples/gameplay/moveplayer3D/actors/player.lua index 0a33ade..85327b8 100644 --- a/examples/gameplay/moveplayer3D/actors/player.lua +++ b/examples/gameplay/moveplayer3D/actors/player.lua @@ -38,6 +38,7 @@ end function Player:setAnimation() local gsp = utils.math.pointDistance(0, 0, self.xsp, self.ysp) self:setCustomSpeed(math.abs(gsp) / 12) + self:setDirection(self.xsp) if (self.isPunching) then self:changeAnimation("punch", false) else @@ -53,6 +54,14 @@ function Player:setAnimation() end end +function Player:setDirection(direction) + direction = direction or 0 + if direction ~= 0 then + direction = utils.math.sign(direction) + self.direction = direction + self:setSpriteScallingX(direction) + end +end function Player:draw() Player.super.draw(self) From 5bdb275b8a9501aa9da02a9929cdced918ce0812 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Mon, 1 Jul 2019 17:00:55 +0200 Subject: [PATCH 13/16] feat(actor3D): add a basic 3D box drawing system for 3D actors --- .../gameplay/moveplayer3D/actors/wall.lua | 6 +- gamecore/modules/world/actors/actor3D.lua | 10 +- .../modules/world/actors/utils/boxes/init.lua | 30 ++++++ .../world/actors/utils/boxes/parent.lua | 93 +++++++++++++++++++ 4 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 gamecore/modules/world/actors/utils/boxes/init.lua create mode 100644 gamecore/modules/world/actors/utils/boxes/parent.lua diff --git a/examples/gameplay/moveplayer3D/actors/wall.lua b/examples/gameplay/moveplayer3D/actors/wall.lua index 1706f85..6de23b0 100644 --- a/examples/gameplay/moveplayer3D/actors/wall.lua +++ b/examples/gameplay/moveplayer3D/actors/wall.lua @@ -4,11 +4,7 @@ local Wall = Base:extend() function Wall:new(world, x, y, z, w, h, d) Wall.super.new(self, world, "wall", x, y, z, w, h, d, true) self:setDebugColor(0,0,0) -end - -function Wall:draw() - self:drawMainHitbox() - utils.graphics.resetColor( ) + self.boxes.Base(self, w, h, d) end return Wall diff --git a/gamecore/modules/world/actors/actor3D.lua b/gamecore/modules/world/actors/actor3D.lua index 541dbc9..21da23f 100644 --- a/gamecore/modules/world/actors/actor3D.lua +++ b/gamecore/modules/world/actors/actor3D.lua @@ -27,6 +27,7 @@ local BaseActor = require(cwd .. "baseactor") local Actor3D = BaseActor:extend() local Hitbox = require(cwd .. "utils.hitbox3D") +local Boxes = require(cwd .. "utils.boxes") -- INIT FUNCTIONS -- Initialise the actor and its base functions @@ -35,6 +36,7 @@ function Actor3D:new(world, type, x, y, z, w, h, d, isSolid) Actor3D.super.new(self, world, type, x, y, z, w, h, d, isSolid) self:initHitboxes() self.world:registerShape(self) + self.boxes = Boxes end function Actor3D:destroy() @@ -208,8 +210,12 @@ end function Actor3D:draw() self:drawStart() - local x, y = math.floor(self.x), math.floor(self.y - self.z - self.d + (self.h/2)) - self:drawSprite(x, y) + if (self.box ~= nil) then + self.box:draw(self.x, self.y, self.z) + else + local x, y = math.floor(self.x), math.floor(self.y - self.z - self.d + (self.h/2)) + self:drawSprite(x, y) + end self:drawEnd() end diff --git a/gamecore/modules/world/actors/utils/boxes/init.lua b/gamecore/modules/world/actors/utils/boxes/init.lua new file mode 100644 index 0000000..624e60f --- /dev/null +++ b/gamecore/modules/world/actors/utils/boxes/init.lua @@ -0,0 +1,30 @@ +-- box3D :: drawable box with shadow handling for fake3D actors + +--[[ + 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('%.init$', '') .. "." + +local Boxes = {} + +Boxes.Base = require(cwd .. "parent") + +return Boxes diff --git a/gamecore/modules/world/actors/utils/boxes/parent.lua b/gamecore/modules/world/actors/utils/boxes/parent.lua new file mode 100644 index 0000000..0da34e3 --- /dev/null +++ b/gamecore/modules/world/actors/utils/boxes/parent.lua @@ -0,0 +1,93 @@ +-- box3D :: drawable box with shadow handling for fake3D actors + +--[[ + 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 Box3D = Object:extend() + +function Box3D:new(owner, w, h, d) + self.owner = owner + + self.w = w + self.h = h + self.d = d + + self.haveLine = true + + self.texture = {} + self:setTopTexture() + self:setBottomTexture() + + self:register() +end + +function Box3D:register() + self.owner.box = self +end + +function Box3D:setSizeFromOwner() + self:setSize(self.owner.w, self.owner.h, self.owner.d) +end + +function Box3D:setSize() + self.w = w + self.h = h + self.d = d + + self:regenerate() +end + +function Box3D:setTopTexture() + local canvas = love.graphics.newCanvas(self.w, self.h) + love.graphics.setCanvas( canvas ) + utils.graphics.resetColor() + love.graphics.rectangle("fill", 0, 0, self.w, self.h) + love.graphics.setCanvas( ) + local imagedata = canvas:newImageData() + self.texture.top = love.graphics.newImage( imagedata ) + imagedata:release() + canvas:release() +end + +function Box3D:setBottomTexture() + local canvas = love.graphics.newCanvas(self.w, self.d) + love.graphics.setCanvas( canvas ) + love.graphics.setColor(0.9, 0.9, 0.9, 1) + love.graphics.rectangle("fill", 0, 0, self.w, self.d) + utils.graphics.resetColor() + love.graphics.setCanvas( ) + local imagedata = canvas:newImageData() + self.texture.bottom = love.graphics.newImage( imagedata ) + imagedata:release() + canvas:release() +end + +function Box3D:draw(x, y, z) + love.graphics.setColor(0, 0, 0, 1) + if (self.haveLine) then + love.graphics.rectangle("line", x, (y-z) - (self.d), self.w, self.d + self.h) + end + utils.graphics.resetColor() + love.graphics.draw(self.texture.top, x, (y-z) - (self.d)) + love.graphics.draw(self.texture.bottom, x, (y-z) - (self.d) + (self.h)) +end + +return Box3D From c043bb8ecfae0aed494d1c76e973b006d361824a Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Mon, 1 Jul 2019 18:06:25 +0200 Subject: [PATCH 14/16] feat(actor3D): add zSorting support --- gamecore/modules/world/world3D.lua | 99 ++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 11 deletions(-) diff --git a/gamecore/modules/world/world3D.lua b/gamecore/modules/world/world3D.lua index 06813db..e910d13 100644 --- a/gamecore/modules/world/world3D.lua +++ b/gamecore/modules/world/world3D.lua @@ -29,6 +29,7 @@ local World3D = BaseWorld:extend() local Sti = require(cwd .. "libs.sti") local Bump = require(cwd .. "libs.bump") local Bump3D = require(cwd .. "libs.bump-3dpd") +local Tsort = require(cwd .. "libs.tsort") local CameraSystem = require(cwd .. "camera") local PADDING_VALUE = 10/100 @@ -79,17 +80,7 @@ function BaseWorld:getVisibleActors(id) actors = self:getActors() end - table.sort(actors, function(a,b) - if (a.y == b.y) then - if (a.depth == b.depth) then - return a.creationID < b.creationID - else - return a.depth > b.depth - end - else - return a.y < b.y - end - end) + actors = self:zSortItems(actors) return actors end @@ -199,4 +190,90 @@ function World3D:getShapeInRect(x, y, w, h) return self.shapes:queryRect(x, y, w, h) end +-- DRAW FUNCTIONS +-- Functions to draw the world + +function World3D:zSortItems(items) + -- zSorting algorithm taken from bump3D example, adapted to gamecore. + local graph = Tsort.new() + local noOverlap = {} + + -- Iterate through all visible items, and calculate ordering of all pairs + -- of overlapping items. + -- TODO: Each pair is calculated twice currently. Maybe this is slow? + for _, itemA in ipairs(items) do repeat + local x, y, w, h = self.shapes:getRect(itemA) + local otherItemsFilter = function(other) return other ~= itemA end + local overlapping, len = self.shapes:queryRect(x, y, w, h, otherItemsFilter) + + if len == 0 then + table.insert(noOverlap, itemA) + + break + end + + local _, aY, aZ, _, aH, aD = self.bodies:getCube(itemA.mainHitbox) + aDepth = itemA.depth + aID = itemA.id + aType = itemA.type + aZ = math.ceil(aZ) + aY = math.ceil(aY) + + for _, itemB in ipairs(overlapping) do + local _, bY, bZ, _, bH, bD = self.bodies:getCube(itemB.mainHitbox) + bDepth = itemB.depth + bID = itemB.id + bType = itemB.type + bZ = math.ceil(bZ) + bY = math.ceil(bY) + + if aZ >= bZ + bD then + -- item A is completely above item B + graph:add(itemB, itemA) + elseif bZ >= aZ + aD then + -- item B is completely above item A + graph:add(itemA, itemB) + elseif aY + aH <= bY then + -- item A is completely behind item B + graph:add(itemA, itemB) + elseif bY + bH <= aY then + -- item B is completely behind item A + graph:add(itemB, itemA) + elseif (aY - aZ) + aH > (bY - bZ) + bH then + -- item A's forward-most point is in front of item B's forward-most point + graph:add(itemB, itemA) + elseif (aY - aZ) + aH < (bY - bZ) + bH then + -- item B's forward-most point is in front of item A's forward-most point + graph:add(itemA, itemB) + else + -- item A's forward-most point is the same than item B's forward-most point + if aDepth > bDepth then + graph:add(itemB, itemA) + elseif aDepth < bDepth then + graph:add(itemA, itemB) + else + if aID > bID then + graph:add(itemA, itemB) + elseif aID < bID then + graph:add(itemB, itemA) + else + err("two object can't have the same ID") + end + end + end + end + until true end + + local sorted, err = graph:sort() + if err then + error(err) + end + for _, item in ipairs(noOverlap) do + table.insert(sorted, item) + end + + return sorted + +end + return World3D From a3b0f471271e633724bb0e9fbddb87cc6de7e27f Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sat, 6 Jul 2019 18:00:00 +0200 Subject: [PATCH 15/16] feat(actor3D): cast shadow below the actor. --- CHANGELOG.md | 2 +- gamecore/modules/world/actors/actor3D.lua | 75 +++++++++++++++++++ .../world/actors/utils/boxes/parent.lua | 67 ++++++++++++++++- gamecore/modules/world/world3D.lua | 35 +++++++++ 4 files changed, 177 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 181810d..5d370f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **camera:** Add two new camera types: "middle" and "zoom". -- **world:** Add a fake 3D world, à la Zelda or BeatThemAll +- **world:** Add a fake 3D world, à la Zelda or BeatThemAll, complete with shadow support ### Changed diff --git a/gamecore/modules/world/actors/actor3D.lua b/gamecore/modules/world/actors/actor3D.lua index 21da23f..a87142c 100644 --- a/gamecore/modules/world/actors/actor3D.lua +++ b/gamecore/modules/world/actors/actor3D.lua @@ -37,9 +37,14 @@ function Actor3D:new(world, type, x, y, z, w, h, d, isSolid) self:initHitboxes() self.world:registerShape(self) self.boxes = Boxes + self.doCastShadows = true end function Actor3D:destroy() + self:removeOldShadowTargets() + if self.box ~= nil then + self.world:removeTerrain(self) + end self.world:removeActor(self) self.mainHitbox:destroy() self.world:removeShape(self) @@ -87,11 +92,19 @@ end function Actor3D:move(dx, dy, dz) local cols, colNumber = {}, 0 + local oldx, oldy, oldz = self.x, self.y, self.z if (self.isDestroyed == false) then self.x, self.y, self.z, cols, colNumber = self.mainHitbox:checkCollision(dx, dy, dz, self.filter) self.mainHitbox:updatePosition() self.world:updateShape(self) end + + if (oldx ~= self.x) or (oldy ~= self.y) or (oldz ~= self.z) or (self.shadowTargetsPrevious == nil) then + if (self.doCastShadows) then + self:castShadow() + end + end + return self.x, self.y, self.z, cols, colNumber end @@ -201,9 +214,71 @@ function Actor3D:checkHitboxCollisionsAtPoint(name, dx, dy, dz, filter) return x, y, z, cols, colNumber end +-- SHADOW FUNCTIONS +-- Handle everything related to shadow + +function Actor3D:castShadow() + local shadowTargets = self.world:getTerrainInRect(self.x, self.y, self.w, self.d) + -- initialize the shadowTargetsPrevious variable if it doesn't exist + if (self.shadowTargetsPrevious == nil) then + self.shadowTargetsPrevious = {} + end + + for i, target in ipairs(shadowTargets) do + -- We test if the actor is below the current actor + if (target ~= self) and (target.box ~= nil) then + + if (target.z + target.d <= self.z + self.d) then + -- Remove the target of the list of item targeted last update, + -- in order to only have object no longer shadowed after the + -- end of the loop + for j, oldtarget in ipairs(self.shadowTargetsPrevious) do + if (target == oldtarget) then + table.remove(self.shadowTargetsPrevious, j) + end + end + + -- We update the shadow source + local x, y = math.floor(self.x - target.x), math.floor(self.y - target.y) + target.box:setShadowSource(self, x, y) + end + + end + + end + + -- At this point, if a target is still in the shadowTargetsPrevious list, + -- it mean that it's not shadowed. So we can simply remove the shadow. + self:removeOldShadowTargets() + + self.shadowTargetsPrevious = shadowTargets +end + +function Actor3D:removeOldShadowTargets() + if (self.shadowTargetsPrevious ~= nil) then + for i, target in ipairs(self.shadowTargetsPrevious) do + if (target.box ~= nil) then + target.box:removeShadowSource(self) + end + end + end +end + +function Actor3D:redrawShadowCanvas() + if (self.box ~= nil) then + self.box:redrawShadowCanvas() + end +end + -- DRAW FUNCTIONS -- Draw the actors. +function Actor3D:drawShadow(x, y) + love.graphics.setColor(0, 0, 0, 1) + love.graphics.rectangle("fill", x, y, self.w, self.h) + utils.graphics.resetColor() +end + function Actor3D:getShape() return (self.x), (self.y - self.z - self.d), self.w, (self.h + self.d) end diff --git a/gamecore/modules/world/actors/utils/boxes/parent.lua b/gamecore/modules/world/actors/utils/boxes/parent.lua index 0da34e3..5459e48 100644 --- a/gamecore/modules/world/actors/utils/boxes/parent.lua +++ b/gamecore/modules/world/actors/utils/boxes/parent.lua @@ -24,7 +24,9 @@ local Box3D = Object:extend() function Box3D:new(owner, w, h, d) - self.owner = owner + self.owner = owner + self.world = owner.world + self.cameras = self.world.cameras self.w = w self.h = h @@ -32,15 +34,20 @@ function Box3D:new(owner, w, h, d) self.haveLine = true + self.shadowSources = {} + self.needRedraw = false + self.texture = {} self:setTopTexture() self:setBottomTexture() + self.texture.shadows = nil self:register() end function Box3D:register() self.owner.box = self + self.world:registerTerrain(self.owner) end function Box3D:setSizeFromOwner() @@ -80,6 +87,60 @@ function Box3D:setBottomTexture() canvas:release() end +function Box3D:setShadowSource(actor, x, y) + local foundShadow = false + + for i,v in ipairs(self.shadowSources) do + if (v.actor == actor) then + if (v.x ~= x) or (v.y ~= y) then + v.x = x + v.y = y + self.needRedraw = true + end + foundShadow = true + end + end + + if (foundShadow == false) then + local shadow = {} + shadow.actor = actor + shadow.x = x + shadow.y = y + self.needRedraw = true + + table.insert(self.shadowSources, shadow) + end +end + +function Box3D:removeShadowSource(actor) + for i,v in ipairs(self.shadowSources) do + if (v.actor == actor) then + table.remove(self.shadowSources, i) + self.needRedraw = true + end + end +end + +function Box3D:redrawShadowCanvas() + if (self.needRedraw) then + print("DEBUG: Generating " .. #self.shadowSources .. " shadows") + local canvas = love.graphics.newCanvas(self.w, self.h) + love.graphics.setCanvas( canvas ) + for i,v in ipairs(self.shadowSources) do + v.actor:drawShadow(v.x, v.y) + end + + love.graphics.setCanvas( ) + + local imagedata = canvas:newImageData() + self.texture.shadows = love.graphics.newImage( imagedata ) + imagedata:release() + canvas:release() + + self.needRedraw = false + end +end + function Box3D:draw(x, y, z) love.graphics.setColor(0, 0, 0, 1) if (self.haveLine) then @@ -88,6 +149,10 @@ function Box3D:draw(x, y, z) utils.graphics.resetColor() love.graphics.draw(self.texture.top, x, (y-z) - (self.d)) love.graphics.draw(self.texture.bottom, x, (y-z) - (self.d) + (self.h)) + if (self.texture.shadows ~= nil) and (#self.shadowSources > 0) then + print("DEBUG: Drawing " .. #self.shadowSources .. " shadow textures") + love.graphics.draw(self.texture.shadows, x, (y-z) - (self.d)) + end end return Box3D diff --git a/gamecore/modules/world/world3D.lua b/gamecore/modules/world/world3D.lua index e910d13..0d5ef76 100644 --- a/gamecore/modules/world/world3D.lua +++ b/gamecore/modules/world/world3D.lua @@ -46,6 +46,7 @@ function World3D:initActors() self.actors = {} self.bodies = Bump3D.newWorld(50) self:initShapes() + self:initTerrain() end function World3D:newActor(name, x, y, z) @@ -161,6 +162,17 @@ function World3D:getBodiesInRect(x, y, w, h) return {} --self.bodies:queryRect(x, y, w, h) end +-- UPDATE +-- Update everything in the world + +function World3D:updateActors(dt) + World3D.super.updateActors(self, dt) + local actors = self:getActors() + for i,v in ipairs(actors) do + v:redrawShadowCanvas() + end +end + -- SHAPE SYSTEM -- Handle onscreen shapes @@ -190,6 +202,29 @@ function World3D:getShapeInRect(x, y, w, h) return self.shapes:queryRect(x, y, w, h) end +-- TERRAIN SYSTEM +-- Handle onscreen shapes + +function World3D:initTerrain() + self.terrains = Bump.newWorld(50) +end + +function World3D:registerTerrain(actor) + return self.terrains:add(actor, actor.x, actor.y, actor.w, actor.h) +end + +function World3D:updateTerrain(actor) + return self.terrains:update(actor, actor.x, actor.y, actor.w, actor.h) +end + +function World3D:removeTerrain(actor) + return self.terrains:remove(actor) +end + +function World3D:getTerrainInRect(x, y, w, h) + return self.terrains:queryRect(x, y, w, h) +end + -- DRAW FUNCTIONS -- Functions to draw the world From 0993f1e8bb664f511b23d20520140391717199ac Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Sat, 6 Jul 2019 18:02:53 +0200 Subject: [PATCH 16/16] fix(boxes): remove some test print. --- gamecore/modules/world/actors/utils/boxes/parent.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/gamecore/modules/world/actors/utils/boxes/parent.lua b/gamecore/modules/world/actors/utils/boxes/parent.lua index 5459e48..d8538c6 100644 --- a/gamecore/modules/world/actors/utils/boxes/parent.lua +++ b/gamecore/modules/world/actors/utils/boxes/parent.lua @@ -123,7 +123,6 @@ end function Box3D:redrawShadowCanvas() if (self.needRedraw) then - print("DEBUG: Generating " .. #self.shadowSources .. " shadows") local canvas = love.graphics.newCanvas(self.w, self.h) love.graphics.setCanvas( canvas ) for i,v in ipairs(self.shadowSources) do @@ -150,7 +149,6 @@ function Box3D:draw(x, y, z) love.graphics.draw(self.texture.top, x, (y-z) - (self.d)) love.graphics.draw(self.texture.bottom, x, (y-z) - (self.d) + (self.h)) if (self.texture.shadows ~= nil) and (#self.shadowSources > 0) then - print("DEBUG: Drawing " .. #self.shadowSources .. " shadow textures") love.graphics.draw(self.texture.shadows, x, (y-z) - (self.d)) end end