Compare commits

...

23 commits

Author SHA1 Message Date
Kazhnuz
0710086b25 feat: add ennemies 2022-05-28 11:55:40 +02:00
Kazhnuz
2f8ffc4240 fix: add hit combo to sprites 2022-05-28 11:55:34 +02:00
Kazhnuz
4598b25e05 feat: add hit combo 2022-05-28 11:55:21 +02:00
Kazhnuz
3545e6b898 improvement: replace actions by the state machine 2022-05-27 09:29:39 +02:00
Kazhnuz
75145f1485 feat: add a finite state machine to actors 2022-05-26 13:12:08 +02:00
Kazhnuz
84e48c0320 fix: add fallback for animations 2022-05-26 13:09:47 +02:00
Kazhnuz
7993e6b6fe fix: fix player initialization 2022-05-26 11:22:17 +02:00
Kazhnuz
aa2b14a509 improvement: make fighter non-solid 2022-05-26 11:21:57 +02:00
Kazhnuz
b1bd072f94 fix: fix zsorting crash 2022-05-22 19:43:01 +02:00
Kazhnuz
b4f7cdb44b chore: forgot something again woops 2022-05-20 19:11:48 +02:00
Kazhnuz
5368b94f88 feat: get hitbox and z position from datas 2022-05-20 19:11:23 +02:00
Kazhnuz
4bb1635cce chore: add forgotten file to commit 2022-05-20 18:25:49 +02:00
Kazhnuz
303bee4e37 feat: add support for abstract 2022-05-20 18:25:07 +02:00
Kazhnuz
084d31a13c improvement: mise en commun de fonction de sprite 2022-05-20 14:46:08 +02:00
Kazhnuz
4d22e35288 improvement: add a fighter parent 2022-05-19 12:45:20 +02:00
Kazhnuz
62b382a4d6 chore(fighter): rename folder 2022-05-19 12:34:52 +02:00
Kazhnuz
27bd6da373 improvement(player): separate inputs 2022-05-19 12:34:16 +02:00
Kazhnuz
a35079f1c7 feat: initial new battles scene 2022-05-12 17:07:27 +02:00
Kazhnuz
102fc467eb feat: add statutbar to new cbs 2022-05-12 13:29:38 +02:00
Kazhnuz
cdc5b083ca feat: add character switching to subgames 2022-05-11 23:07:55 +02:00
Kazhnuz
f5bff3e1b9 improvement: adapt overworld to changes 2022-05-11 23:07:19 +02:00
Kazhnuz
6c7e0caf4b improvement: refactor subgame Player 2022-05-11 20:44:14 +02:00
Kazhnuz
1bb9d13e5d feat: add more keys 2022-05-11 20:44:00 +02:00
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
end
self.currentAnimation = name
if (self.sprite.data.animations[name] ~= nil) then
self.currentAnimation = name
else
self.currentAnimation = self.sprite.data.metadata.defaultAnim
end
self.animationData = self.sprite.data.animations[self.currentAnimation]
if (self.animationData == nil) then
error("animation " .. self.currentAnimation .. " not found.")
end
if (restart == true) then
self.frame = self.animationData.startAt
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 PhysicalActor = require("birb.modules.world.actors.mixins.physics")
local StateMachine = require("birb.classes.states")
local Actor2D = Rect:extend()
Actor2D:implement(BaseActor)
Actor2D:implement(SpritedActor)
@ -36,6 +38,8 @@ Actor2D:implement(TimedActor)
Actor2D:implement(InputActor)
Actor2D:implement(PhysicalActor)
Actor2D:implement(StateMachine)
local Hitbox = require "birb.modules.world.actors.utils.hitbox2D"
-- INIT FUNCTIONS
@ -49,6 +53,7 @@ function Actor2D:new(world, type, x, y, w, h, isSolid)
self:initTimers()
self:initSprite()
self:initKeys()
self:initStates()
end
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 Shape3DActor = require("birb.modules.world.actors.mixins.shapes")
local StateMachine = require("birb.classes.states")
local Actor3D = BasicBox:extend()
Actor3D:implement(BaseActor)
Actor3D:implement(SpritedActor)
@ -41,6 +43,8 @@ Actor3D:implement(InputActor)
Actor3D:implement(PhysicalActor)
Actor3D:implement(Shape3DActor)
Actor3D:implement(StateMachine)
-- INIT 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:initKeys()
self:initShape(Boxes, true)
self:initStates()
end
function Actor3D:destroy()

View file

@ -88,6 +88,7 @@ end
function BaseActor:update(dt)
self:updateStart(dt)
self:applyUpdateFunctions(dt)
self:updateState(dt)
self:updateEnd(dt)
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)
end
function Hitbox3D:getCube()
return self.world.bodies:getCube(self)
end
-- COLLISION FUNCTIONS
-- 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 CameraSystem = require(cwd .. "camera")
local comparisons = require(cwd .. "utils.compare")
local PADDING_VALUE = 10/100
function World3D:new(scene, actorlist, mapfile, maptype)
@ -183,87 +185,10 @@ end
-- Functions to draw the world
function World3D:zSortItems(items)
-- zSorting algorithm taken from bump3D example, adapted to gamecore.
local graph = Tsort.new()
local noOverlap = {}
-- TODO : take from a self.shapes:queryRect()
table.sort(items, comparisons.zsort)
-- Iterate through all visible items, and calculate ordering of all pairs
-- of overlapping items.
-- TODO: Each pair is calculated twice currently. Maybe this is slow?
for _, itemA in ipairs(items) do repeat
local x, y, w, h = self.shapes:getRect(itemA)
local otherItemsFilter = function(other) return other ~= itemA end
local overlapping, len = self.shapes:queryRect(x, y, w, h, otherItemsFilter)
if len == 0 then
table.insert(noOverlap, itemA)
break
end
local _, aY, aZ, _, aH, aD = self.bodies:getCube(itemA.mainHitbox)
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
return items
end

View file

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

View file

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

View file

@ -6,11 +6,26 @@ return {
["right"] = "right",
["up"] = "up",
["down"] = "down",
["dleft"] = "k",
["dright"] = "m",
["dup"] = "o",
["ddown"] = "l",
["A"] = "a",
["B"] = "z",
["C"] = "e",
["X"] = "e",
["Y"] = "r",
["C"] = "n",
["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 PauseScreen = require("game.modules.subgames.pause")
local HUD = require("game.modules.subgames.hud")
local TestWorld = require("game.modules.subgames.world.parent")
local EnnemyController = require "game.modules.subgames.ennemies"
function PlayStyle:new(supportedLevels, missionfile)
PlayStyle.super.new(self, false, false)
self.timer = 0
@ -17,9 +20,11 @@ function PlayStyle:new(supportedLevels, missionfile)
self.tweens = TweenManager(self)
PauseScreen()
HUD()
self.haveStarted = false
self.canPause = true
self.ennemies = EnnemyController(self)
end
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
local cwd = (...):gsub('%.init$', '') .. "."
Obj.Player = require(cwd .. "player")
Obj.Player = require(cwd .. "fighters.player")
Obj.Ring = require(cwd .. "items.ring")
Obj.index = {}
@ -19,4 +19,7 @@ Obj.index = {}
Obj.index[01] = Obj.Ring
Obj.index[02] = Obj.Ring
Obj.ennemies = {}
Obj.ennemies["basic"] = require "game.modules.subgames.world.actors.fighters.ennemies"
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.autorun = false
self.i = 0
end
function ParentWorld:createMapController()
@ -22,6 +23,17 @@ function ParentWorld:loadMapObjects()
self:addInvisibleWalls()
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)
self.obj.index[id](self, x, y, z)
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 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)
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)
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)
self.abstract = fighter.abstract
if (fighter == nil) then
self.currentChar = game.characters:getActiveCharacter()
self.abstract = game.characters:getActiveCharacterData()
else
self.abstract = fighter.abstract
end
self.hp = self.abstract.hp
self.pp = self.abstract.pp
self.stats = self.abstract:getStats()
@ -25,8 +46,8 @@ end
function StatusBar:createParts(scene)
self.emblem = Emblem(self.abstract, scene)
self.hpbar = ComplexHPBar(58)
self.ppbar = ComplexHPBar(58)
self.hpbar = ComplexHPBar(HPBAR_W)
self.ppbar = ComplexHPBar(HPBAR_W)
self.hpbar:setColorForeground(248 / 255, 160 / 255, 0, 1)
self.hpbar:setColorBackground(112 / 255, 0, 0)
self.ppbar:setColorForeground(0, 248 / 255, 248 / 255, 1)

View file

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

View file

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

View file

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