scene: add back level code from an earlier boost version

This commit is contained in:
Kazhnuz 2019-02-03 19:54:02 +01:00
parent 24dda63900
commit 81afa3ff11
19 changed files with 2114 additions and 0 deletions

View file

@ -0,0 +1,7 @@
local ActorIndex = {}
local Actor = "scenes.levels.actors"
ActorIndex[1] = Actor.Ring
ActorIndex[2] = Actor.Crystal
return ActorIndex

View 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

View 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

View file

@ -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

View 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

View 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

View 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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View 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

View file

@ -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

View 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

View 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

View 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