WIP: new-cbs #117

Closed
kazhnuz wants to merge 23 commits from new-cbs into master
40 changed files with 1011 additions and 281 deletions

View file

@ -0,0 +1,102 @@
-- classes/states :: a finite state machine for objects
--[[
Copyright © 2022 Kazhnuz
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
local StateMachine = Object:extend()
function StateMachine.addState(self, name, state, isDefault)
if (self.states == nil) then
self.states = {}
self.states.list = {}
end
self.states.list[name] = state
if (isDefault == true) then
self.states.default = name
end
end
function StateMachine.addStates(self, statesPath, default)
local states = require(statesPath)
for i, stateName in ipairs(states) do
local state = require(statesPath .. "." .. stateName)
self:addState(stateName, state)
end
self.states.default = default
end
function StateMachine:initStates()
if (self.states == nil) then
self.states = {}
self.states.list = {}
end
self.currentState = self.states.default or "none"
end
function StateMachine:updateState(dt)
self:playStateFunc("update", dt)
end
function StateMachine:haveState(state)
return (self.states.list[state] ~= nil)
end
function StateMachine:setState(state)
if (not self:haveState(state)) then
return self.currentState
end
self:playStateFunc("stop", state)
local currentState = self.currentState
self.currentState = state
self:playStateFunc("start", currentState)
return state
end
function StateMachine:getState()
return self.states.list[self.currentState]
end
function StateMachine:getStateVar(varName, default)
local state = self:getState()
if (state == nil) then
return nil
end
local var = state[varName]
if (var == nil) then
return default
end
return var
end
function StateMachine:playStateFunc(funcName, ...)
local state = self:getState()
if (state == nil) then
return
end
local func = state[funcName]
if (func ~= nil) then
func(self, ...)
end
end
return StateMachine

View file

@ -87,9 +87,18 @@ function Animator:changeAnimation(name, restart)
restart = restart or false restart = restart or false
end end
if (self.sprite.data.animations[name] ~= nil) then
self.currentAnimation = name self.currentAnimation = name
else
self.currentAnimation = self.sprite.data.metadata.defaultAnim
end
self.animationData = self.sprite.data.animations[self.currentAnimation] self.animationData = self.sprite.data.animations[self.currentAnimation]
if (self.animationData == nil) then
error("animation " .. self.currentAnimation .. " not found.")
end
if (restart == true) then if (restart == true) then
self.frame = self.animationData.startAt self.frame = self.animationData.startAt
self.frameTimer = 0 self.frameTimer = 0

View file

@ -29,6 +29,8 @@ local TimedActor = require("birb.modules.world.actors.mixins.timers")
local InputActor = require("birb.modules.world.actors.mixins.inputs") local InputActor = require("birb.modules.world.actors.mixins.inputs")
local PhysicalActor = require("birb.modules.world.actors.mixins.physics") local PhysicalActor = require("birb.modules.world.actors.mixins.physics")
local StateMachine = require("birb.classes.states")
local Actor2D = Rect:extend() local Actor2D = Rect:extend()
Actor2D:implement(BaseActor) Actor2D:implement(BaseActor)
Actor2D:implement(SpritedActor) Actor2D:implement(SpritedActor)
@ -36,6 +38,8 @@ Actor2D:implement(TimedActor)
Actor2D:implement(InputActor) Actor2D:implement(InputActor)
Actor2D:implement(PhysicalActor) Actor2D:implement(PhysicalActor)
Actor2D:implement(StateMachine)
local Hitbox = require "birb.modules.world.actors.utils.hitbox2D" local Hitbox = require "birb.modules.world.actors.utils.hitbox2D"
-- INIT FUNCTIONS -- INIT FUNCTIONS
@ -49,6 +53,7 @@ function Actor2D:new(world, type, x, y, w, h, isSolid)
self:initTimers() self:initTimers()
self:initSprite() self:initSprite()
self:initKeys() self:initKeys()
self:initStates()
end end
function Actor2D:destroy() function Actor2D:destroy()

View file

@ -33,6 +33,8 @@ local InputActor = require("birb.modules.world.actors.mixins.inputs")
local PhysicalActor = require("birb.modules.world.actors.mixins.physics") local PhysicalActor = require("birb.modules.world.actors.mixins.physics")
local Shape3DActor = require("birb.modules.world.actors.mixins.shapes") local Shape3DActor = require("birb.modules.world.actors.mixins.shapes")
local StateMachine = require("birb.classes.states")
local Actor3D = BasicBox:extend() local Actor3D = BasicBox:extend()
Actor3D:implement(BaseActor) Actor3D:implement(BaseActor)
Actor3D:implement(SpritedActor) Actor3D:implement(SpritedActor)
@ -41,6 +43,8 @@ Actor3D:implement(InputActor)
Actor3D:implement(PhysicalActor) Actor3D:implement(PhysicalActor)
Actor3D:implement(Shape3DActor) Actor3D:implement(Shape3DActor)
Actor3D:implement(StateMachine)
-- INIT FUNCTIONS -- INIT FUNCTIONS
-- Initialise the actor and its base functions -- Initialise the actor and its base functions
@ -52,6 +56,7 @@ function Actor3D:new(world, type, x, y, z, w, h, d, isSolid)
self:initSprite() self:initSprite()
self:initKeys() self:initKeys()
self:initShape(Boxes, true) self:initShape(Boxes, true)
self:initStates()
end end
function Actor3D:destroy() function Actor3D:destroy()

View file

@ -88,6 +88,7 @@ end
function BaseActor:update(dt) function BaseActor:update(dt)
self:updateStart(dt) self:updateStart(dt)
self:applyUpdateFunctions(dt) self:applyUpdateFunctions(dt)
self:updateState(dt)
self:updateEnd(dt) self:updateEnd(dt)
end end

View file

@ -123,6 +123,10 @@ function Hitbox3D:getCenter()
return self.x + (self.w/2), self.y + (self.h/2), self.z + (self.d/2) return self.x + (self.w/2), self.y + (self.h/2), self.z + (self.d/2)
end end
function Hitbox3D:getCube()
return self.world.bodies:getCube(self)
end
-- COLLISION FUNCTIONS -- COLLISION FUNCTIONS
-- Handle Hitbox position -- Handle Hitbox position

View file

@ -0,0 +1,74 @@
local comparisons = {}
function comparisons.zsort(itemA, itemB)
local _, aY, aZ, _, aH, aD = itemA.mainHitbox:getCube()
local aDepth, aID, aType
aDepth = itemA.depth
aID = itemA.creationID
aType = itemA.type
aZ = math.ceil(aZ)
aY = math.ceil(aY)
local _, bY, bZ, _, bH, bD = itemB.mainHitbox:getCube()
local bDepth, bID, bType
bDepth = itemB.depth
bID = itemB.creationID
bType = itemB.type
bZ = math.ceil(bZ)
bY = math.ceil(bY)
--print("comparing " .. aID .. " to " .. bID)
--print("a", aY, aZ, aH, aD, aDepth, aID, itemA.type)
--print("b", bY, bZ, bH, bD, bDepth, bID, itemB.type)
local comparison = 0
if aZ >= bZ + bD then
-- item A is completely above item B
--graph:add(itemB, itemA)
comparison = 1
elseif bZ >= aZ + aD then
-- item B is completely above item A
--graph:add(itemA, itemB)
comparison = -1
elseif aY + aH <= bY then
-- item A is completely behind item B
--graph:add(itemA, itemB)
comparison = -1
elseif bY + bH <= aY then
-- item B is completely behind item A
--graph:add(itemB, itemA)
comparison = 1
elseif aY + aH > bY + bH then --(aY - aZ) + aH > (bY - bZ) + bH then
-- item A's forward-most point is in front of item B's forward-most point
--graph:add(itemB, itemA)
comparison = 1
elseif aY + aH < bY + bH then --aY < (bY - bZ) + bH then
-- item B's forward-most point is in front of item A's forward-most point
--graph:add(itemA, itemB)
comparison = -1
else
-- item A's forward-most point is the same than item B's forward-most point
if aDepth > bDepth then
--graph:add(itemB, itemA)
comparison = 1
elseif aDepth < bDepth then
--graph:add(itemA, itemB)
comparison = -1
else
if aID > bID then
--graph:add(itemA, itemB)
comparison = 1
elseif aID < bID then
--graph:add(itemB, itemA)
comparison = -1
end
end
end
return comparison == -1
end
return comparisons

View file

@ -31,6 +31,8 @@ local Bump3D = require(cwd .. "libs.bump-3dpd")
local Tsort = require(cwd .. "libs.tsort") local Tsort = require(cwd .. "libs.tsort")
local CameraSystem = require(cwd .. "camera") local CameraSystem = require(cwd .. "camera")
local comparisons = require(cwd .. "utils.compare")
local PADDING_VALUE = 10/100 local PADDING_VALUE = 10/100
function World3D:new(scene, actorlist, mapfile, maptype) function World3D:new(scene, actorlist, mapfile, maptype)
@ -183,87 +185,10 @@ end
-- Functions to draw the world -- Functions to draw the world
function World3D:zSortItems(items) function World3D:zSortItems(items)
-- zSorting algorithm taken from bump3D example, adapted to gamecore. -- TODO : take from a self.shapes:queryRect()
local graph = Tsort.new() table.sort(items, comparisons.zsort)
local noOverlap = {}
-- Iterate through all visible items, and calculate ordering of all pairs return items
-- of overlapping items.
-- TODO: Each pair is calculated twice currently. Maybe this is slow?
for _, itemA in ipairs(items) do repeat
local x, y, w, h = self.shapes:getRect(itemA)
local otherItemsFilter = function(other) return other ~= itemA end
local overlapping, len = self.shapes:queryRect(x, y, w, h, otherItemsFilter)
if len == 0 then
table.insert(noOverlap, itemA)
break
end
local _, aY, aZ, _, aH, aD = self.bodies:getCube(itemA.mainHitbox)
local aDepth, aID, aType
aDepth = itemA.depth
aID = itemA.creationID
aType = itemA.type
aZ = math.ceil(aZ)
aY = math.ceil(aY)
for _, itemB in ipairs(overlapping) do
local _, bY, bZ, _, bH, bD = self.bodies:getCube(itemB.mainHitbox)
local bDepth, bID, bType
bDepth = itemB.depth
bID = itemB.creationID
bType = itemB.type
bZ = math.ceil(bZ)
bY = math.ceil(bY)
if aZ >= bZ + bD then
-- item A is completely above item B
graph:add(itemB, itemA)
elseif bZ >= aZ + aD then
-- item B is completely above item A
graph:add(itemA, itemB)
elseif aY + aH <= bY then
-- item A is completely behind item B
graph:add(itemA, itemB)
elseif bY + bH <= aY then
-- item B is completely behind item A
graph:add(itemB, itemA)
elseif (aY - aZ) + aH > (bY - bZ) + bH then
-- item A's forward-most point is in front of item B's forward-most point
graph:add(itemB, itemA)
elseif (aY - aZ) + aH < (bY - bZ) + bH then
-- item B's forward-most point is in front of item A's forward-most point
graph:add(itemA, itemB)
else
-- item A's forward-most point is the same than item B's forward-most point
if aDepth > bDepth then
graph:add(itemB, itemA)
elseif aDepth < bDepth then
graph:add(itemA, itemB)
else
if aID > bID then
graph:add(itemA, itemB)
elseif aID < bID then
graph:add(itemB, itemA)
else
error("two object can't have the same ID")
end
end
end
end
until true end
local sorted, err = graph:sort()
if err then
error(err)
end
for _, item in ipairs(noOverlap) do
table.insert(sorted, item)
end
return sorted
end end

View file

@ -35,46 +35,25 @@ return {
speed = 10, speed = 10,
pauseAtEnd = true, pauseAtEnd = true,
}, },
["hit1start"] = { ["hit1"] = {
startAt = 29, startAt = 29,
endAt = 32,
loop = 32,
speed = 25,
pauseAtEnd = true,
},
["hit1end"] = {
startAt = 33,
endAt = 34, endAt = 34,
loop = 34, loop = 34,
speed = 25, speed = 20,
pauseAtEnd = true, pauseAtEnd = true,
}, },
["hit2start"] = { ["hit2"] = {
startAt = 35, startAt = 35,
endAt = 37,
loop = 37,
speed = 25,
pauseAtEnd = true,
},
["hit2end"] = {
startAt = 38,
endAt = 39, endAt = 39,
loop = 39, loop = 39,
speed = 25, speed = 20,
pauseAtEnd = true, pauseAtEnd = true,
}, },
["hit3start"] = { ["hit3"] = {
startAt = 40, startAt = 40,
endAt = 44,
loop = 44,
speed = 25,
pauseAtEnd = true,
},
["hit3end"] = {
startAt = 45,
endAt = 46, endAt = 46,
loop = 46, loop = 46,
speed = 25, speed = 20,
pauseAtEnd = true, pauseAtEnd = true,
}, },
["spindash"] = { ["spindash"] = {

View file

@ -35,46 +35,25 @@ return {
speed = 10, speed = 10,
pauseAtEnd = true, pauseAtEnd = true,
}, },
["hit1start"] = { ["hit1"] = {
startAt = 22, startAt = 22,
endAt = 24,
loop = 24,
speed = 25,
pauseAtEnd = true,
},
["hit1end"] = {
startAt = 24,
endAt = 26, endAt = 26,
loop = 26, loop = 26,
speed = 25, speed = 20,
pauseAtEnd = true, pauseAtEnd = true,
}, },
["hit2start"] = { ["hit2"] = {
startAt = 28, startAt = 28,
endAt = 30,
loop = 30,
speed = 25,
pauseAtEnd = true,
},
["hit2end"] = {
startAt = 30,
endAt = 32, endAt = 32,
loop = 32, loop = 32,
speed = 25, speed = 20,
pauseAtEnd = true, pauseAtEnd = true,
}, },
["hit3start"] = { ["hit3"] = {
startAt = 33, startAt = 33,
endAt = 35,
loop = 35,
speed = 25,
pauseAtEnd = true,
},
["hit3end"] = {
startAt = 36,
endAt = 36, endAt = 36,
loop = 36, loop = 36,
speed = 25, speed = 20,
pauseAtEnd = true, pauseAtEnd = true,
}, },
["spindash"] = { ["spindash"] = {

View file

@ -6,11 +6,26 @@ return {
["right"] = "right", ["right"] = "right",
["up"] = "up", ["up"] = "up",
["down"] = "down", ["down"] = "down",
["dleft"] = "k",
["dright"] = "m",
["dup"] = "o",
["ddown"] = "l",
["A"] = "a", ["A"] = "a",
["B"] = "z", ["B"] = "z",
["C"] = "e", ["X"] = "e",
["Y"] = "r",
["C"] = "n",
["start"] = "return", ["start"] = "return",
["select"] = "space" ["select"] = "space",
["R1"] = "w",
["R2"] = "q",
["L1"] = "x",
["L2"] = "s",
} }
} }
} }

View file

@ -1 +1,21 @@
return {"up", "down", "left", "right", "A", "B", "C", "start", "select"} return {
"up",
"down",
"left",
"right",
"dup",
"ddown",
"dleft",
"dright",
"A",
"B",
"X",
"Y",
"C",
"start",
"select",
"R1",
"R2",
"L1",
"L2",
}

View file

@ -0,0 +1,52 @@
local EnnemyController = Object:extend()
local Villain = require "scenes.battlesystem.fighters.ennemy"
local STATS = require "datas.consts.stats"
function EnnemyController:new(scene)
self.super.new(self)
self.scene = scene
self.list = {}
end
function EnnemyController:addAll(ennemies)
local count = self:countList(ennemies)
for i, ennemyBaseData in ipairs(ennemies) do
local ennData = core.datas:parse("ennemytype", ennemyBaseData)
local nbr = ennData.number or 1
for i=1, nbr do
self:add(ennData, count)
end
end
end
function EnnemyController:countList(ennemies)
local count = 0
for i, ennemyBaseData in ipairs(ennemies) do
local ennData = core.datas:parse("ennemytype", ennemyBaseData)
local nbr = ennData.number or 1
count = count + nbr
end
return count
end
function EnnemyController:getEnnemyArchetype(ennData)
if (ennData.archetype ~= nil) then
return ennData.archetype
end
return ennData.name
end
function EnnemyController:add(ennData, count)
local ennemy = {}
ennemy.type = ennData.type
ennemy.name = ennData.name
ennemy.category = ennData.category
ennemy.actor = nil
ennemy.isAlive = true
ennemy.data = ennData
table.insert(self.list, ennemy)
self.scene.world:spawnEnnemy(self:getEnnemyArchetype(ennData), ennemy, count)
end
return EnnemyController

View file

@ -0,0 +1,64 @@
local GuiScreen = require "birb.modules.gui.screen"
local OWScreen = GuiScreen:extend()
local Composite = require "birb.modules.gui.elements.composite"
local Counter = require "birb.modules.gui.elements.counter"
local Asset = require "birb.modules.gui.elements.assets"
local Emblems = require "scenes.overworld.gui.hudelements.emblems"
local StatusBar = require "scenes.battlesystem.gui.hudelements.statutbar"
local show = {
-- {"rings", "movement", 0, 0.3, 16, 16, "inOutQuart"},
-- {"time", "movement", 0, 0.3, 408, 250, "inOutQuart"},
{"teamEmblems", "movement", 0, 0.3, 368, 24, "inOutQuart"},
-- {"lifebars", "movement", 0, 0.3, 8, 168, "inOutQuart"},
}
local hide = {
-- {"rings", "movement", 0, 0.3, -16, -16, "inOutQuart"},
-- {"time", "movement", 0, 0.3, 408, 250, "inOutQuart"},
{"teamEmblems", "movement", 0, 0.3, 500, 24, "inOutQuart"},
-- {"lifebars", "movement", 0, 0.3, -124, 168, "inOutQuart"},
}
local showMenu = {
-- {"rings", "movement", 0, 0.5, 8, 8, "inOutQuart"},
-- {"time", "movement", 0, 0.5, 408, 221, "inOutQuart"},
{"teamEmblems", "movement", 0, 0.3, 500, 24, "inOutQuart"},
-- {"lifebars", "movement", 0, 0.3, -124, 168, "inOutQuart"},
}
local hideMenu = {
-- {"rings", "movement", 0, 0.5, 16, 16, "inOutQuart"},
-- {"time", "movement", 0, 0.5, 408, 250, "inOutQuart"},
{"teamEmblems", "movement", 0, 0.3, 368, 24, "inOutQuart"},
-- {"lifebars", "movement", 0, 0.3, 8, 168, "inOutQuart"}
}
function OWScreen:new()
OWScreen.super.new(self, "hud")
self:addTransform("show", show)
self:addTransform("hide", hide)
self:addTransform("pause", showMenu)
self:addTransform("unpause", hideMenu)
self:show()
end
function OWScreen:createElements()
local list = {
-- {Composite("rings", -16, -16, {
-- {Asset("guiRing", "images", "guiRing", -1, -1), 0, 0},
-- {Counter("turnCnt", "hudnbrs", game.loot, "rings", 3, -1, -1), 14, 1}
-- }), 0, -100},
-- {TimeElement("hudnbrs", 408, 250, "right"), 0, -100},
Emblems(500, 24),
StatusBar(),
-- Lifebars(-124, 168),
-- Interactions()
}
return list
end
return OWScreen

View file

@ -3,8 +3,11 @@ local PlayStyle = Scene:extend()
local TweenManager = require "birb.classes.time" local TweenManager = require "birb.classes.time"
local PauseScreen = require("game.modules.subgames.pause") local PauseScreen = require("game.modules.subgames.pause")
local HUD = require("game.modules.subgames.hud")
local TestWorld = require("game.modules.subgames.world.parent") local TestWorld = require("game.modules.subgames.world.parent")
local EnnemyController = require "game.modules.subgames.ennemies"
function PlayStyle:new(supportedLevels, missionfile) function PlayStyle:new(supportedLevels, missionfile)
PlayStyle.super.new(self, false, false) PlayStyle.super.new(self, false, false)
self.timer = 0 self.timer = 0
@ -17,9 +20,11 @@ function PlayStyle:new(supportedLevels, missionfile)
self.tweens = TweenManager(self) self.tweens = TweenManager(self)
PauseScreen() PauseScreen()
HUD()
self.haveStarted = false self.haveStarted = false
self.canPause = true self.canPause = true
self.ennemies = EnnemyController(self)
end end
function PlayStyle:loadMissionFile(supportedLevels, missionfile) function PlayStyle:loadMissionFile(supportedLevels, missionfile)

View file

@ -0,0 +1,33 @@
local Parent = require("game.modules.subgames.world.actors.fighters.parent")
local Ennemy = Parent:extend()
function Ennemy:new(world, x, y, owner)
self.defaultDir = -1
self.owner = owner
self.data = self.owner.data
Ennemy.super.new(self, world, x, y, self.owner.name)
self:changeSprite(self.owner.name)
end
function Ennemy:getAbstract()
return game.ennemies:getEnnemyData(self.owner.category, self.owner.name)
end
function Ennemy:getFighterHitbox()
return 16, 12, self.abstract.data.hudHeight
end
function Ennemy:isAerial()
return self.abstract.data.isAerial
end
function Ennemy:getCustomSpeed()
return 16
end
function Ennemy:getSpritePath()
return "datas/gamedata/ennemies/" .. self.owner.category .. "/" .. self.owner.name .. "/sprites"
end
return Ennemy

View file

@ -0,0 +1,7 @@
local FighterAbstract = Object:extend()
function FighterAbstract:initAbstract()
self.abstract = self:getAbstract()
end
return FighterAbstract

View file

@ -0,0 +1,54 @@
local PlayerMovement = Object:extend()
local SPEED = 160
function PlayerMovement:initMovements()
if (not self:isAerial()) then
self:setGravity(480 * 2)
end
end
function PlayerMovement:updateMovements()
self:setFrc()
end
-- GOTO FUNCTIONS
-- Help the movable go toward something
function PlayerMovement:goTowardDir(angle, strenght)
self.xsp, self.ysp = utils.math.lengthdir(SPEED, angle)
end
function PlayerMovement:goX(dir)
self.xsp = SPEED * (dir or 1)
end
function PlayerMovement:goY(dir)
self.ysp = SPEED * (dir or 1)
end
-- FRICTION
function PlayerMovement:setFrc()
self.xfrc, self.yfrc = 480 * 3, 480 * 3
end
-- JUMP FUNCTIONS
function PlayerMovement:jump()
self.zsp = 280 * 1.33
end
function PlayerMovement:isNotJumping()
return self.onGround
end
function PlayerMovement:getStartZ()
if (self:isAerial()) then
return 16
else
return 0
end
end
return PlayerMovement

View file

@ -0,0 +1,59 @@
local FighterSprite = Object:extend()
function FighterSprite:changeSprite(name)
if (self.assets.sprites[name] == nil) then
self.assets:addSprite(name, self:getSpritePath(name))
end
self.assets.sprites[name]:setCustomSpeed(16)
local ox, oy = self:getOrigin()
self:setSprite(name, true, ox, oy)
self:changeAnimation("idle")
self:setDirection(self.direction or self.defaultDir)
end
function FighterSprite:getOrigin()
local _, _, d = self:getFighterHitbox()
return 8, (d - 14)
end
function FighterSprite:updateSprites(dt)
self.sprite:setCustomSpeed(self:getCustomSpeed())
self:setDirection(self.xsp)
self:setAnimation()
end
function FighterSprite:setAnimation()
if (self:getStateVar("defaultAnim", false)) then
self:defaultAnim()
else
self:playStateFunc("changeAnimation")
end
end
function FighterSprite:defaultAnim()
if (self.onGround or self:isAerial()) then
if (math.abs(self.xsp) > 0) or (math.abs(self.ysp) > 0) then
self.sprite:changeAnimation("walk", false)
else
self.sprite:changeAnimation("idle", false)
end
else
if (self.zsp) > 0 then
self.sprite:changeAnimation("jump", false)
else
self.sprite:changeAnimation("fall", false)
end
end
end
function FighterSprite:setDirection(direction)
direction = direction or 0
if (direction ~= 0) then
direction = utils.math.sign(direction)
self.direction = direction
self.sprite:setScallingX(direction)
end
end
return FighterSprite

View file

@ -0,0 +1,45 @@
local Parent = require("game.modules.subgames.world.actors.parent")
local FighterParent = Parent:extend()
local TweenManager = require "birb.classes.time"
local Movements = require "game.modules.subgames.world.actors.fighters.mixins.movements"
local Sprites = require "game.modules.subgames.world.actors.fighters.mixins.sprites"
local Abstract = require "game.modules.subgames.world.actors.fighters.mixins.abstract"
FighterParent:implement(Movements)
FighterParent:implement(Sprites)
FighterParent:implement(Abstract)
local states = {"idle"}
FighterParent:addStates("game.modules.subgames.world.actors.fighters.states", "idle")
function FighterParent:new(world, x, y, fighterType)
self.abstract = self:getAbstract()
local w, h, d = self:getFighterHitbox()
local z = self:getStartZ()
FighterParent.super.new(self, world, fighterType, x, y, z, w, h, d, false)
self.defaultDir = self.defaultDir or -1
self:initMovements()
self.tweens = TweenManager(self)
end
function FighterParent:update(dt)
self:updateMovements(dt)
FighterParent.super.update(self, dt)
self.tweens:update(dt)
end
function FighterParent:updateEnd(dt)
self:updateSprites()
end
function FighterParent:animationEnded(name)
self:playStateFunc("animationEnded", name)
end
return FighterParent

View file

@ -0,0 +1,88 @@
local PlayerControls = Object:extend()
function PlayerControls:applyInputs()
self:applyMoveInput()
self:applyJumpInput()
self:applyActionsInputs()
self:applySwitchInputs()
end
function PlayerControls:applyMoveInput()
if (self:getStateVar("canMove", false)) then
if (self.world.autorun == true) then
self:applyAutorunInput()
else
self:applyFreemoveInput()
end
end
end
function PlayerControls:applyFreemoveInput()
local angle, strenght = self:dpadToAngle()
if (strenght ~= 0) then
self:goTowardDir(angle, strenght)
end
end
function PlayerControls:applyAutorunInput()
self:goX()
if self.keys["up"].isDown then
self:goY(-1)
end
if self.keys["down"].isDown then
self:goY(1)
end
end
function PlayerControls:dpadToAngle()
local xsp, ysp = 0, 0
local strenght = 0
local angle = 0
if self.keys["up"].isDown then
ysp = -1
end
if self.keys["down"].isDown then
ysp = 1
end
if self.keys["left"].isDown then
xsp = -1
end
if self.keys["right"].isDown then
xsp = 1
end
if (xsp ~= 0 or ysp ~= 0) then
angle = utils.math.pointDirection(0, 0, xsp, ysp)
strenght = 1
end
return angle, strenght
end
function PlayerControls:applyJumpInput()
if self.keys["A"].isPressed and (self:isNotJumping() and self:getStateVar("canJump", false)) then
self:jump()
end
end
function PlayerControls:applyActionsInputs()
if self.keys["B"].isPressed then
--self:setState("hit1")
self:playStateFunc("bAction")
end
end
function PlayerControls:applySwitchInputs()
if (self.onGround and self:getStateVar("canSwitch", false)) then
if self.keys["L1"].isPressed then
self:switchActiveCharacter()
end
if self.keys["R1"].isPressed then
self:switchActiveCharacter(-1)
end
end
end
return PlayerControls

View file

@ -0,0 +1,15 @@
local PlayerHitboxes = Object:extend()
function PlayerHitboxes:getAbstract()
return game.characters.list[game.characters:getActiveCharacter()]
end
function PlayerHitboxes:getFighterHitbox()
return 16, 12, 24
end
function PlayerHitboxes:isAerial()
return false
end
return PlayerHitboxes

View file

@ -0,0 +1,46 @@
local Parent = require("game.modules.subgames.world.actors.fighters.parent")
local Player = Parent:extend()
local Score = require "game.modules.subgames.world.actors.fighters.player.score"
local Sprites = require "game.modules.subgames.world.actors.fighters.player.sprites"
local Controls = require "game.modules.subgames.world.actors.fighters.player.controls"
local Identity = require "game.modules.subgames.world.actors.fighters.player.identity"
local Team = require "scenes.overworld.actors.player.team"
Player:implement(Score)
Player:implement(Sprites)
Player:implement(Team)
Player:implement(Controls)
Player:implement(Identity)
function Player:new(world, x, y, z, id)
self.defaultDir = 1
Player.super.new(self, world, x, y, "player")
self:updateCurrentCharset()
self:initScore()
self:initTeam()
end
function Player:updateStart(dt)
self:applyInputs()
end
function Player:collisionResponse(collision)
if collision.other.type == "collectible" then
collision.other.owner:getPicked(self)
end
end
function Player:timerResponse(response)
if (response == "changeCharacter") then
self:endCharacterSwitchAnimation()
end
end
function Player:getViewCenter()
local x, y = Player.super.getViewCenter(self)
return x, y-16
end
return Player

View file

@ -0,0 +1,22 @@
local PlayerScore = Object:extend()
function PlayerScore:initScore()
self.rings = 0
self.score = 0
end
function PlayerScore:setRing(value, isRelative)
if (isRelative == false) then
self.rings = 0
end
self.rings = self.rings + value
end
function PlayerScore:setScore(value, isRelative)
if (isRelative == false) then
self.score = 0
end
self.score = self.score + value
end
return PlayerScore

View file

@ -0,0 +1,18 @@
local SpritedPlayer = Object:extend()
function SpritedPlayer:getSpritePath(name)
return "datas/gamedata/characters/" .. name .. "/sprites"
end
function SpritedPlayer:getCustomSpeed()
local gsp = utils.math.pointDistance(0, 0, self.xsp, self.ysp)
return math.abs(gsp) / 12
end
function SpritedPlayer:updateCurrentCharset()
self.charName = game.characters:getActiveCharacter()
self:initAbstract()
self:changeSprite(self.charName)
end
return SpritedPlayer

View file

@ -0,0 +1,20 @@
local hit1state = {}
hit1state.canSwitch = false
hit1state.canJump = false
hit1state.defaultAnim = false
hit1state.canMove = false
function hit1state:start()
self.sprite:changeAnimation("hit1", true)
end
function hit1state:bAction()
self:setState("hit2")
end
function hit1state:animationEnded()
self:setState("idle")
end
return hit1state

View file

@ -0,0 +1,20 @@
local hit1state = {}
hit1state.canSwitch = false
hit1state.canJump = false
hit1state.defaultAnim = false
hit1state.canMove = false
function hit1state:start()
self.sprite:changeAnimation("hit2", true)
end
function hit1state:bAction()
self:setState("hit3")
end
function hit1state:animationEnded()
self:setState("idle")
end
return hit1state

View file

@ -0,0 +1,16 @@
local hit1state = {}
hit1state.canSwitch = false
hit1state.canJump = false
hit1state.defaultAnim = false
hit1state.canMove = false
function hit1state:start()
self.sprite:changeAnimation("hit3", true)
end
function hit1state:animationEnded()
self:setState("idle")
end
return hit1state

View file

@ -0,0 +1,14 @@
local idleState = {}
idleState.canSwitch = true
idleState.canJump = true
idleState.defaultAnim = true
idleState.canMove = true
function idleState:bAction()
if (self.onGround) then
self:setState("hit1")
end
end
return idleState

View file

@ -0,0 +1,6 @@
return {
"idle",
"hit1",
"hit2",
"hit3",
}

View file

@ -2,7 +2,7 @@ local Obj = {}
-- On charge toutes les différentes types d'acteurs -- On charge toutes les différentes types d'acteurs
local cwd = (...):gsub('%.init$', '') .. "." local cwd = (...):gsub('%.init$', '') .. "."
Obj.Player = require(cwd .. "player") Obj.Player = require(cwd .. "fighters.player")
Obj.Ring = require(cwd .. "items.ring") Obj.Ring = require(cwd .. "items.ring")
Obj.index = {} Obj.index = {}
@ -19,4 +19,7 @@ Obj.index = {}
Obj.index[01] = Obj.Ring Obj.index[01] = Obj.Ring
Obj.index[02] = Obj.Ring Obj.index[02] = Obj.Ring
Obj.ennemies = {}
Obj.ennemies["basic"] = require "game.modules.subgames.world.actors.fighters.ennemies"
return Obj return Obj

View file

@ -1,127 +0,0 @@
local cwd = (...):gsub('%.player$', '') .. "."
local Parent = require(cwd .. "parent")
local Player = Parent:extend()
function Player:new(world, x, y, z, id)
Player.super.new(self, world, "player", x, y, 0, 16, 12, 24, true)
self:setGravity(480*2)
self:initPlayer()
self.action = "normal"
self.rings = 0
self.score = 0
end
function Player:initPlayer()
self.charName = game.characters:getActiveCharacter()
self.assets:addSprite(self.charName, "datas/gamedata/characters/" .. self.charName .. "/sprites")
self:setSprite(self.charName, true, 8, 10)
end
function Player:updateStart(dt)
self.xfrc, self.yfrc = 480*3, 480*3
self:basicMovements()
if self.keys["A"].isPressed and (self.onGround) then
self.zsp = 280*1.33
end
if self.keys["B"].isPressed and (self.onGround) then
-- Nothing for the moment
end
end
function Player:basicMovements()
if self.keys["up"].isDown then
self.ysp = -160
end
if self.keys["down"].isDown then
self.ysp = 160
end
if (self.world.autorun == true) then
self.xsp = 160
else
if self.keys["left"].isDown then
self.xsp = -160
end
if self.keys["right"].isDown then
self.xsp = 160
end
end
end
function Player:collisionResponse(collision)
if collision.other.type == "collectible" then
collision.other.owner:getPicked(self)
end
end
function Player:animationEnded(name)
end
function Player:updateEnd(dt)
self:setAnimation()
end
function Player:setAnimation()
local gsp = utils.math.pointDistance(0, 0, self.xsp, self.ysp)
self:setCustomSpeed(math.abs(gsp) / 12)
self:setDirection(self.xsp)
if (self.action == "punching") then
--the animation system is already active
else
if (self.onGround) then
if (math.abs(self.xsp) > 0) or (math.abs(self.ysp) > 0) then
self:changeAnimation("walk", false)
else
self:changeAnimation("idle", false)
end
else
if (self.zsp) > 0 then
self:changeAnimation("jump", false)
else
self:changeAnimation("fall", false)
end
end
end
end
function Player:setDirection(direction)
direction = direction or 0
if direction ~= 0 then
direction = utils.math.sign(direction)
self.direction = direction
self.sprite:setScallingX(direction)
end
end
function Player:getViewCenter()
local x, y = Player.super.getViewCenter(self)
return x, y-16
end
function Player:draw()
Player.super.draw(self)
end
function Player:setRing(value, isRelative)
if (isRelative == false) then
self.rings = 0
end
self.rings = self.rings + value
end
function Player:setScore(value, isRelative)
if (isRelative == false) then
self.score = 0
end
self.score = self.score + value
end
return Player

View file

@ -11,6 +11,7 @@ function ParentWorld:new(scene, maptype, mapname)
self.mapname = mapname self.mapname = mapname
self.autorun = false self.autorun = false
self.i = 0
end end
function ParentWorld:createMapController() function ParentWorld:createMapController()
@ -22,6 +23,17 @@ function ParentWorld:loadMapObjects()
self:addInvisibleWalls() self:addInvisibleWalls()
end end
function ParentWorld:spawnEnnemy(name, owner, count)
local EnnemyObj = self.obj.ennemies[name]
if (EnnemyObj == nil) then
EnnemyObj = self.obj.ennemies["basic"]
end
local x = math.random(240, 424)
local y = (120 / count) * (self.i)
self.i = self.i + 1
EnnemyObj(self, 240, y, owner)
end
function ParentWorld:newObjFromIndex(id, x, y, z) function ParentWorld:newObjFromIndex(id, x, y, z)
self.obj.index[id](self, x, y, z) self.obj.index[id](self, x, y, z)
end end

View file

@ -0,0 +1,45 @@
-- scenes/battles :: the Radiance Custom Battle System
--[[
Copyright © 2022 Kazhnuz
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
local PlayStyle = require "game.modules.subgames"
local CBS = PlayStyle:extend()
local World = require "scenes.battles.world"
function CBS:new(battleData)
CBS.super.new(self, {"shoot", "test", "battle"}, "testmissions", {"sonic"})
self.assets:batchImport("assets.battle")
self:playMusic(battleData.music)
self.ennemies:addAll(battleData.ennemies)
end
function CBS:playMusic(music)
self.assets:setMusic("assets/music/" .. music .. ".mp3")
self.assets:playMusic()
end
function CBS:initWorld()
World(self, self.map)
end
return CBS

View file

@ -0,0 +1,16 @@
local ParentWorld = require "game.modules.subgames.world.parent"
local CBSWorld = ParentWorld:extend()
local Map = require "scenes.battles.world.map"
function CBSWorld:new(scene, mapname)
CBSWorld.super.new(self, scene, "battle", mapname)
self.mapname = mapname
end
function CBSWorld:createMapController()
Map(self, self.mapname)
self.cameras:lockY(10)
end
return CBSWorld

View file

@ -0,0 +1,50 @@
local BaseMap = require "birb.modules.world.maps.parent"
local CBSMap = BaseMap:extend()
local TILESIZE = 31
local TESTZONE = "forest"
local zoneDatas = require "datas.gamedata.maps.shoot.zones"
local Background = require "game.modules.drawing.parallaxBackground"
function CBSMap:new(world, type)
CBSMap.super.new(self, world)
self:setPadding(0, 0, 0, 0)
self.parallaxBackground = Background(world.scene, 6, 0, TESTZONE)
self.layout = {}
self.chunklist = {}
end
function CBSMap:loadCollisions()
local w, h = self:getDimensions()
self.world:newCollision("fakefloor", 0, 0, -48, w, h, 48)
self.world:newCollision("invisible", 0, 0, -48, w, h, 48)
end
function CBSMap:addBlock(x, y, w, h, top, bottom)
-- Empty Placeholder function
end
function CBSMap:getDimensions()
return 424, 120
end
function CBSMap:loadPlayers()
self.world:addPlayer(16, 50, 0, 1)
end
function CBSMap:loadActors()
-- Empty Placeholder function
end
function CBSMap:drawParallax(x, y, w, h)
self.parallaxBackground:drawParallax(x, y, w, h)
end
function CBSMap:draw()
end
return CBSMap

View file

@ -7,16 +7,37 @@ local ComplexHPBar = require "game.modules.gui.complexhpbar"
local DIST_STATUSBAR = 106 local DIST_STATUSBAR = 106
local Y = 200 local Y = 200
local STATUSBAR_W = 90 local STATUSBAR_W = 128
local HPBAR_W = STATUSBAR_W - 32
function StatusBar:new(fighter, i) function StatusBar:new(fighter, i, y)
self:initAbstract(fighter) self:initAbstract(fighter)
StatusBar.super.new(self, self.abstract.name .. "StatutBar", (i-0.5)*DIST_STATUSBAR-(STATUSBAR_W/2), Y, STATUSBAR_W, 64) local x = 16
local y = 16
if (i == 0) then
x = (i-0.5)*DIST_STATUSBAR-(STATUSBAR_W/2)
y = Y
end
StatusBar.super.new(self, self.abstract.name .. "StatutBar", x, y, STATUSBAR_W, 64)
self:createParts(self.scene) self:createParts(self.scene)
end end
function StatusBar:update(dt)
StatusBar.super.update(self, dt)
if (self.currentChar ~= nil and self.currentChar ~= game.characters:getActiveCharacter()) then
self:initAbstract()
self:createParts(self.scene)
end
end
function StatusBar:initAbstract(fighter) function StatusBar:initAbstract(fighter)
if (fighter == nil) then
self.currentChar = game.characters:getActiveCharacter()
self.abstract = game.characters:getActiveCharacterData()
else
self.abstract = fighter.abstract self.abstract = fighter.abstract
end
self.hp = self.abstract.hp self.hp = self.abstract.hp
self.pp = self.abstract.pp self.pp = self.abstract.pp
self.stats = self.abstract:getStats() self.stats = self.abstract:getStats()
@ -25,8 +46,8 @@ end
function StatusBar:createParts(scene) function StatusBar:createParts(scene)
self.emblem = Emblem(self.abstract, scene) self.emblem = Emblem(self.abstract, scene)
self.hpbar = ComplexHPBar(58) self.hpbar = ComplexHPBar(HPBAR_W)
self.ppbar = ComplexHPBar(58) self.ppbar = ComplexHPBar(HPBAR_W)
self.hpbar:setColorForeground(248 / 255, 160 / 255, 0, 1) self.hpbar:setColorForeground(248 / 255, 160 / 255, 0, 1)
self.hpbar:setColorBackground(112 / 255, 0, 0) self.hpbar:setColorBackground(112 / 255, 0, 0)
self.ppbar:setColorForeground(0, 248 / 255, 248 / 255, 1) self.ppbar:setColorForeground(0, 248 / 255, 248 / 255, 1)

View file

@ -1,7 +1,7 @@
return { return {
test = require "scenes.subgames.testBattle", test = require "scenes.subgames.testBattle",
test2 = require "scenes.subgames.testShoot", test2 = require "scenes.subgames.testShoot",
cbs = require "scenes.battlesystem", cbs = require "scenes.battles",
menus = require "scenes.menus", menus = require "scenes.menus",
overworld = require "scenes.overworld" overworld = require "scenes.overworld"
} }

View file

@ -158,13 +158,16 @@ function PlayerActions:endFly()
end end
function PlayerActions:actionSwitch() function PlayerActions:actionSwitch()
if self.keys["select"].isPressed and (self.currentAction == "idle") then if self.keys["L1"].isPressed and (self.currentAction == "idle") then
self:switchActiveCharacter() self:switchActiveCharacter()
end end
if self.keys["R1"].isPressed and (self.currentAction == "idle") then
self:switchActiveCharacter(-1)
end
end end
function PlayerActions:actionRun() function PlayerActions:actionRun()
if self.keys["C"].isPressed then if self.keys["X"].isPressed then
if (self:canDoAction("run") and self.speedFactor > 0) then if (self:canDoAction("run") and self.speedFactor > 0) then
self.dashJustStarted = true self.dashJustStarted = true
if (utils.table.contain({"run", "idle"}, self.currentAction)) then if (utils.table.contain({"run", "idle"}, self.currentAction)) then
@ -174,7 +177,7 @@ function PlayerActions:actionRun()
end end
self.xsp, self.ysp = self:getDash() self.xsp, self.ysp = self:getDash()
end end
elseif (not self.keys["C"].isDown) then elseif (not self.keys["X"].isDown) then
if (self.currentAction == "run") then if (self.currentAction == "run") then
self.currentAction = "idle" self.currentAction = "idle"
elseif (self.currentAction == "jumpdash") then elseif (self.currentAction == "jumpdash") then

View file

@ -1,8 +1,13 @@
local Team = Object:extend() local Team = Object:extend()
function Team:initTeam() function Team:initTeam(forceCanGameOver)
self.active = game.characters:getActiveCharacterData() self.active = game.characters:getActiveCharacterData()
self.canChangeActive = true self.canChangeActive = true
if (forceCanKO == true) then
self.canKO = true
else
self.canKO = game.difficulty:get("playerKoChar") == false
end
end end
function Team:updateActiveCharacter() function Team:updateActiveCharacter()
@ -16,7 +21,7 @@ function Team:updateActiveCharacter()
if (everybodyIsKo) then if (everybodyIsKo) then
self.scene:gameover() self.scene:gameover()
else else
if ((self.active.hp == 0) and not game.difficulty:get("playerKoChar")) then if ((self.active.hp == 0) and self.canKO) then
self:switchActiveCharacter() self:switchActiveCharacter()
end end
end end
@ -26,9 +31,9 @@ function Team:getCurrentCharType()
return self.active.data.class return self.active.data.class
end end
function Team:switchActiveCharacter() function Team:switchActiveCharacter(direction)
if (self.canChangeActive) then if (self.canChangeActive and self.scene.gui:getElement("teamEmblems") ~= nil) then
local count = game.characters:setActiveCharacter() local count = game.characters:setActiveCharacter(direction)
self.active = game.characters:getActiveCharacterData() self.active = game.characters:getActiveCharacterData()
self.canChangeActive = false self.canChangeActive = false
self.tweens:newTimer(0.3, "changeCharacter") self.tweens:newTimer(0.3, "changeCharacter")