scene: add back level code from an earlier boost version
This commit is contained in:
parent
24dda63900
commit
81afa3ff11
19 changed files with 2114 additions and 0 deletions
|
@ -0,0 +1,7 @@
|
|||
local ActorIndex = {}
|
||||
local Actor = "scenes.levels.actors"
|
||||
|
||||
ActorIndex[1] = Actor.Ring
|
||||
ActorIndex[2] = Actor.Crystal
|
||||
|
||||
return ActorIndex
|
10
sonic-boost.love/scenes/subgame/sonic-boost/actors/block.lua
Normal file
10
sonic-boost.love/scenes/subgame/sonic-boost/actors/block.lua
Normal file
|
@ -0,0 +1,10 @@
|
|||
local Block = Entity:extend()
|
||||
|
||||
function Block:new(level, x, y, z, w, h, d) -- On enregistre une nouvelle entité, avec par défaut sa hitbox.
|
||||
Block.super.new(self, level, "block", x-16, y-10, 0, 31, 20, d)
|
||||
self.name = "block"
|
||||
|
||||
self:setDebugColor(255, 0, 0)
|
||||
end
|
||||
|
||||
return Block
|
466
sonic-boost.love/scenes/subgame/sonic-boost/actors/character.lua
Normal file
466
sonic-boost.love/scenes/subgame/sonic-boost/actors/character.lua
Normal file
|
@ -0,0 +1,466 @@
|
|||
local Entity = require "scenes.levels.actors.parent"
|
||||
local phys = require "datas.physics"
|
||||
local playerHeight = 32
|
||||
local grindheight = 32
|
||||
|
||||
local Character = Entity:extend()
|
||||
|
||||
-- Un "personnage" est une entité unique, dans le sens où elle possède un controller
|
||||
-- special, qui fait le lien entre elle et les différents éléments du niveau
|
||||
|
||||
-- Le code des personnages normaux et rivaux est exactement le même, les différence
|
||||
-- sont géré par les controlleurs, qui s'occupent de leur envoyer les données
|
||||
-- de touche, et d'effecter les réactions logique en cas de disparition de l'entité
|
||||
-- (terminer le niveau pour un joueur, juste le détruire pour un rival)
|
||||
|
||||
-- Le personnage ne sait pas à l'intérieur de lui même s'il est contrôler par une
|
||||
-- IA ou par un vrai joueur.
|
||||
|
||||
-- Il n'a pas non plus accès aux détails de la mission, qui sont aussi géré par
|
||||
-- son controller special (vu par "self.charcontroller")
|
||||
|
||||
function Character:new(charcontroller, rail, character, id)
|
||||
self.charcontroller = charcontroller
|
||||
local world = self.charcontroller.controller.world
|
||||
|
||||
|
||||
local rail = rail or 2
|
||||
local y = 10 + (rail*20)
|
||||
Character.super.new(self, world, "character", 16-8, y-8, 0, 16, 16, playerHeight)
|
||||
self.name = "player"
|
||||
self.charid = id or 1
|
||||
|
||||
self.yspeed = 0
|
||||
self.xspeed = 0
|
||||
self.zspeed = 0
|
||||
|
||||
self.ymove = false
|
||||
self.onGround = true
|
||||
self.groundBellow = true
|
||||
self.groundTerrain = 0
|
||||
self.isJumping = false
|
||||
self.isInAerialAction = false
|
||||
self.canAerialAction = true
|
||||
self.isInAction = false
|
||||
self.canAction = true
|
||||
|
||||
self.dash = false
|
||||
|
||||
self:setDebugColor(0, 255, 0)
|
||||
|
||||
self:characterInit(character)
|
||||
|
||||
self:setSprite("character" .. self.charid, 32, 48, true)
|
||||
|
||||
self.depth = -1
|
||||
|
||||
self.rings = 0
|
||||
self.score = 0
|
||||
self.combo = 0
|
||||
self.bonus = 0
|
||||
self.turn = 1
|
||||
|
||||
self.life = 3
|
||||
|
||||
self.startx = self.x
|
||||
self.starty = self.y
|
||||
|
||||
self.grind = false
|
||||
|
||||
self.ai = isAIControlled or false
|
||||
end
|
||||
|
||||
function Character:characterInit(char)
|
||||
self.data = game.characters:getCharacterData(char)
|
||||
|
||||
self.lifeicon = self.data.assets.lifeicon
|
||||
end
|
||||
|
||||
function Character:update(dt)
|
||||
self:updateTimers(dt)
|
||||
|
||||
-- On initialise les variables de directions
|
||||
local dx, dy, dz = 0, 0, 0
|
||||
|
||||
-- On commence par récupérer les inputs fait sur le pad virtuel, qui est géré
|
||||
-- dans game.input.keys. On le garde dans une variable qui sera utilisée dans
|
||||
-- tout l'objet joueur
|
||||
|
||||
self.groundTerrain, self.groundBellow = self:getTerrain()
|
||||
|
||||
self.keys = self.charcontroller:getKeys()
|
||||
|
||||
self:sideSteps()
|
||||
self:jumpAction()
|
||||
self:jump()
|
||||
self:normalAction()
|
||||
|
||||
self:applyVerticalVelocity(dt)
|
||||
|
||||
self:autoMove(dt)
|
||||
self:snaptoRails(dt)
|
||||
|
||||
self:move()
|
||||
end
|
||||
|
||||
-- ACTIONS FUNCTIONS --
|
||||
|
||||
function Character:sideSteps()
|
||||
if self.grind == true then
|
||||
if (self.keys["up"].isPressed) then
|
||||
self.yspeed = - 1 * 60 * phys.side
|
||||
self.ymove = true
|
||||
elseif (self.keys["down"].isPressed) then
|
||||
self.yspeed = 60 * phys.side
|
||||
self.ymove = true
|
||||
else
|
||||
self.ymove = false
|
||||
end
|
||||
else
|
||||
if (self.keys["up"].isDown) then
|
||||
self.yspeed = - 1 * 60 * phys.side
|
||||
self.ymove = true
|
||||
elseif (self.keys["down"].isDown) then
|
||||
self.yspeed = 60 * phys.side
|
||||
self.ymove = true
|
||||
else
|
||||
self.ymove = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Character:jump()
|
||||
if (self.keys["A"].isPressed) and (self.onGround) then
|
||||
self.zspeed = 60 * self.data.stats.jmp
|
||||
self.onGround = false
|
||||
self.isJumping = true
|
||||
self.isInAction = false
|
||||
end
|
||||
end
|
||||
|
||||
function Character:jumpAction()
|
||||
if self.data.stats.jumpaction == "doublejump" then
|
||||
if (self.keys["A"].isPressed) and (self.isJumping) and (self.canAerialAction) then
|
||||
self.zspeed = 60 * self.data.stats.jumpaction_power
|
||||
self.isInAerialAction = true
|
||||
self.canAerialAction = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Character:normalAction()
|
||||
if self.data.stats.action == "spinattack" then
|
||||
if (self.keys["B"].isPressed) and (self.onGround) and (self.canAction) and (self.grind == false) then
|
||||
self.xspeed = math.max(self.xspeed, self.data.stats.spd * 60)
|
||||
self.isInAction = true
|
||||
self.canAction = false
|
||||
self:addTimer("action", .5)
|
||||
self:addTimer("action_cooldown", 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Moving functions --
|
||||
|
||||
function Character:move()
|
||||
local cols, coll_number
|
||||
|
||||
self:setFilter()
|
||||
|
||||
self.x, self.y, self.z, cols, coll_number = Character.super.move(self)
|
||||
|
||||
for i=1, coll_number do
|
||||
local col = cols[i]
|
||||
if col.other.type == "collectible" then
|
||||
col.other:pickedUp(self)
|
||||
end
|
||||
self.collisionResponse(cols[i])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function Character:collisionResponse(other)
|
||||
if other == nil then return 0 end
|
||||
if other.type == "collectible" then
|
||||
other:pickedUp()
|
||||
end
|
||||
end
|
||||
|
||||
function Character:setFilter()
|
||||
self.filter = function(item, other)
|
||||
if other.type == "collectible" then return "cross"
|
||||
else return "cross" end
|
||||
end
|
||||
end
|
||||
|
||||
function Character:autoMove(dt)
|
||||
local max = self.data.stats.spd
|
||||
self.lockspeed = false
|
||||
|
||||
|
||||
|
||||
|
||||
acc = phys.acc
|
||||
|
||||
if (self.groundTerrain == 1) and (self.z <= 0) then
|
||||
self.dash = true
|
||||
self:addTimer("dash", 2)
|
||||
acc = phys.acc
|
||||
end
|
||||
|
||||
if (self.groundTerrain == 2) and (self.z <= 0) then
|
||||
max = phys.max * 1/3
|
||||
self.dash = false
|
||||
self.acc = acc*2
|
||||
end
|
||||
|
||||
if (self.groundTerrain == 4) and (self.z <= 0) then
|
||||
self.dash = true
|
||||
self:addTimer("dash", 2)
|
||||
self.zspeed = 60 * (phys.spring * 4/5)
|
||||
self.onGround = false
|
||||
self.isJumping = true
|
||||
self.assets.sfx["jumpboard"]:play()
|
||||
end
|
||||
|
||||
if (self.groundTerrain == 3) and (self.z <= 0) then
|
||||
max = 0
|
||||
self.dash = false
|
||||
self.acc = acc*3
|
||||
self.xspeed = self.xspeed * 3/4
|
||||
--self.lockspeed = true
|
||||
end
|
||||
|
||||
if (self.lockspeed == false) then
|
||||
if self.dash == true then
|
||||
self.xspeed = max * 60 * phys.boost
|
||||
elseif self.grind == true then
|
||||
self.xspeed = max * 60
|
||||
else
|
||||
if self.xspeed < (max*60) then
|
||||
self.xspeed = self.xspeed + acc
|
||||
elseif (self.xspeed - acc*2) > (phys.max*60) then
|
||||
self.xspeed = self.xspeed - acc*2
|
||||
else
|
||||
self.xspeed = (max*60)
|
||||
end
|
||||
end
|
||||
|
||||
self.x = self.x + self.xspeed * dt
|
||||
end
|
||||
|
||||
if self.x >= self.controller.world.width then
|
||||
self:overflowLevel()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Character:applyVerticalVelocity(dt)
|
||||
if (self.groundBellow == false) and (self.onGround == true) then
|
||||
self.onGround = false
|
||||
end
|
||||
|
||||
local grindBellow = self.world:getGrindAtPoint(self.x, self.y, self.turn)
|
||||
|
||||
if (grindBellow == false) and (self.onGround == true) and self.z > 0 then
|
||||
self.onGround = false
|
||||
self.grind = false
|
||||
end
|
||||
|
||||
if (self.onGround == false) then
|
||||
self.zspeed = self.zspeed - phys.grv
|
||||
|
||||
if self.zspeed < 0 then
|
||||
if (self.z + self.zspeed*dt <= 0) and (self.groundBellow == true) then
|
||||
self.z = 0
|
||||
self.onGround = true
|
||||
self.isJumping = false
|
||||
self.grind = false -- pas vraiment nécessaire de retirer le grind ici
|
||||
self.isInAerialAction = false
|
||||
self.canAerialAction = true
|
||||
end
|
||||
|
||||
if (self.z + self.zspeed*dt <= grindheight) and (self.z + self.zspeed*dt > grindheight - 8) and (grindBellow == true) then
|
||||
self.z = grindheight
|
||||
self.onGround = true
|
||||
self.isJumping = false
|
||||
self.grind = true
|
||||
self.isInAerialAction = false
|
||||
self.canAerialAction = true
|
||||
end
|
||||
|
||||
|
||||
if (self.groundBellow == false) and (self.z < -64) then
|
||||
self:die()
|
||||
end
|
||||
end
|
||||
self.z = self.z + self.zspeed*dt
|
||||
end
|
||||
|
||||
if self.ground == true then
|
||||
self.zspeed = 0
|
||||
end
|
||||
end
|
||||
|
||||
function Character:snaptoRails(dt)
|
||||
local centery = self.y + 8
|
||||
local yrail = math.floor((centery - 10) / 20)
|
||||
local newyrail = math.floor((centery + self.yspeed*dt - 10) / 20)
|
||||
|
||||
if (newyrail < 0) and (self.yspeed < 0) then
|
||||
centery = 10
|
||||
self.yspeed = 0
|
||||
elseif (newyrail >= 4) and (self.yspeed > 0) then
|
||||
centery = 90
|
||||
self.yspeed = 0
|
||||
else
|
||||
if (self.ymove == false) and (yrail ~= newyrail) then
|
||||
if self.yspeed > 0 then
|
||||
centery = newyrail * 20 + 10
|
||||
end
|
||||
if self.yspeed < 0 then
|
||||
centery = yrail * 20 + 10
|
||||
end
|
||||
self.yspeed = 0
|
||||
else
|
||||
centery = centery + self.yspeed*dt
|
||||
end
|
||||
end
|
||||
|
||||
self.y = centery - 8
|
||||
end
|
||||
|
||||
---------- INTERACTION FUNCTIONS ---------
|
||||
|
||||
function Character:getTerrain()
|
||||
local terrain, groundbellow
|
||||
terrain = self.world:getTerrainAtPoint(self.x, self.y, self.turn)
|
||||
|
||||
if (terrain == 3) then
|
||||
groundbellow = false
|
||||
else
|
||||
groundbellow = true
|
||||
end
|
||||
|
||||
return terrain, groundbellow
|
||||
end
|
||||
|
||||
function Character:addScore(score)
|
||||
self.combo = self.combo + 1
|
||||
|
||||
self.bonus = math.floor(self.combo / 5) * 2
|
||||
|
||||
self.score = self.score + score + math.floor(1/10 * score * self.bonus)
|
||||
|
||||
self:addTimer("combo", 3)
|
||||
end
|
||||
|
||||
---------- DRAWING FUNCTIONS ---------
|
||||
|
||||
function Character:animations()
|
||||
self.assets.sprites["character" .. self.charid]:setCustomSpeed(math.abs(self.xspeed / 16))
|
||||
|
||||
if self.onGround then
|
||||
if self.grind == true then
|
||||
self:setAnimation("grind")
|
||||
elseif self.isInAction == true then
|
||||
self:setAnimation("action")
|
||||
else
|
||||
if self.xspeed == 0 then
|
||||
self:setAnimation("idle")
|
||||
elseif self.xspeed < phys.max*60 then
|
||||
self:setAnimation("run2")
|
||||
elseif self.xspeed >= phys.max*60 then
|
||||
self:setAnimation("dash")
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.isJumping then
|
||||
self:setAnimation("jump")
|
||||
else
|
||||
self:setAnimation("fall")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Character:setAnimation(animation)
|
||||
if (self.animation ~= animation) then
|
||||
self.animation = animation
|
||||
self.assets.sprites["character" .. self.charid]:changeAnimation(animation, true)
|
||||
end
|
||||
end
|
||||
|
||||
function Character:draw()
|
||||
self:animations()
|
||||
if (self.z < 0) and (self.onGround == false) then
|
||||
z = self.z
|
||||
if self.z < -48 then z = -48 end
|
||||
love.graphics.setScissor(0, 0, 424, self.y + 100)
|
||||
end
|
||||
self:drawSprite()
|
||||
love.graphics.setScissor()
|
||||
end
|
||||
|
||||
function Character:drawEcho()
|
||||
self:animations()
|
||||
if (self.z < 0) and (self.onGround == false) then
|
||||
z = self.z
|
||||
if self.z < -48 then z = -48 end
|
||||
love.graphics.setScissor(0, 0, 424, self.y + 100)
|
||||
end
|
||||
self:drawSprite(self.world.width, 0)
|
||||
love.graphics.setScissor()
|
||||
end
|
||||
|
||||
function Character:drawShadow(tx, ty)
|
||||
if (self.z < 0) and (self.onGround == false) then
|
||||
return 0
|
||||
end
|
||||
Character.super.drawShadow(self, tx, ty)
|
||||
end
|
||||
|
||||
function Character:drawShadowEcho()
|
||||
if (self.z < 0) and (self.onGround == false) then
|
||||
return 0
|
||||
end
|
||||
Character.super.drawShadow(self, self.world.width, 0)
|
||||
end
|
||||
|
||||
---------- LEVEL FINISH FUNCTIONS ----------
|
||||
|
||||
function Character:overflowLevel()
|
||||
self.charcontroller:newLap()
|
||||
end
|
||||
|
||||
function Character:finishLevel()
|
||||
--love.event.quit()
|
||||
end
|
||||
|
||||
function Character:die()
|
||||
if self.life == 0 then
|
||||
self.charcontroller:die()
|
||||
else
|
||||
self.life = self.life - 1
|
||||
self.x = self.startx
|
||||
self.y = self.starty
|
||||
self.z = 0
|
||||
self.rings = 0
|
||||
end
|
||||
end
|
||||
|
||||
----- TIMERS -----
|
||||
|
||||
function Character:endedTimer(name)
|
||||
if name == "dash" then
|
||||
self.dash = false
|
||||
elseif name == "combo" then
|
||||
self.combo = 0
|
||||
self.bonus = 0
|
||||
elseif name == "action" then
|
||||
self.isInAction = false
|
||||
elseif name == "action_cooldown" then
|
||||
self.canAction = true
|
||||
end
|
||||
end
|
||||
|
||||
return Character
|
|
@ -0,0 +1,21 @@
|
|||
local Entity = require("scenes.levels.actors.parent")
|
||||
local Crystal = Entity:extend()
|
||||
|
||||
function Crystal:new(world, x, y, z)
|
||||
local z = z or 8
|
||||
Crystal.super.new(self, world, "collectible", x-8, y-8, z, 16, 16, 16)
|
||||
|
||||
self:setSprite("crystal", 8, 16, true)
|
||||
|
||||
self:setDebugColor(255, 255, 0)
|
||||
|
||||
self.depth = 1
|
||||
end
|
||||
|
||||
function Crystal:pickedUp(player)
|
||||
player:addScore(10)
|
||||
|
||||
self:destroy()
|
||||
end
|
||||
|
||||
return Crystal
|
12
sonic-boost.love/scenes/subgame/sonic-boost/actors/init.lua
Normal file
12
sonic-boost.love/scenes/subgame/sonic-boost/actors/init.lua
Normal file
|
@ -0,0 +1,12 @@
|
|||
local Actor = {}
|
||||
|
||||
Actor.Character = require "scenes.levels.actors.character"
|
||||
Actor.Ring = require "scenes.levels.actors.ring"
|
||||
Actor.Crystal = require "scenes.levels.actors.crystal"
|
||||
Actor.Rail = require "scenes.levels.actors.rail"
|
||||
|
||||
Actor.Index = {}
|
||||
Actor.Index[01] = Actor.Ring
|
||||
Actor.Index[02] = Actor.Crystal
|
||||
|
||||
return Actor
|
223
sonic-boost.love/scenes/subgame/sonic-boost/actors/parent.lua
Normal file
223
sonic-boost.love/scenes/subgame/sonic-boost/actors/parent.lua
Normal file
|
@ -0,0 +1,223 @@
|
|||
local ParentEntity = Object:extend() -- On créer la classe des entitées, c'est la classe de base
|
||||
|
||||
local Timer = require "scenes.levels.actors.utils.timers"
|
||||
|
||||
function ParentEntity:new(world, type, x, y, z, w, h, d) -- On enregistre une nouvelle entité, avec par défaut sa hitbox.
|
||||
self:setHitbox(x, y, z, w, h, d)
|
||||
self:register(world)
|
||||
--self:initPhysics()
|
||||
--self:resetTimers()
|
||||
self:setDebugColor(0,0,0)
|
||||
self.destroyed = false
|
||||
self.invisible = false
|
||||
self.appearence = "none"
|
||||
|
||||
self.type = type
|
||||
|
||||
self:setSprite("", 0, 0, false)
|
||||
|
||||
self:setFilter()
|
||||
|
||||
self.depth = 0
|
||||
self.id = self.world.creationID
|
||||
self.world.creationID = self.world.creationID + 1
|
||||
|
||||
self:resetTimers()
|
||||
end
|
||||
|
||||
function ParentEntity:setHitbox(x, y, z, w, h, d)
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.d = d
|
||||
end
|
||||
|
||||
function ParentEntity:setSprite(name, ox, oy, active)
|
||||
self.sprite = {}
|
||||
|
||||
self.sprite.name = name
|
||||
self.sprite.ox = ox
|
||||
self.sprite.oy = oy
|
||||
self.sprite.active = active or false
|
||||
end
|
||||
|
||||
function ParentEntity:update(dt)
|
||||
self:updateTimers(dt)
|
||||
end
|
||||
|
||||
function ParentEntity:register(world)
|
||||
-- On enregistre la hitbox dans le monde, pour l'instant les deux parties du programmes
|
||||
-- sont séparé (génération et enregistrement, peut-être qu'elles seront fusionnées)
|
||||
self.world = world
|
||||
self.controller = world.controller
|
||||
self.assets = self.controller.assets
|
||||
|
||||
self.world:register(self)
|
||||
end
|
||||
|
||||
function ParentEntity:destroy()
|
||||
if self.destroyed == false then
|
||||
self.world:remove(self)
|
||||
self.destroyed = true
|
||||
end
|
||||
end
|
||||
|
||||
function ParentEntity:move()
|
||||
local x, y, z, cols, coll_number = self.x, self.y, self.z, {}, 0
|
||||
if self.destroyed == false then
|
||||
x, y, z, cols, coll_number = self.world:move(
|
||||
self,
|
||||
self.x,
|
||||
self.y,
|
||||
self.z,
|
||||
self.filter
|
||||
)
|
||||
end
|
||||
|
||||
return x, y, z, cols, coll_number
|
||||
end
|
||||
|
||||
function ParentEntity:drawDebug()
|
||||
if self.invisible == true then
|
||||
return 0
|
||||
end
|
||||
|
||||
self:draw()
|
||||
end
|
||||
|
||||
--------------------------- DEBUG FUNCTIONS ------------------------------------
|
||||
|
||||
function ParentEntity:setDebugColor(r,g,b)
|
||||
self.debugColor = {}
|
||||
|
||||
self.debugColor.r = r
|
||||
self.debugColor.g = g
|
||||
self.debugColor.b = b
|
||||
end
|
||||
|
||||
---------- COLLISION ----------
|
||||
|
||||
function ParentEntity:setFilter()
|
||||
self.filter = function(item, other)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function ParentEntity:set2DFilter()
|
||||
self.filter2D = function(item, other)
|
||||
return "cross"
|
||||
end
|
||||
end
|
||||
|
||||
function ParentEntity:pickedUp()
|
||||
self:destroy()
|
||||
end
|
||||
|
||||
--------------------------- COORDINATE FUNCTIONS ------------------------------------
|
||||
|
||||
function ParentEntity:getCenter()
|
||||
local x, y, z
|
||||
x = math.floor(self.x + self.w / 2)
|
||||
y = math.floor(self.y + self.h / 2)
|
||||
z = math.floor(self.z + self.d / 2)
|
||||
|
||||
return x, y, z
|
||||
end
|
||||
|
||||
function ParentEntity:getOrigin()
|
||||
local x, y, z
|
||||
y = math.floor(self.y + self.h / 2)
|
||||
x = math.floor(self.x + self.w / 2) + math.floor(y / 2)
|
||||
z = math.floor(self.z)
|
||||
|
||||
return x, y, z
|
||||
end
|
||||
|
||||
function ParentEntity:getSpritePosition()
|
||||
local x, y, z = self:getOrigin()
|
||||
y = y - z
|
||||
|
||||
return x, y, z
|
||||
end
|
||||
|
||||
--------------------------- DRAW FUNCTIONS ------------------------------------
|
||||
|
||||
function ParentEntity:draw()
|
||||
self:drawSprite()
|
||||
end
|
||||
|
||||
function ParentEntity:drawEcho()
|
||||
self:drawSprite(self.world.width, 0)
|
||||
end
|
||||
|
||||
function ParentEntity:drawSprite(tx, ty)
|
||||
utils.draw.resetColor()
|
||||
|
||||
local x, y, z = self:getSpritePosition()
|
||||
|
||||
local tx = tx or 0
|
||||
local ty = ty or 0
|
||||
|
||||
if (self.sprite.active) then
|
||||
self.assets.sprites[self.sprite.name]:drawAnimation(x + tx, y + ty, 0, 1, 1, self.sprite.ox, self.sprite.oy)
|
||||
end
|
||||
end
|
||||
|
||||
function ParentEntity:drawShadow(tx, ty)
|
||||
local x, y, z = self:getOrigin()
|
||||
love.graphics.setColor(0, 0, 1, 1)
|
||||
local tx = tx or 0
|
||||
local ty = ty or 0
|
||||
x = math.floor(x + tx)
|
||||
y = math.floor(y + ty)
|
||||
self.assets:drawImage("shadow", x, y, 0, 1, 1, 12, 3)
|
||||
end
|
||||
|
||||
function ParentEntity:drawShadowEcho()
|
||||
self:drawShadow(self.world.width, 0)
|
||||
end
|
||||
|
||||
function ParentEntity:drawHitBox()
|
||||
x, y, z = self:getOrigin()
|
||||
|
||||
local r, g, b, a = self.debugColor.r, self.debugColor.g, self.debugColor.b, self.debugColor.a
|
||||
|
||||
--utils.draw.box(self.x, self.y + self.z + self.h, self.w, self.d, self.h, r, g, b, a)
|
||||
--utils.draw.box(x - (self.w/2), y - (self.w/2) - self.z, self.w, self.h, r, g, b, a)
|
||||
--utils.draw.box(x - (self.w/2), y - (self.w/2) - self.z, self.w, self.d, r, g, b, a)
|
||||
--utils.draw.box(x - (self.w/2), y + (self.w/2) - self.z - self.d, self.w, self.d, r, g, b, a)
|
||||
--utils.draw.box(x - (self.w/2), y - (self.w/2) - self.z - self.d, self.w, self.h, r, g, b, a)
|
||||
--utils.draw.box(x - (self.w/2), y + (self.w/2) - self.z - self.d, self.w, self.d, r, g, b, a)
|
||||
|
||||
utils.draw.box(x - (self.w/2), y - (self.h/2), self.w, self.h, r/5, g/5, b/5, 1)
|
||||
|
||||
utils.draw.box(x - (self.w/2), y - z - self.d, self.w, self.d, r, g, b, 1)
|
||||
|
||||
end
|
||||
|
||||
----------- TIMER RELATED FUNCTIONS ----------
|
||||
|
||||
function ParentEntity:resetTimers()
|
||||
self.timers = {}
|
||||
end
|
||||
|
||||
function ParentEntity:addTimer(name, t)
|
||||
self.timers[name] = Timer(self, name, t)
|
||||
return name
|
||||
end
|
||||
|
||||
function ParentEntity:updateTimers(dt)
|
||||
for i, v in pairs(self.timers) do
|
||||
v:update(dt)
|
||||
end
|
||||
end
|
||||
|
||||
function ParentEntity:endedTimer(name)
|
||||
if name == "destroy" then
|
||||
self:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
return ParentEntity
|
25
sonic-boost.love/scenes/subgame/sonic-boost/actors/rail.lua
Normal file
25
sonic-boost.love/scenes/subgame/sonic-boost/actors/rail.lua
Normal file
|
@ -0,0 +1,25 @@
|
|||
local Entity = require("scenes.levels.actors.parent")
|
||||
local Rail = Entity:extend()
|
||||
|
||||
function Rail:new(world, x, y, z, id)
|
||||
local z = z or 32
|
||||
self.railid = id or 2
|
||||
|
||||
Rail.super.new(self, world, "grind", x, y-4, 24, 31, 8, 8)
|
||||
|
||||
self:setDebugColor(.2, .2, .2)
|
||||
|
||||
self.depth = 1
|
||||
end
|
||||
|
||||
function Rail:draw()
|
||||
utils.draw.resetColor( )
|
||||
love.graphics.draw(self.world.textures.rail, self.world.quads.rails[self.railid], self.x + math.floor(self.y / 2), self.y - self.z -(self.d / 2))
|
||||
end
|
||||
|
||||
function Rail:drawEcho()
|
||||
utils.draw.resetColor( )
|
||||
love.graphics.draw(self.world.textures.rail, self.world.quads.rails[self.railid], self.x + math.floor(self.y / 2) + self.world.width, self.y - self.z -(self.d / 2))
|
||||
end
|
||||
|
||||
return Rail
|
22
sonic-boost.love/scenes/subgame/sonic-boost/actors/ring.lua
Normal file
22
sonic-boost.love/scenes/subgame/sonic-boost/actors/ring.lua
Normal file
|
@ -0,0 +1,22 @@
|
|||
local Entity = require("scenes.levels.actors.parent")
|
||||
local Ring = Entity:extend()
|
||||
|
||||
function Ring:new(world, x, y, z)
|
||||
local z = z or 8
|
||||
Ring.super.new(self, world, "collectible", x-8, y-8, z, 16, 16, 16)
|
||||
|
||||
self:setSprite("ring", 8, 16, true)
|
||||
|
||||
self:setDebugColor(255, 255, 0)
|
||||
|
||||
self.depth = 1
|
||||
end
|
||||
|
||||
function Ring:pickedUp(player)
|
||||
player.rings = player.rings + 1
|
||||
player:addScore(10)
|
||||
|
||||
self:destroy()
|
||||
end
|
||||
|
||||
return Ring
|
|
@ -0,0 +1,21 @@
|
|||
local Timer = Object:extend()
|
||||
|
||||
function Timer:new(entity, name, t)
|
||||
self.time = t
|
||||
self.entity = entity
|
||||
self.name = name
|
||||
end
|
||||
|
||||
function Timer:update(dt)
|
||||
self.time = self.time - dt
|
||||
if (self.time <= 0) then
|
||||
self:finish()
|
||||
end
|
||||
end
|
||||
|
||||
function Timer:finish()
|
||||
self.entity:endedTimer(self.name)
|
||||
self.entity.timers[self.name] = nil
|
||||
end
|
||||
|
||||
return Timer
|
|
@ -0,0 +1,51 @@
|
|||
local Background = Object:extend()
|
||||
|
||||
function Background:new(controller, levelname)
|
||||
self.controller = controller
|
||||
local filename = self.controller.datas.background or "forest"
|
||||
self.back1 = love.graphics.newImage("assets/levels/backgrounds/" .. filename .. "-back.png")
|
||||
self.back2 = love.graphics.newImage("assets/levels/backgrounds/" .. filename .. "-fore.png")
|
||||
end
|
||||
|
||||
function Background:destroy()
|
||||
self.back1:release( )
|
||||
self.back2:release( )
|
||||
end
|
||||
|
||||
function Background:draw()
|
||||
local x0, x1, x2
|
||||
|
||||
local turn = self.controller.camera.turn
|
||||
|
||||
x0 = self.controller.camera.view.x + (turn * self.controller.world.width)
|
||||
x1 = x0 / 3 % 240
|
||||
x2 = x0 / 9 % 480
|
||||
|
||||
local sx = 1
|
||||
for i=1, 4 do
|
||||
if (i == 2) or (i == 4) then
|
||||
love.graphics.draw(self.back1, (i)*240 - x2, 20, 0, -1, 1)
|
||||
else
|
||||
love.graphics.draw(self.back1, (i-1)*240 - x2, 20, 0, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
for i=1, 3 do
|
||||
love.graphics.draw(self.back2, (i-1)*240 - x1, 20, 0, 1, 1)
|
||||
end
|
||||
|
||||
--self:drawBorders()
|
||||
--self:drawGround(0, 90)
|
||||
end
|
||||
|
||||
function Background:drawGround(x, y)
|
||||
for i=1, 5 do
|
||||
for j=1, 16 do
|
||||
local k = 1 + ((i + j) % 2)
|
||||
print(k)
|
||||
love.graphics.draw(self.normalTileImage, self.normalTile[k], x + (j-3)*31 + (i-1)*10 , y + (i-1)*20)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Background
|
|
@ -0,0 +1,122 @@
|
|||
local Camera = require "libs.hump.camera"
|
||||
local CameraSystem = Object:extend()
|
||||
|
||||
function CameraSystem:new(controller, x, y, target)
|
||||
self.controller = controller
|
||||
self.target = target
|
||||
self.view = Camera(212, 30, 1, 0, true)
|
||||
local width, height, flags = love.window.getMode( )
|
||||
self.screen = {}
|
||||
self.screen.width = width
|
||||
self.screen.height = height
|
||||
self.width = 424
|
||||
self.height = 240
|
||||
self.resolution = self.screen.width / self.width
|
||||
--self:limit()
|
||||
|
||||
self.turn = 1
|
||||
end
|
||||
|
||||
function CameraSystem:setTarget(target)
|
||||
self.target = target
|
||||
end
|
||||
|
||||
function CameraSystem:floorCoord()
|
||||
self.view.x, self.view.y = utils.math.floorCoord(self.view.x, self.view.y)
|
||||
end
|
||||
|
||||
function CameraSystem:update()
|
||||
if (self.target ~= nil) then
|
||||
self:followEntity(self.target)
|
||||
end
|
||||
self:limit()
|
||||
self:floorCoord()
|
||||
end
|
||||
|
||||
function CameraSystem:move(x, y)
|
||||
self.view.x = x
|
||||
self.view.y = y
|
||||
|
||||
self:limit()
|
||||
end
|
||||
|
||||
function CameraSystem:getCoord()
|
||||
local camx, camy, camh, camw
|
||||
camx = self.view.x - (self.width/2)
|
||||
camy = self.view.y - (self.height/2)
|
||||
|
||||
camw = self.width
|
||||
camh = self.height
|
||||
return camx, camy, camw, camh
|
||||
end
|
||||
|
||||
function CameraSystem:worldCoord(x, y, ox, oy, w, h)
|
||||
ox, oy = ox or 0, oy or 0
|
||||
w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
|
||||
return self.view:worldCoords(x, y, ox, oy, w, h)
|
||||
end
|
||||
|
||||
function CameraSystem:viewCoord(x, y)
|
||||
return self.view:cameraCoords(x, y, ox, oy, w, h)
|
||||
end
|
||||
|
||||
function CameraSystem:getScreenCoord()
|
||||
local camx, camy, camh, camw
|
||||
camx = self.view.x - (self.screen.width/2)
|
||||
camy = self.view.y - (self.screen.height/2)
|
||||
|
||||
camw = self.screen.width
|
||||
camh = self.screen.height
|
||||
return camx, camy, camw, camh
|
||||
end
|
||||
|
||||
function CameraSystem:limit()
|
||||
local camx, camy = self.view.x, self.view.y
|
||||
|
||||
local currentTurn, maxTurn = self.turn, self.controller.missiondata.turns
|
||||
|
||||
if currentTurn == 1 then
|
||||
camx = math.max(212, camx)
|
||||
end
|
||||
|
||||
if currentTurn == maxTurn then
|
||||
camx = math.min(camx, self.controller.world.width - 212 + 31)
|
||||
end
|
||||
|
||||
self.view.x, self.view.y = camx, 30
|
||||
end
|
||||
|
||||
function CameraSystem:followEntity(entity)
|
||||
local entity = entity
|
||||
|
||||
if (entity ~= nil) then
|
||||
self.turn = entity.turn or 1
|
||||
|
||||
local playx, playy = entity:getCenter()
|
||||
|
||||
local camx, camy = self.view.x + (self.width/2),
|
||||
self.view.y + (self.height/2)
|
||||
|
||||
|
||||
playx, playy = self:viewCoord(playx-16+212, 30)
|
||||
playx = playx - (self.width/2)
|
||||
playy = playy - (self.height/2)
|
||||
|
||||
if (math.abs(playx) > 8) then
|
||||
camx = camx + (playx - (8*utils.math.sign(playx)))
|
||||
end
|
||||
|
||||
if (playy > 16) then
|
||||
camy = camy + (playy - 16)
|
||||
elseif (playy < -64) then
|
||||
camy = camy + (playy + 64)
|
||||
end
|
||||
|
||||
self.view.x, self.view.y = camx - (self.width/2),
|
||||
camy - (self.height/2)
|
||||
end
|
||||
end
|
||||
|
||||
-- Anciennes Fonctions
|
||||
|
||||
return CameraSystem
|
|
@ -0,0 +1,120 @@
|
|||
local CharManager = Object:extend()
|
||||
local Dummy = Object:extend()
|
||||
local Player = Dummy:extend()
|
||||
local Rival = Dummy:extend()
|
||||
local actor = require "scenes.levels.actors"
|
||||
|
||||
|
||||
function CharManager:new(controller)
|
||||
self.controller = controller
|
||||
self.list = {}
|
||||
end
|
||||
|
||||
function CharManager:newPlayer(character, rail)
|
||||
local id = #self.list + 1
|
||||
table.insert(self.list, Player(self, id, character, rail))
|
||||
end
|
||||
|
||||
function CharManager:newDummy(character, rail)
|
||||
local id = #self.list + 1
|
||||
table.insert(self.list, Dummy(self, id, character, rail))
|
||||
end
|
||||
|
||||
function CharManager:update(dt)
|
||||
for i,v in ipairs(self.list) do
|
||||
v:update(dt)
|
||||
end
|
||||
end
|
||||
|
||||
function CharManager:getType(id)
|
||||
self.list[id]:getType()
|
||||
end
|
||||
|
||||
-- DUMMY CHARACTER FUNCTION --
|
||||
|
||||
function Dummy:new(manager, playerid, character, rail)
|
||||
self.manager = manager
|
||||
self.controller = manager.controller
|
||||
self.type = "dummy"
|
||||
|
||||
local character = character or "sonic"
|
||||
|
||||
local rail = rail
|
||||
|
||||
local spritepath = "assets/sprites/characters/" .. character
|
||||
self.controller.assets:addSprite("character" .. playerid, spritepath)
|
||||
|
||||
self.actor = actor.Character(self, rail, character, playerid)
|
||||
end
|
||||
|
||||
|
||||
function Dummy:getKeys()
|
||||
return game.input.fakekeys
|
||||
end
|
||||
|
||||
function Dummy:update(dt)
|
||||
-- le Dummy ne fait rien, donc inutile
|
||||
end
|
||||
|
||||
function Dummy:newLap()
|
||||
local currentTurn, maxTurn = self.actor.turn, self.controller.missiondata.turns
|
||||
|
||||
if (currentTurn < maxTurn) then
|
||||
self:wrapActor()
|
||||
else
|
||||
self:finishLevel()
|
||||
end
|
||||
end
|
||||
|
||||
function Dummy:wrapActor()
|
||||
self.actor.x = math.floor(self.actor.x - self.controller.world.width)
|
||||
self.actor.turn = self.actor.turn + 1
|
||||
end
|
||||
|
||||
function Dummy:getRealPosition()
|
||||
local turn = self.actor.turn - 1 -- on calcule le tour à partir de 0 pour
|
||||
-- obtenir le vrai x. Techniquement, ça ne change rien pour le joueur,
|
||||
-- mais c'est plus correct comme ça
|
||||
|
||||
local turnStart = (turn * self.controller.world.width)
|
||||
|
||||
return turnStart + self.actor.x
|
||||
end
|
||||
|
||||
function Dummy:finishLevel()
|
||||
-- Pour le Dummy ça n'a aucun effet
|
||||
end
|
||||
|
||||
function Dummy:die()
|
||||
self.actor:destroy()
|
||||
end
|
||||
|
||||
-- PLAYER CONTROL FUNCTION --
|
||||
|
||||
function Player:new(manager, playerid, character, rail)
|
||||
Player.super.new(self, manager, playerid, character, rail)
|
||||
|
||||
self.type = "player"
|
||||
self.controller.camera:setTarget(self.actor)
|
||||
self.controller.hud:setTarget(self.actor)
|
||||
end
|
||||
|
||||
function Player:getKeys()
|
||||
return game.input.keys
|
||||
end
|
||||
|
||||
function Player:wrapActor()
|
||||
self.actor.x = math.floor(self.actor.x - self.controller.world.width)
|
||||
self.actor.turn = self.actor.turn + 1
|
||||
self.controller.camera.view.x = self.controller.camera.view.x - self.controller.world.width
|
||||
end
|
||||
|
||||
function Player:finishLevel()
|
||||
--love.event.quit()
|
||||
end
|
||||
|
||||
function Player:die()
|
||||
love.event.quit()
|
||||
end
|
||||
|
||||
return CharManager
|
127
sonic-boost.love/scenes/subgame/sonic-boost/controller/hud.lua
Normal file
127
sonic-boost.love/scenes/subgame/sonic-boost/controller/hud.lua
Normal file
|
@ -0,0 +1,127 @@
|
|||
local BattleHUD = Object:extend()
|
||||
|
||||
function BattleHUD:new(controller)
|
||||
self.controller = controller
|
||||
self.target = nil
|
||||
|
||||
self:loadAssets()
|
||||
end
|
||||
|
||||
function BattleHUD:setTarget(target)
|
||||
self.target = target
|
||||
end
|
||||
|
||||
function BattleHUD:loadAssets()
|
||||
self.progressbarImage = love.graphics.newImage("assets/gui/progressbar.png")
|
||||
self.barBack = love.graphics.newQuad(0, 0, 211, 12, 211, 24)
|
||||
self.barFore = love.graphics.newQuad(0, 12, 211, 12, 211, 24)
|
||||
self.hud1 = love.graphics.newImage("assets/gui/boosthud1.png")
|
||||
self.hud2 = love.graphics.newImage("assets/gui/boosthud2.png")
|
||||
|
||||
self.ring = love.graphics.newImage("assets/gui/ring.png")
|
||||
|
||||
|
||||
|
||||
self.font = love.graphics.newImageFont("assets/gui/hudnumbers.png", " 0123456789:/", 1)
|
||||
self.font2 = love.graphics.newImageFont("assets/gui/hudsmallnumbers.png", " 0123456789", 0)
|
||||
|
||||
self.time = love.graphics.newImage("assets/gui/hudtime.png")
|
||||
self.score = love.graphics.newImage("assets/gui/hudscore.png")
|
||||
self.bonus = love.graphics.newImage("assets/gui/hudbonus.png")
|
||||
|
||||
self.controller.assets:addTileset("lifeicon", "assets/sprites/characters/charicons")
|
||||
end
|
||||
|
||||
function BattleHUD:destroy( )
|
||||
self.progressbarImage:release( )
|
||||
self.barBack:release( )
|
||||
self.barFore:release( )
|
||||
self.hud1:release( )
|
||||
self.hud2:release( )
|
||||
end
|
||||
|
||||
function BattleHUD:update(dt)
|
||||
--
|
||||
end
|
||||
|
||||
function BattleHUD:draw()
|
||||
love.graphics.setFont( self.font )
|
||||
self:drawFrame()
|
||||
|
||||
if self.target ~= nil then
|
||||
self:drawTop(0, 0)
|
||||
self:drawBottom(0, 200)
|
||||
end
|
||||
|
||||
self.controller:resetFont( )
|
||||
end
|
||||
|
||||
function BattleHUD:drawFrame()
|
||||
love.graphics.draw(self.hud1, 0, 0)
|
||||
love.graphics.draw(self.hud2, 0, 200)
|
||||
end
|
||||
|
||||
function BattleHUD:drawTop(x, y)
|
||||
|
||||
local ringx, ringy = x + 289, y + 6
|
||||
love.graphics.draw(self.ring, ringx, ringy)
|
||||
local rings = utils.math.numberToString(self.target.rings, 3)
|
||||
|
||||
love.graphics.print(rings, ringx + 14, ringy + 1)
|
||||
|
||||
|
||||
love.graphics.draw(self.score, x+8, y+3)
|
||||
local score = utils.math.numberToString(self.target.score, 9)
|
||||
local bonus = utils.math.numberToString(self.target.bonus, 3)
|
||||
local combo = utils.math.numberToString(self.target.combo, 3)
|
||||
|
||||
love.graphics.print(score, x + 8 + 42, y + 4)
|
||||
|
||||
local bonusx, bonusy = x + 165, y + 1
|
||||
love.graphics.draw(self.bonus, bonusx, bonusy)
|
||||
love.graphics.setFont( self.font2 )
|
||||
love.graphics.print(combo, bonusx + 28, bonusy)
|
||||
love.graphics.print(bonus, bonusx + 28, bonusy + 8)
|
||||
love.graphics.setFont( self.font )
|
||||
|
||||
self.controller.assets.tileset["lifeicon"]:drawTile(self.target.lifeicon, x + 360, y + 4)
|
||||
local lives = utils.math.numberToString(self.target.life, 2)
|
||||
love.graphics.print(lives, x + 360 + 18, y + 7 )
|
||||
end
|
||||
|
||||
function BattleHUD:drawBottom(x, y)
|
||||
local progressx, progressy = x + 5, y + 4
|
||||
love.graphics.draw(self.progressbarImage, self.barBack, progressx, progressy)
|
||||
local width = math.floor((self.target.x / self.controller.world.width) * (211 - 16))
|
||||
width = math.max(0, width)
|
||||
width = math.min(width, (211 - 16))
|
||||
love.graphics.setScissor(progressx + 8, progressy, width, 12)
|
||||
love.graphics.draw(self.progressbarImage, self.barFore, progressx, progressy)
|
||||
love.graphics.setScissor( )
|
||||
self.controller.assets.tileset["lifeicon"]:drawTile(self.target.lifeicon, progressx + width, progressy - 2)
|
||||
if (self.controller.missiondata.turns > 1) then
|
||||
local turn1 = utils.math.numberToString(self.target.turn, 2)
|
||||
local turn2 = utils.math.numberToString(self.controller.missiondata.turns, 2)
|
||||
love.graphics.printf(turn1 .. "/" .. turn2, progressx, progressy + 12 + 2, 210, "right")
|
||||
end
|
||||
|
||||
local timex, timey = x + 228, y + 1
|
||||
love.graphics.draw(self.time, timex, timey)
|
||||
local timestring = self:getTimeString(self.controller.mission.timer)
|
||||
|
||||
love.graphics.print(timestring, timex + 32, timey + 1)
|
||||
|
||||
|
||||
end
|
||||
|
||||
function BattleHUD:getTimeString(numberOfSeconds)
|
||||
local numberOfSeconds = numberOfSeconds or 0
|
||||
local microseconds = math.floor((numberOfSeconds % 1) * 100)
|
||||
local seconds = math.floor(numberOfSeconds % 60)
|
||||
local minutes = math.floor(numberOfSeconds / 60)
|
||||
return utils.math.numberToString(minutes, 2) .. ":"
|
||||
.. utils.math.numberToString(seconds, 2) .. ":"
|
||||
.. utils.math.numberToString(microseconds, 2)
|
||||
end
|
||||
|
||||
return BattleHUD
|
161
sonic-boost.love/scenes/subgame/sonic-boost/controller/init.lua
Normal file
161
sonic-boost.love/scenes/subgame/sonic-boost/controller/init.lua
Normal file
|
@ -0,0 +1,161 @@
|
|||
local Controller = Object:extend()
|
||||
local GUI = require "modules.gui"
|
||||
local Assets = require "modules.assets"
|
||||
|
||||
local HUD = require "scenes.levels.controller.hud"
|
||||
local Background = require "scenes.levels.controller.background"
|
||||
local Camera = require "scenes.levels.controller.camera"
|
||||
local World = require "scenes.levels.controller.world"
|
||||
local PauseMenu = require "scenes.levels.controller.pause"
|
||||
|
||||
local CharacterManager = require "scenes.levels.controller.characters"
|
||||
|
||||
local zoneDatas = require "datas.levels.zones"
|
||||
|
||||
local LoadAssets = require "scenes.levels.controller.loader"
|
||||
|
||||
function Controller:new(levelid, character)
|
||||
self:initMission()
|
||||
|
||||
self.assets = Assets()
|
||||
self.gui = GUI()
|
||||
LoadAssets(self)
|
||||
|
||||
self:initManagers()
|
||||
|
||||
self:resetFont()
|
||||
|
||||
self.levelid = levelid
|
||||
self.character = character
|
||||
|
||||
if self.datas.music ~= nil then
|
||||
local filepath = "assets/music/" .. self.datas.music .. ".mp3"
|
||||
print(filepath)
|
||||
self.assets:setMusic(filepath)
|
||||
self.assets:playMusic()
|
||||
end
|
||||
|
||||
self.pause = false
|
||||
self.initiated = false
|
||||
|
||||
self.world:loadWorld()
|
||||
|
||||
self.characters:newPlayer("sonic", 2)
|
||||
--self.characters:newDummy("sonic", 0)
|
||||
--self.characters:newDummy("sonic", 1)
|
||||
--self.characters:newDummy("sonic", 3)
|
||||
--self.characters:newDummy("sonic", 4)
|
||||
end
|
||||
|
||||
function Controller:restartLevel()
|
||||
self:new(self.levelid, self.character)
|
||||
end
|
||||
|
||||
function Controller:exitLevel()
|
||||
Gamestate.switch(Scenes.options)
|
||||
end
|
||||
|
||||
function Controller:initManagers()
|
||||
--self.loader = Loader()
|
||||
self.world = World(self)
|
||||
self.hud = HUD(self)
|
||||
self.camera = Camera(self, 0, 0)
|
||||
self.background = Background(self)
|
||||
self.characters = CharacterManager(self)
|
||||
self.pausemenu = PauseMenu(self)
|
||||
end
|
||||
|
||||
function Controller:destroy()
|
||||
self.world:destroy()
|
||||
|
||||
|
||||
self.world = nil
|
||||
self.hud = nil
|
||||
self.camera = nil
|
||||
self.background = nil
|
||||
self.characters = nil
|
||||
self.pausemenu = nil
|
||||
|
||||
self.assets:clear()
|
||||
end
|
||||
|
||||
function Controller:initMission(levelid)
|
||||
self:getLevelData(levelid)
|
||||
|
||||
self.mission = {}
|
||||
self.mission.timer = 0
|
||||
self.mission.completed = false
|
||||
end
|
||||
|
||||
function Controller:startMission()
|
||||
self.initiated = true
|
||||
end
|
||||
|
||||
function Controller:getLevelData(file)
|
||||
local file = file or "testlevel.test1"
|
||||
local level = require("datas.levels." .. file)
|
||||
|
||||
self.zone = level.datas.zone
|
||||
|
||||
local zone_data = zoneDatas[self.zone]
|
||||
local bypass_data = level.datas.bypass_data
|
||||
|
||||
self.datas = {}
|
||||
|
||||
if (level.datas.bypass_zone) then
|
||||
self.datas.name = bypass_data.name or zone_data.name
|
||||
self.datas.borders = bypass_data.borders or zone_data.borders
|
||||
self.datas.tiles = bypass_data.tiles or zone_data.tiles
|
||||
self.datas.background = bypass_data.background or zone_data.background
|
||||
self.datas.music = bypass_data.music or zone_data.music
|
||||
else
|
||||
self.datas = zone_data
|
||||
end
|
||||
|
||||
self.layout = level.layout
|
||||
self.parts = level.parts
|
||||
self.endless_parts = level.endless_parts
|
||||
|
||||
self.missiondata = level.datas.missiondata
|
||||
|
||||
end
|
||||
|
||||
function Controller:update(dt)
|
||||
|
||||
if self.pause == false then
|
||||
self.assets:update(dt)
|
||||
self.mission.timer = self.mission.timer + dt
|
||||
self.world:update(dt)
|
||||
self.camera:update(dt)
|
||||
else
|
||||
self.pausemenu:update(dt)
|
||||
end
|
||||
|
||||
if game.input.keys["start"].isPressed then
|
||||
self.pause = (self.pause == false)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function Controller:draw()
|
||||
|
||||
self.background:draw()
|
||||
|
||||
self.camera.view:attach()
|
||||
self.world:draw()
|
||||
self.camera.view:detach()
|
||||
|
||||
utils.draw.resetColor()
|
||||
self.hud:draw()
|
||||
|
||||
if self.pause == true then
|
||||
self.pausemenu:draw(dt)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function Controller:resetFont()
|
||||
self.assets.fonts["text"]:set()
|
||||
end
|
||||
|
||||
return Controller
|
|
@ -0,0 +1,82 @@
|
|||
local Loader = Object:extend()
|
||||
|
||||
function Loader:new(controller)
|
||||
self.controller = controller
|
||||
self.assetQueue = {}
|
||||
self.pointer = 1
|
||||
self.finished = false
|
||||
end
|
||||
|
||||
function Loader:addElement(type, name, filepath, arg1, arg2, arg3, arg4)
|
||||
local queueElement = {}
|
||||
|
||||
queueElement.type = type
|
||||
queueElement.name = name
|
||||
queueElement.file = filepath
|
||||
table.insert(self.assetQueue, queueElement)
|
||||
|
||||
self.finished = false
|
||||
end
|
||||
|
||||
function Loader:update(dt)
|
||||
|
||||
end
|
||||
|
||||
function Loader:treatAssetQueueElement(id)
|
||||
if self.assetQueue[id] ~= nil then
|
||||
local asset = self.assetQueue[id]
|
||||
if asset.type == "image" then
|
||||
self.controller.assets:addImage(asset.name, asset.file)
|
||||
elseif asset.type == "sprite" then
|
||||
self.controller.assets:addSprite(asset.name, asset.file)
|
||||
elseif asset.type == "sfx" then
|
||||
self.controller.assets:addSFX(asset.name, asset.file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Loader:treatAssetQueue()
|
||||
for i = self.pointer, 10 do
|
||||
if i <= #self.assetQueue then
|
||||
self.finished = true
|
||||
end
|
||||
end
|
||||
self.pointer = i
|
||||
end
|
||||
|
||||
local function LoadAssets(controller)
|
||||
controller.assets:addImage("shadow", "assets/sprites/shadow.png")
|
||||
controller.assets:addSprite("ring", "assets/sprites/items/ring")
|
||||
controller.assets:addSprite("crystal", "assets/sprites/items/crystal")
|
||||
|
||||
controller.assets:addFont("text", "assets/fonts/PixelOperator.ttf", 16.5)
|
||||
controller.gui:addTextBox("solid", "assets/gui/dialogbox.png")
|
||||
|
||||
controller.assets:addSFX("ring", "assets/sfx/gameplay/objects/ring.wav")
|
||||
controller.assets:addSFX("booster", "assets/sfx/gameplay/objects/booster.wav")
|
||||
controller.assets:addSFX("jumpboard", "assets/sfx/gameplay/objects/jumpboard.wav")
|
||||
|
||||
controller.assets:addSFX("jump", "assets/sfx/gameplay/actions/jump-modern.wav")
|
||||
controller.assets:addSFX("doublejump", "assets/sfx/gameplay/actions/doublejump.wav")
|
||||
controller.assets:addSFX("spin", "assets/sfx/gameplay/actions/spin.wav")
|
||||
|
||||
controller.assets:addSFX("grind", "assets/sfx/gameplay/grind/grind.wav")
|
||||
controller.assets:addSFX("grindland", "assets/sfx/gameplay/grind/land.wav")
|
||||
|
||||
controller.assets:addFont("menu", "assets/fonts/RussoOne-Regular.ttf", 15)
|
||||
controller.assets.fonts["menu"]:setAlign("center")
|
||||
controller.assets.fonts["menu"]:setFilter("border")
|
||||
controller.assets.fonts["menu"]:setSpacing(true, 1)
|
||||
|
||||
controller.assets:addFont("title", "assets/fonts/Teko-Bold.ttf", 22)
|
||||
controller.assets.fonts["title"]:setAlign("center")
|
||||
controller.assets.fonts["title"]:setFilter("doubleborder")
|
||||
controller.assets.fonts["title"]:setSpacing(true, 2)
|
||||
|
||||
controller.assets:addSFX("select", "assets/sfx/menu/select.wav")
|
||||
controller.assets:addSFX("validate", "assets/sfx/menu/validate.wav")
|
||||
controller.assets:addSFX("cancel", "assets/sfx/menu/cancel.wav")
|
||||
|
||||
end
|
||||
|
||||
return LoadAssets
|
102
sonic-boost.love/scenes/subgame/sonic-boost/controller/pause.lua
Normal file
102
sonic-boost.love/scenes/subgame/sonic-boost/controller/pause.lua
Normal file
|
@ -0,0 +1,102 @@
|
|||
local PauseMenu = Object:extend()
|
||||
local Menu = require "modules.menus"
|
||||
|
||||
local ResumeWidget = Menu.Widget.Base:extend()
|
||||
local RestartWidget = Menu.Widget.Base:extend()
|
||||
local ExitWidget = Menu.Widget.Base:extend()
|
||||
|
||||
function PauseMenu:new(controller)
|
||||
self.controller = controller
|
||||
self.active = false
|
||||
|
||||
self.height = 56+16
|
||||
|
||||
self.assets = self.controller.assets
|
||||
|
||||
self.menusystem = Menu.Controller()
|
||||
self.menu = Menu.TextMenu(424/2, self.height+8, self.assets.fonts["menu"], 6)
|
||||
|
||||
self.menusystem:addMenu(self.menu)
|
||||
self.menu:centerText(180)
|
||||
self.menu:setSound(self.assets.sfx["select"])
|
||||
self.menu.focus = true
|
||||
|
||||
self.menu:addWidget(ResumeWidget(self))
|
||||
self.menu:addWidget(RestartWidget(self))
|
||||
self.menu:addWidget(ExitWidget(self))
|
||||
|
||||
self.canvas = nil
|
||||
self.activeCanvas = false
|
||||
self.width = 0
|
||||
end
|
||||
|
||||
function PauseMenu:update(dt)
|
||||
self.menusystem:update(dt)
|
||||
end
|
||||
|
||||
function PauseMenu:draw()
|
||||
if (self.activeCanvas == false) then
|
||||
local width = self.menu:getWidth() or 10
|
||||
self.width = self:drawCanvas(width, 64)
|
||||
end
|
||||
|
||||
love.graphics.draw(self.canvas, (424 - self.width)/2, self.height - 28)
|
||||
self.menusystem:draw()
|
||||
end
|
||||
|
||||
function PauseMenu:drawCanvas(width, height)
|
||||
local width = (math.floor( width / 16 ) + 1) * 16
|
||||
local height = height or 80
|
||||
self.canvas = love.graphics.newCanvas(width + 64, height + 64)
|
||||
|
||||
CScreen:cease()
|
||||
love.graphics.setCanvas( self.canvas )
|
||||
|
||||
self.controller.gui.textbox["solid"]:draw(32, 32, width, height)
|
||||
self.controller.assets.fonts["title"]:draw("PAUSE", (width + 64)/2, 12, -1)
|
||||
|
||||
love.graphics.setCanvas( )
|
||||
CScreen:cease()
|
||||
|
||||
self.activeCanvas = true
|
||||
|
||||
return width + 64
|
||||
end
|
||||
|
||||
--- MENU WIDGETS
|
||||
|
||||
function ResumeWidget:new(menusystem)
|
||||
ResumeWidget.super.new(self)
|
||||
self.label = "resume"
|
||||
self.menusystem = menusystem
|
||||
self.controller = menusystem.controller
|
||||
end
|
||||
|
||||
function ResumeWidget:action()
|
||||
self.controller.pause = false
|
||||
end
|
||||
|
||||
function RestartWidget:new(menusystem)
|
||||
RestartWidget.super.new(self)
|
||||
self.label = "restart"
|
||||
self.menusystem = menusystem
|
||||
self.controller = menusystem.controller
|
||||
end
|
||||
|
||||
function RestartWidget:action()
|
||||
self.controller:restartLevel()
|
||||
end
|
||||
|
||||
function ExitWidget:new(menusystem)
|
||||
ExitWidget.super.new(self)
|
||||
self.label = "exit"
|
||||
self.menusystem = menusystem
|
||||
self.controller = menusystem.controller
|
||||
end
|
||||
|
||||
function ExitWidget:action()
|
||||
self.controller:exitLevel()
|
||||
end
|
||||
|
||||
|
||||
return PauseMenu
|
510
sonic-boost.love/scenes/subgame/sonic-boost/controller/world.lua
Normal file
510
sonic-boost.love/scenes/subgame/sonic-boost/controller/world.lua
Normal file
|
@ -0,0 +1,510 @@
|
|||
local World = Object:extend()
|
||||
|
||||
local bump3dpd = require 'libs.bump-3dpd'
|
||||
local bump2d = require 'libs.bump'
|
||||
local tsort = require 'libs.tsort'
|
||||
|
||||
local actor = require "scenes.levels.actors"
|
||||
|
||||
local tilesize = 31
|
||||
|
||||
---------- WORLD FUNCTIONS ----------
|
||||
|
||||
function World:new(controller)
|
||||
self.controller = controller
|
||||
self.creationID = 1
|
||||
|
||||
self.entities = bump3dpd.newWorld()
|
||||
self.chunks = {}
|
||||
|
||||
self:loadAssets()
|
||||
|
||||
self.worldloaded = false
|
||||
end
|
||||
|
||||
function World:destroy()
|
||||
self.chunks = {}
|
||||
for i,v in ipairs(self.entities:getItems()) do
|
||||
v:destroy( )
|
||||
end
|
||||
end
|
||||
|
||||
---------- ENTITIES MANAGEMENT FUNCTIONS ----------
|
||||
|
||||
function World:addEntitiesFromChunk(chunkpos)
|
||||
local chunkdata, isTrue = self:getChunkData(chunkpos, 1)
|
||||
local objectdata = chunkdata.objects
|
||||
|
||||
local chunkx = (chunkpos - 1) * (8*31)
|
||||
print("trying to get objects from chunk at pos " .. chunkpos)
|
||||
|
||||
for i=1, 5 do
|
||||
for j=1, 8 do
|
||||
local y = (i-1)*20 + 10
|
||||
local x = chunkx + (j-1)*31 + 16
|
||||
|
||||
local id = objectdata[i][j]
|
||||
--print(chunkpos)
|
||||
self:addEntityFromID(id, x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function World:addRailsFromChunk(chunkpos)
|
||||
local chunkdata, isTrue = self:getChunkData(chunkpos, 1)
|
||||
local objectdata = chunkdata.grind
|
||||
|
||||
local chunkx = (chunkpos - 1) * (8*31)
|
||||
print("trying to get rails from chunk at pos " .. chunkpos)
|
||||
|
||||
for i=1, 5 do
|
||||
for j=1, 8 do
|
||||
local y = (i-1)*20 + 10
|
||||
local x = chunkx + (j-1)*31
|
||||
|
||||
local id = objectdata[i][j]
|
||||
--print(chunkpos)
|
||||
if id ~= 0 then
|
||||
actor.Rail(self, x, y, 10, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function World:addEntityFromID(id, x, y)
|
||||
if actor.Index[id] == nil then
|
||||
if (id ~= 0) then
|
||||
print("WARNING: Object " .. id .. " doesn't exist")
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
actor.Index[id](self, x, y)
|
||||
end
|
||||
|
||||
function World:register(entity)
|
||||
self.entities:add(entity, entity.x, entity.y, entity.z, entity.w, entity.h, entity.d)
|
||||
end
|
||||
|
||||
function World:remove(entity)
|
||||
if entity.destroyed == false then
|
||||
self.entities:remove(entity)
|
||||
print("entity " .. entity.id .. " removed")
|
||||
end
|
||||
end
|
||||
|
||||
function World:move(entity, dx, dy, dz, filter)
|
||||
local dx, dy, dz = dx, dy, dz
|
||||
local newx, newy, newz
|
||||
newx, newy, newz, cols, coll_number = self.entities:move(entity, dx, dy, dz, filter)
|
||||
return newx, newy, newz, cols, coll_number
|
||||
end
|
||||
|
||||
function World:updateEntity(entity, dx, dy, dz)
|
||||
newx, newy, newz, cols, coll_number = self.entities:update(entity, dx, dy, dz)
|
||||
end
|
||||
|
||||
---------- UPDATE FUNCTIONS ----------
|
||||
|
||||
function World:update(dt)
|
||||
for _, item in ipairs(self.entities:getItems()) do
|
||||
item:update(dt)
|
||||
--self.world2D:update(item, item.x, item.y)
|
||||
end
|
||||
end
|
||||
|
||||
---------- DRAW FUNCTIONS ----------
|
||||
|
||||
|
||||
function World:draw()
|
||||
local chunksize = 8 * tilesize
|
||||
local camstart = math.floor(math.max(0, (self.controller.camera.view.x - 212) / chunksize)) --
|
||||
|
||||
self:drawBorder(-10)
|
||||
|
||||
for i=0, 3 do
|
||||
-- on fait commencer la boucle à 0 pour regarder celui *avant* la caméra,
|
||||
-- pour éviter des soucis d'affichage.
|
||||
local chunkid = camstart + i
|
||||
self:drawChunk((chunkid - 1) * chunksize, 0, chunkid)
|
||||
end
|
||||
|
||||
local itemsToDraw = self.entities:getItems()
|
||||
|
||||
for _, item in ipairs(itemsToDraw) do
|
||||
item:drawShadow()
|
||||
if self.controller.camera.turn < self.controller.missiondata.turns then
|
||||
item:drawShadowEcho()
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(itemsToDraw, sortItemsToDraw)
|
||||
|
||||
for _, item in ipairs(itemsToDraw) do
|
||||
item:draw()
|
||||
if self.controller.camera.turn < self.controller.missiondata.turns then
|
||||
item:drawEcho()
|
||||
end
|
||||
--item:drawHitBox()
|
||||
end
|
||||
|
||||
self:drawBorder(100)
|
||||
end
|
||||
|
||||
function World:drawChunk(x, y, chunkid, turn)
|
||||
local chunkdata, isTrue = self:getChunkData(chunkid, self.controller.camera.turn)
|
||||
local terraindata = chunkdata.terrain
|
||||
|
||||
for i=1, 5 do
|
||||
for j=1, 8 do
|
||||
local tiley = (i-1)*20 - 4
|
||||
local tilex = x + (j-1)*31 + (i-1)*10
|
||||
local tileid = terraindata[i][j]
|
||||
|
||||
local variant = 1 + ((i + j) % 2)
|
||||
if (isTrue == false) then
|
||||
love.graphics.setColor(.75, .75, .75, 1)
|
||||
end
|
||||
self:drawTile(tilex, tiley, tileid, variant)
|
||||
utils.draw.resetColor()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function World:drawTile(x, y, type, variant)
|
||||
if type == 0 then
|
||||
love.graphics.draw(self.textures.tiles, self.quads.tiles[variant], x, y)
|
||||
else
|
||||
love.graphics.draw(self.textures.sptiles, self.quads.sptiles[type], x, y-2)
|
||||
end
|
||||
end
|
||||
|
||||
function World:drawBorder(y)
|
||||
local x = math.floor((self.controller.camera.view.x - 212) / 80) * 80
|
||||
|
||||
for i=1, 7 do
|
||||
love.graphics.draw(self.textures.borders, self.quads.borders, x + (i-1)*80, y, 0, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
---------- LOADING FUNCTIONS ----------
|
||||
|
||||
function World:loadWorld()
|
||||
self.chunks = {}
|
||||
|
||||
self:addChunk("basics", 00)
|
||||
|
||||
local layout = self.controller.layout
|
||||
for i,v in ipairs(layout) do
|
||||
--print("Decompressing group of parts " .. i .. " located in " .. v[1] .. " (containing " .. #v[2] .. " parts)")
|
||||
|
||||
-- self.controller.layout est un tableau composée d'une série de tableau,
|
||||
-- chacuns en deux partie : le premier (v[1]) contient le nom du fichier
|
||||
-- où se trouve des partie de niveau, et la seconde partie (v[2]) une liste
|
||||
-- d'identifiant de partie de niveau à rajouter.
|
||||
|
||||
-- Ce format permet de simplifier l'écriture de layout, si on a besoin de
|
||||
-- plusieur partie de niveau se trouvant dans le même fichier.
|
||||
|
||||
for j,w in ipairs(v[2]) do
|
||||
-- On dit au gestionnaire de terrain d'ajouter la partie numéro j se trouvant
|
||||
-- dans v[2]. Le nom du fichier contenant les parties sera toujours v[1]
|
||||
self:addPart(v[1], w)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function World:addPart(filename, part)
|
||||
local filename = filename or "self"
|
||||
local partdata = {}
|
||||
|
||||
-- On recupère les données de chunks
|
||||
|
||||
if (filename == "self") or (filename == "") then
|
||||
|
||||
-- Si le nom est "self", cela veut dire que fichier est le même que celui ou
|
||||
-- se trouve le layout, qui est forcément le fichier du niveau. Cela veut dire
|
||||
-- qu'il faut utiliser les parties de niveau du niveau actuel, localisée dans
|
||||
-- self.controller.parts
|
||||
|
||||
partdata = self.controller.parts
|
||||
else
|
||||
|
||||
-- Si c'est un autre nom, on charge dans "partdata" la liste des partie de niveau
|
||||
-- du fichier qu'on réfère.
|
||||
|
||||
local chunkfile = require("datas.chunks." .. filename)
|
||||
partdata = chunkfile.parts
|
||||
end
|
||||
|
||||
-- On charge ensuite la partie de niveau voulue, qui correspond à l'identifiant
|
||||
-- qu'on a envoyé dans cette fonction (part) dans la liste partdata.
|
||||
|
||||
local chunklist = partdata[part]
|
||||
|
||||
for i, v in ipairs(chunklist) do
|
||||
-- chunklist fonctionne de la même manière que partlist :
|
||||
-- chaque entrée dans la liste (v) contient deux partie.
|
||||
-- v[1]: l'identifiant du fichier de chunk où se trouve le chunk voulu
|
||||
-- v[2]: la liste de chunks voulu. chaque entrée dedans est un nombre,
|
||||
-- correspondant à un chunk
|
||||
|
||||
--print("- Decompressing group of chunk " .. i .. " located in " .. v[1] .. " (containing " .. #v[2] .. " chunk)")
|
||||
|
||||
for j, w in ipairs(v[2]) do
|
||||
local chunkfile = v[1]
|
||||
if (chunkfile == "") or (chunkfile == "self") then
|
||||
-- si le fichier de chunk est "self", on lui indique que le chunk se trouve
|
||||
-- dans le même fichier que le fichier de partie.
|
||||
chunkfile = filename
|
||||
end
|
||||
self:addChunk(chunkfile, w)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function World:addChunk(filename, chunk)
|
||||
if filename == "self" then filename = "basic" end
|
||||
--print("--- Adding chunk id " .. chunk .. " located in " .. filename)
|
||||
|
||||
local chunkfile = require("datas.chunks." .. filename)
|
||||
chunkdata = chunkfile.chunks
|
||||
|
||||
local chunkpos = #self.chunks
|
||||
|
||||
table.insert(self.chunks, chunkdata[chunk])
|
||||
self:addEntitiesFromChunk(chunkpos)
|
||||
self:addRailsFromChunk(chunkpos)
|
||||
self:updateSize()
|
||||
end
|
||||
|
||||
---------- ASSETS LOADING FUNCTIONS ----------
|
||||
|
||||
function World:loadAssets()
|
||||
self.textures = {}
|
||||
self.textures.tiles = love.graphics.newImage("assets/levels/normaltile.png")
|
||||
self.textures.sptiles = love.graphics.newImage("assets/levels/specialtile.png")
|
||||
self.textures.borders = love.graphics.newImage("assets/levels/borders.png")
|
||||
|
||||
self.textures.rail = love.graphics.newImage("assets/levels/rails/basic.png")
|
||||
|
||||
self.quads = {}
|
||||
self.quads.tiles = {}
|
||||
self.quads.sptiles = {}
|
||||
self.quads.rails = {}
|
||||
|
||||
local tileline = self.controller.datas.tiles or 0
|
||||
local borderline = self.controller.datas.borders or 0
|
||||
|
||||
|
||||
local w, h = self.textures.tiles:getDimensions()
|
||||
self.quads.tiles[1] = love.graphics.newQuad( 0, tileline*24, 40, 24, w, h)
|
||||
self.quads.tiles[2] = love.graphics.newQuad(40, tileline*24, 40, 24, w, h)
|
||||
|
||||
local w, h = self.textures.sptiles:getDimensions()
|
||||
local h2 = math.floor(h / 26)
|
||||
for i=1, h2 do
|
||||
self.quads.sptiles[i] = love.graphics.newQuad(0, (i-1)*26, 40, 26, w, h)
|
||||
end
|
||||
|
||||
local w, h = self.textures.borders:getDimensions()
|
||||
self.quads.borders = love.graphics.newQuad(0, borderline*10, 80, 10, w, h)
|
||||
|
||||
local w, h = self.textures.rail:getDimensions()
|
||||
for i=1, 3 do
|
||||
self.quads.rails[i] = love.graphics.newQuad((i-1)*31, 0, 31, 8, w, h)
|
||||
end
|
||||
end
|
||||
|
||||
---------- DATA FUNCTIONS ----------
|
||||
|
||||
function World:getChunkData(chunkid, turn)
|
||||
local turn = turn or 1
|
||||
local currentTurn, maxTurn = turn, self.controller.missiondata.turns
|
||||
|
||||
if chunkid <= 0 then
|
||||
if currentTurn <= 1 then
|
||||
return self:getFakeChunk()
|
||||
else
|
||||
chunkid = (chunkid - 1)
|
||||
chunkid = utils.math.wrap(chunkid, 0, #self.chunks)
|
||||
return self.chunks[chunkid + 1], true
|
||||
end
|
||||
elseif chunkid > #self.chunks then
|
||||
if currentTurn >= maxTurn then
|
||||
return self:getFakeChunk()
|
||||
else
|
||||
chunkid = (chunkid - 1)
|
||||
chunkid = utils.math.wrap(chunkid, 0, #self.chunks)
|
||||
return self.chunks[chunkid + 1], true
|
||||
end
|
||||
else
|
||||
return self.chunks[chunkid], true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function World:getFakeChunk()
|
||||
local fakedata = {}
|
||||
local emptyline = {00, 00, 00, 00, 00, 00, 00, 00}
|
||||
fakedata.objects = {emptyline, emptyline, emptyline, emptyline, emptyline}
|
||||
fakedata.terrain = {emptyline, emptyline, emptyline, emptyline, emptyline}
|
||||
fakedata.grind = {emptyline, emptyline, emptyline, emptyline, emptyline}
|
||||
|
||||
return fakedata, false
|
||||
end
|
||||
|
||||
function World:getTerrainAtPoint(x, y, turn)
|
||||
local chunkid = self:getChunkAtPoint(x, y)
|
||||
local chunkdata, isTrue = self:getChunkData(chunkid, turn)
|
||||
|
||||
local i = math.floor(y / 20) + 1
|
||||
local j = math.floor((x % (8*31)) / 31) + 1
|
||||
|
||||
local terrain = chunkdata.terrain[i][j]
|
||||
|
||||
--print(terrain)
|
||||
return terrain
|
||||
end
|
||||
|
||||
function World:getGrindAtPoint(x, y, turn)
|
||||
local chunkid = self:getChunkAtPoint(x, y)
|
||||
local chunkdata, isTrue = self:getChunkData(chunkid, turn)
|
||||
|
||||
local i = math.floor(y / 20) + 1
|
||||
local j = math.floor((x % (8*31)) / 31) + 1
|
||||
|
||||
local grind = chunkdata.grind[i][j]
|
||||
|
||||
--print(terrain)
|
||||
return grind > 0
|
||||
end
|
||||
|
||||
function World:getChunkAtPoint(x, y)
|
||||
return math.floor(x / (8*31)) + 1
|
||||
end
|
||||
|
||||
|
||||
---------- USEFULL FUNCTIONS ----------
|
||||
|
||||
function World:updateSize()
|
||||
self.size = #self.chunks * 8
|
||||
self.width = self.size * 31
|
||||
end
|
||||
|
||||
function World:getZSortedItems()
|
||||
local bump2d = require 'libs.bump'
|
||||
local tsort = require 'libs.tsort'
|
||||
local world2d = bump2d.newWorld()
|
||||
|
||||
local world = self.entities
|
||||
|
||||
for _, item in ipairs(world:getItems()) do
|
||||
if item.invisible ~= true and item.destroyed ~= true then
|
||||
local x,y,z,w,h,d = world:getCube(item)
|
||||
if world2d:hasItem(item) then
|
||||
world2d:update(item, x, y + z)
|
||||
else
|
||||
world2d:add(item, x, y + z, w, h + d)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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(world2d:getItems()) do repeat
|
||||
local x, y, w, h = world2d:getRect(itemA)
|
||||
local otherItemsFilter = function(other) return other ~= itemA end
|
||||
local overlapping, len = world2d:queryRect(x, y, w, h, otherItemsFilter)
|
||||
|
||||
if len == 0 then
|
||||
table.insert(noOverlap, itemA)
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
local _, aY, aZ, _, aH, aD = world:getCube(itemA)
|
||||
aDepth = itemA.depth
|
||||
aID = itemA.id
|
||||
aType = itemA.type
|
||||
|
||||
--print("testing overlap with itemA " .. aID .. " (" .. aType .. ")")
|
||||
|
||||
|
||||
for _, itemB in ipairs(overlapping) do
|
||||
local _, bY, bZ, _, bH, bD = world:getCube(itemB)
|
||||
bDepth = itemB.depth
|
||||
bID = itemB.id
|
||||
bType = itemB.type
|
||||
|
||||
--print("itemB " .. aID .. " overlap with item " .. bID .. " (" .. bType .. ")")
|
||||
|
||||
if aZ + aD <= bZ then
|
||||
-- item A is completely above item B
|
||||
graph:add(itemB, itemA)
|
||||
--print("itemA is completely above itemB")
|
||||
elseif bZ + bD <= aZ then
|
||||
-- item B is completely above item A
|
||||
graph:add(itemA, itemB)
|
||||
--print("itemB is completely above itemA")
|
||||
elseif aY + aH <= bY then
|
||||
-- item A is completely behind item B
|
||||
graph:add(itemA, itemB)
|
||||
--print("itemA is completely behind itemB")
|
||||
elseif bY + bH <= aY then
|
||||
-- item B is completely behind item A
|
||||
graph:add(itemB, itemA)
|
||||
--print("itemB is completely behind itemA")
|
||||
elseif aY + aZ + aH + aD == bY + bZ + bH + bD then
|
||||
-- item A's forward-most point is the same than item B's forward-most point
|
||||
--print("itemA's forward-most point is the same than itemB'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
|
||||
elseif aY + aZ + aH + aD >= bY + bZ + bH + bD then
|
||||
-- item A's forward-most point is in front of item B's forward-most point
|
||||
graph:add(itemB, itemA)
|
||||
--print("itemA's forward-most point is in front of itemB's forward-most point")
|
||||
else
|
||||
-- item B's forward-most point is in front of item A's forward-most point
|
||||
graph:add(itemA, itemB)
|
||||
--print("itemB's forward-most point is in front of itemA's forward-most point")
|
||||
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
|
||||
|
||||
function sortItemsToDraw(a, b)
|
||||
return a.y < b.y
|
||||
end
|
||||
|
||||
return World
|
32
sonic-boost.love/scenes/subgame/sonic-boost/init.lua
Normal file
32
sonic-boost.love/scenes/subgame/sonic-boost/init.lua
Normal file
|
@ -0,0 +1,32 @@
|
|||
local Levels = {}
|
||||
local Controller = require "scenes.levels.controller"
|
||||
|
||||
function Levels:enter()
|
||||
self.controller = Controller()
|
||||
print("battle started")
|
||||
--self.background = love.graphics.newImage("assets/background/testbackground.png")
|
||||
end
|
||||
|
||||
function Levels:update(dt)
|
||||
game:update(dt)
|
||||
game.input:update(dt)
|
||||
self.controller:update(dt)
|
||||
end
|
||||
|
||||
function Levels:draw()
|
||||
--CScreen:apply()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.rectangle("fill", 0, 0, 424, 240)
|
||||
--love.graphics.draw(self.background, 0, 0)
|
||||
self.controller:draw()
|
||||
--CScreen:cease()
|
||||
end
|
||||
|
||||
function Levels:leave()
|
||||
self.controller:destroy()
|
||||
self.controller = nil
|
||||
|
||||
collectgarbage()
|
||||
end
|
||||
|
||||
return Levels
|
Loading…
Reference in a new issue