Difference between revisions of "Tuto tiny-ecs beatemup Part 11 Systems 3"

From GiderosMobile
(wip)
 
(3 intermediate revisions by the same user not shown)
Line 189: Line 189:
 
  '''There are quite a bit of commented code you can delete as this Entity is immediately removed'''
 
  '''There are quite a bit of commented code you can delete as this Entity is immediately removed'''
  
== sSpritesSorting.lua.lua ==
+
== sSpritesSorting.lua ==
"'''sSpritesSorting.lua.lua'''" in the '''"_S"''' folder. The code:
+
"'''sSpritesSorting.lua'''" in the '''"_S"''' folder. The code:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 
SSpritesSorting = Core.class()
 
SSpritesSorting = Core.class()
Line 250: Line 250:
 
It would be difficult to accurately position the hit and hurt boxes, the collision boxes, ... without visual cues.
 
It would be difficult to accurately position the hit and hurt boxes, the collision boxes, ... without visual cues.
  
Debug systems help us with all of the above. Fortunately they are small and quite simple.
+
Debug systems help us with the above. Fortunately they are small and quite simple.
  
 
=== sDebugCollision.lua ===
 
=== sDebugCollision.lua ===
Line 503: Line 503:
  
 
function SDebugHurtBoxNme:onRemove(ent) -- tiny function
 
function SDebugHurtBoxNme:onRemove(ent) -- tiny function
ent.spritelayer:removeChild(ent.debugheadhurtbox)
+
if not ent.isdestructibleobject then -- isdestructibleobject is somehow already removed!
ent.spritelayer:removeChild(ent.debugspinehurtbox)
+
ent.spritelayer:removeChild(ent.debugheadhurtbox)
 +
ent.spritelayer:removeChild(ent.debugspinehurtbox)
 +
end
 
end
 
end
  
 
function SDebugHurtBoxNme:process(ent, dt) -- tiny function
 
function SDebugHurtBoxNme:process(ent, dt) -- tiny function
ent.debugheadhurtbox:setPosition(ent.pos+vector(ent.collbox.w/2+(ent.headhurtbox.x*ent.flip), ent.headhurtbox.y))
+
local function fun()
ent.debugspinehurtbox:setPosition(ent.pos+vector(ent.collbox.w/2+(ent.spinehurtbox.x*ent.flip), ent.spinehurtbox.y))
+
ent.debugheadhurtbox:setPosition(ent.pos+vector(ent.collbox.w/2+(ent.headhurtbox.x*ent.flip), ent.headhurtbox.y))
 +
ent.debugspinehurtbox:setPosition(ent.pos+vector(ent.collbox.w/2+(ent.spinehurtbox.x*ent.flip), ent.spinehurtbox.y))
 +
Core.yield(1)
 +
end
 +
Core.asyncCall(fun)
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This System displays the enemies hurt boxes.
+
This System displays the enemies and breakable objects hurt boxes.
  
 
=== sDebugHurtBoxPlayer.lua ===
 
=== sDebugHurtBoxPlayer.lua ===
Line 592: Line 598:
  
 
== Next? ==
 
== Next? ==
Awesome we have everything in place.
+
'''Congratulations'''! We have finished our game.
 
 
  
Next we add the systems for the breakable objects and the collectibles and we are almost done with the game!
+
Let's add the final scene: '''YOU WIN'''!
  
  
 
Prev.: [[Tuto tiny-ecs beatemup Part 10 Systems 2]]</br>
 
Prev.: [[Tuto tiny-ecs beatemup Part 10 Systems 2]]</br>
'''Next: [[Tuto tiny-ecs beatemup Part 12 XXX]]'''
+
'''Next: [[Tuto tiny-ecs beatemup Part 12 You Win]]'''
  
  
 
'''[[Tutorial - tiny-ecs beatemup]]'''
 
'''[[Tutorial - tiny-ecs beatemup]]'''
 
{{GIDEROS IMPORTANT LINKS}}
 
{{GIDEROS IMPORTANT LINKS}}

Latest revision as of 02:32, 25 November 2024

The Systems 3

A couple more systems to add and we are done. We also add the Debug Systems to help us visualize all the boxes (hitbox, hurtbox, collsion box, ...).

sDestructibleObjects.lua

Please create a file "sDestructibleObjects.lua" in the "_S" folder and the code:

SDestructibleObjects = Core.class()

local random, cos, sin = math.random, math.cos, math.sin
local insert = table.insert

function SDestructibleObjects:init(xtiny, xbworld) -- tiny function
	self.tiny = xtiny -- ref so we can remove entities from tiny system
	self.tiny.processingSystem(self) -- called once on init and every update
	self.bworld = xbworld
	-- sfx
	self.snd = Sound.new("audio/sfx/footstep/Forest02.wav")
	self.channel = self.snd:play(0, false, true)
end

function SDestructibleObjects:filter(ent) -- tiny function
	return ent.isdestructibleobject
end

function SDestructibleObjects:onAdd(ent) -- tiny function
end

function SDestructibleObjects:onRemove(ent) -- tiny function
	-- spawn a random collectible: ECollectible:init(xspritelayer, xpos)
	local function fun()
		local el = ECollectible.new(ent.spritelayer, ent.pos+vector(ent.collbox.w/4, -1*ent.collbox.h))
		self.tiny.tworld:addEntity(el)
		self.bworld:add(el, el.pos.x, el.pos.y, el.collbox.w, el.collbox.h)
		Core.yield(1)
	end
	Core.asyncCall(fun)
	self.bworld:remove(ent) -- remove collision box from cbump world here!
end

function SDestructibleObjects:process(ent, dt) -- tiny function
	local function EffectExplode(s, scale, pos, r, speed, texture)
		local p = Particles.new()
		p:setPosition(pos)
		p:setTexture(texture)
		p:setScale(scale)
		s:addChild(p)
		local parts = {}
		for i = 1, 6 do -- 8
			local a = random()*6.3
			local dx, dy = cos(a), sin(a)
			local sr = random()*r
			local px, py = dx*sr, dy*sr
			local ss = (random()+0.5) * (speed or 1)
			insert(parts,
				{
					x = px, y = py,
					speedX = dx * ss,
					speedY = dy * ss,
					speedAngular = random()*4 - 2,
					decayAlpha = random()*0.04 + 0.95,
					ttl = 32, -- 500
					size = random()*10 + 20,
				}
			)
		end
		p:addParticles(parts)
		Core.yield(1)
		p:removeFromParent()
	end
	-- hurt fx
	if ent.washurt and ent.washurt > 0 then
		ent.washurt -= 1
		if ent.washurt < ent.recovertimer/2 then
			if ent.hitfx then ent.hitfx:setVisible(false) end
		end
		if ent.washurt <= 0 then
			ent.sprite:setColorTransform(1, 1, 1, 1)
		end
	end
	if ent.isdirty then -- hit
		self.channel = self.snd:play()
		if self.channel then self.channel:setVolume(g_sfxvolume*0.01) end
		ent.hitfx:setVisible(true)
		ent.hitfx:setPosition(ent.pos + vector(ent.headhurtbox.x+4, ent.headhurtbox.y))
		ent.spritelayer:addChild(ent.hitfx)
		ent.currhealth -= ent.damage
		ent.washurt = ent.recovertimer -- timer for a flash effect
		ent.sprite:setColorTransform(1, 1, 1, 3) -- a flash effect
		ent.isdirty = false
		if ent.currhealth <= 0 then
			--EffectExplode(s, scale, pos, r, speed, texture)
			Core.asyncCall(EffectExplode, ent.spritelayer, 2,
				ent.pos+vector(ent.collbox.w/2, -ent.h/2), 4, 2,
				Texture.new("gfx/fx/fxBarrel_02_0011.png"))
			ent.spritelayer:removeChild(ent.hitfx)
			self.tiny.tworld:removeEntity(ent) -- sprite is removed in SDrawable
			self.tiny.numberofdestructibleobjects -= 1
		end
	end
end

The System removes a breakable object when destroyed and spawn a collectible in the onRemove function:

  • it runs every frame
  • it affects only entities with an isdestructibleobject id
  • on hurt adds an hit fx
  • on destroyed adds particles
  • onRemove spawns a collectible

sCollectible.lua

"sCollectible.lua" in the "_S" folder. The code:

SCollectible = Core.class()

local random = math.random

function SCollectible:init(xtiny, xbump, xplayer1) -- tiny function
	self.tiny = xtiny -- make a class ref
	self.tiny.processingSystem(self) -- called once on init and every update
	self.bworld = xbump
	self.player1 = xplayer1
	-- sfx
	self.snd = Sound.new("audio/sfx/sfx_coin_double1.wav")
	self.channel = self.snd:play(0, false, true)
end

function SCollectible:filter(ent) -- tiny function
	return ent.iscollectible
end

function SCollectible:onAdd(ent) -- tiny function
end

function SCollectible:onRemove(ent) -- tiny function
	self.bworld:remove(ent) -- remove collision box from cbump world here!
end

function SCollectible:process(ent, dt) -- tiny function
	if ent.isdirty then -- hit
		local function map(v, minSrc, maxSrc, minDst, maxDst, clampValue)
			local newV = (v - minSrc) / (maxSrc - minSrc) * (maxDst - minDst) + minDst
			return not clampValue and newV or clamp(newV, minDst >< maxDst, minDst <> maxDst)
		end
		self.channel = self.snd:play()
		if self.channel then self.channel:setVolume(g_sfxvolume*0.01) end
--		ent.hitfx:setVisible(true)
--		ent.hitfx:setPosition(ent.pos.x+ent.headhurtbox.x, ent.y+ent.headhurtbox.y)
--		ent.spritelayer:addChild(ent.hitfx)
--		ent.currhealth -= ent.damage
--		ent.washurt = ent.recovertimer -- timer for a flash effect
		if random(100) > 50 then
			if self.player1.currjumps < 0 then self.player1.currjumps = 0 end
			self.player1.currjumps += 3
			self.tiny.hudcurrjumps:setText("JUMPS: "..self.player1.currjumps)
		else
			self.player1.currhealth += 1
			-- hud
			local hudhealthwidth = map(self.player1.currhealth, 0, self.player1.totalhealth, 0, 100)
			self.tiny.hudhealth:setWidth(hudhealthwidth)
			if self.player1.currhealth < self.player1.totalhealth/3 then self.tiny.hudhealth:setColor(0xff0000)
			elseif self.player1.currhealth < self.player1.totalhealth/2 then self.tiny.hudhealth:setColor(0xff5500)
			else self.tiny.hudhealth:setColor(0x00ff00)
			end
		end
		ent.sprite:setColorTransform(0, 2, 0, 3) -- the flash effect (a bright color)
		ent.isdirty = false
--[[
		if ent.currhealth <= 0 then
			ent.hitfx:setColorTransform(3, 0, 0, random(1, 3)/10)
			ent.hitfx:setY(ent.hitfx:getY()+ent.h/1.1) -- magik XXX
			ent.hitfx:setRotation(random(360))
			ent.hitfx:setScale(random(5, 10)/10)
			ent.bgfxlayer:addChild(ent.hitfx)
			self.tiny.tworld:removeEntity(ent) -- sprite is removed in SDrawable
--			self.tiny.numberofnmes -= 1
		end
]]
		self.tiny.tworld:removeEntity(ent) -- sprite is removed in SDrawable
	end
end

This System spawns a collectible:

  • runs once on init and every game loop (process)
  • there are two kind of collectibles: health and jump attacks (updated in the HUD)
There are quite a bit of commented code you can delete as this Entity is immediately removed

sSpritesSorting.lua

"sSpritesSorting.lua" in the "_S" folder. The code:

SSpritesSorting = Core.class()

function SSpritesSorting:init(xtiny) -- tiny function
	xtiny.processingSystem(self) -- called once on init and every update
	self.spriteslist = xtiny.spriteslist
end

function SSpritesSorting:filter(ent) -- tiny function
	return ent.sprite
end

function SSpritesSorting:onAdd(ent) -- tiny function
--	print("SSpritesSorting added", ent)
	self.spriteslist[ent] = true
end

function SSpritesSorting:onRemove(ent) -- tiny function
--	print("SSpritesSorting removed", ent)
	self.spriteslist[ent] = nil
end

local p1rangetoofar = myappwidth*0.5 -- save some CPU
function SSpritesSorting:process(ent, dt) -- tiny function
	local function fun()
		for k, _ in pairs(self.spriteslist) do
			if ent.currlives <= 0 or k.currlives <= 0 then -- don't sort if dead
				return
			end
			if k.isplayer1 then -- don't sort out of range actors to save frames
				if -(k.pos.x-ent.pos.x)<>(k.pos.x-ent.pos.x) > p1rangetoofar then
					return
				end
			end
			if not ent.body.isonfloor then
				if ent.positionystart < k.positionystart and -- ent is behind
					ent.spritelayer:getChildIndex(ent.sprite) > k.spritelayer:getChildIndex(k.sprite) then -- sprite is in front
					ent.spritelayer:swapChildren(ent.sprite, k.sprite)
				end
			else
				if ent.pos.y < k.pos.y and -- ent is behind
					ent.spritelayer:getChildIndex(ent.sprite) > k.spritelayer:getChildIndex(k.sprite) then -- sprite is in front
					ent.spritelayer:swapChildren(ent.sprite, k.sprite)
				end
			end
		end
		Core.yield(0.5)
	end
	Core.asyncCall(fun) -- profiler seems to be faster without asyncCall (because of pairs traversing?)
end

Finally this System sorts the actors on the y axis:

  • runs once on init and every game loop (process)
  • there is a distinction between the actor being on floor and jumping

DEBUG SYSTEMS

It would be difficult to accurately position the hit and hurt boxes, the collision boxes, ... without visual cues.

Debug systems help us with the above. Fortunately they are small and quite simple.

sDebugCollision.lua

"sDebugCollision.lua" in the "_S" folder. The code:

SDebugCollision = Core.class()

function SDebugCollision:init(xtiny) -- tiny function
	xtiny.processingSystem(self) -- called once on init and every update
end

function SDebugCollision:filter(ent) -- tiny function
	return ent.collbox
end

function SDebugCollision:onAdd(ent) -- tiny function
	local debugcolor = 0xff00ff
	if ent.isplayer1 then debugcolor = 0x00ffff end
	ent.debug = Pixel.new(debugcolor, 0.25, ent.collbox.w, ent.collbox.h)
	ent.spritelayer:addChild(ent.debug)
end

function SDebugCollision:onRemove(ent) -- tiny function
	ent.spritelayer:removeChild(ent.debug)
end

function SDebugCollision:process(ent, dt) -- tiny function
--	ent.debug:setPosition(ent.x, ent.y)
	ent.debug:setPosition(ent.pos)
end

This System displays the actors collision box.

sDebugHitBoxNme.lua

"sDebugHitBoxNme.lua" in the "_S" folder. The code:

SDebugHitBoxNme = Core.class()

function SDebugHitBoxNme:init(xtiny, xshowbox) -- tiny function
	xtiny.processingSystem(self) -- called once on init and every update
	self.showbox = xshowbox
end

function SDebugHitBoxNme:filter(ent) -- tiny function
	return (ent.headhitboxattack1 or ent.headhitboxattack2 or ent.spinehitboxattack1 or ent.spinehitboxattack2 or
		ent.headhitboxjattack1 or ent.spinehitboxjattack1) and not ent.isplayer1
end

function SDebugHitBoxNme:onAdd(ent) -- tiny function
	-- debugheadhitboxp1
	if ent.headhitboxattack1 then
		ent.debugheadhitboxp1 = Pixel.new(0xaa0000, 0.5, ent.headhitboxattack1.w, ent.headhitboxattack1.h)
		ent.debugheadhitboxp1:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugheadhitboxp1)
		ent.debugheadhitboxp1:setVisible(self.showbox[1]) -- granular debugging
	end
	-- debugheadhitboxp2
	if ent.headhitboxattack2 then
		ent.debugheadhitboxp2 = Pixel.new(0xaa5500, 0.5, ent.headhitboxattack2.w, ent.headhitboxattack2.h)
		ent.debugheadhitboxp2:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugheadhitboxp2)
		ent.debugheadhitboxp2:setVisible(self.showbox[2]) -- granular debugging
	end
	-- debugspinehitboxk1
	if ent.spinehitboxattack1 then
		ent.debugspinehitboxk1 = Pixel.new(0x005500, 0.5, ent.spinehitboxattack1.w, ent.spinehitboxattack1.h)
		ent.debugspinehitboxk1:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugspinehitboxk1)
		ent.debugspinehitboxk1:setVisible(self.showbox[3]) -- granular debugging
	end
	-- debugspinehitboxk2
	if ent.spinehitboxattack2 then
		ent.debugspinehitboxk2 = Pixel.new(0x00aa00, 0.5, ent.spinehitboxattack2.w, ent.spinehitboxattack2.h)
		ent.debugspinehitboxk2:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugspinehitboxk2)
		ent.debugspinehitboxk2:setVisible(self.showbox[4]) -- granular debugging
	end
	-- debugheadhitboxjp1
	if ent.headhitboxjattack1 then
		ent.debugheadhitboxjp1 = Pixel.new(0xaaaa00, 0.5, ent.headhitboxjattack1.w, ent.headhitboxjattack1.h)
		ent.debugheadhitboxjp1:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugheadhitboxjp1)
		ent.debugheadhitboxjp1:setVisible(self.showbox[5]) -- granular debugging
	end
	-- debugspinehitboxjk1
	if ent.spinehitboxjattack1 then
		ent.debugspinehitboxjk1 = Pixel.new(0x00ff00, 0.5, ent.spinehitboxjattack1.w, ent.spinehitboxjattack1.h)
		ent.debugspinehitboxjk1:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugspinehitboxjk1)
		ent.debugspinehitboxjk1:setVisible(self.showbox[6]) -- granular debugging
	end
end

function SDebugHitBoxNme:onRemove(ent) -- tiny function
	if ent.headhitboxattack1 then ent.spritelayer:removeChild(ent.debugheadhitboxp1) end
	if ent.headhitboxattack2 then ent.spritelayer:removeChild(ent.debugheadhitboxp2) end
	if ent.spinehitboxattack1 then ent.spritelayer:removeChild(ent.debugspinehitboxk1) end
	if ent.spinehitboxattack2 then ent.spritelayer:removeChild(ent.debugspinehitboxk2) end
	if ent.headhitboxjattack1 then ent.spritelayer:removeChild(ent.debugheadhitboxjp1) end
	if ent.spinehitboxjattack1 then ent.spritelayer:removeChild(ent.debugspinehitboxjk1) end
end

function SDebugHitBoxNme:process(ent, dt) -- tiny function
	local function fun()
		if ent.headhitboxattack1 then
			ent.debugheadhitboxp1:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.headhitboxattack1.x*ent.flip), ent.headhitboxattack1.y))
		end
		if ent.headhitboxattack2 then
			ent.debugheadhitboxp2:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.headhitboxattack2.x*ent.flip), ent.headhitboxattack2.y))
		end
		if ent.spinehitboxattack1 then
			ent.debugspinehitboxk1:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.spinehitboxattack1.x*ent.flip), ent.spinehitboxattack1.y))
		end
		if ent.spinehitboxattack2 then
			ent.debugspinehitboxk2:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.spinehitboxattack2.x*ent.flip), ent.spinehitboxattack2.y))
		end
		if ent.headhitboxjattack1 then
			ent.debugheadhitboxjp1:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.headhitboxjattack1.x*ent.flip), ent.headhitboxjattack1.y))
		end
		if ent.spinehitboxjattack1 then
			ent.debugspinehitboxjk1:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.spinehitboxjattack1.x*ent.flip), ent.spinehitboxjattack1.y))
		end
		Core.yield(1)
	end
	Core.asyncCall(fun)
end

This System displays the enemies hit boxes when available.

sDebugHitBoxPlayer.lua

"sDebugHitBoxPlayer.lua" in the "_S" folder. The code:

SDebugHitBoxPlayer = Core.class()

function SDebugHitBoxPlayer:init(xtiny, xshowbox) -- tiny function
	xtiny.processingSystem(self) -- called once on init and every update
	self.showbox = xshowbox
end

function SDebugHitBoxPlayer:filter(ent) -- tiny function
	return (ent.headhitboxattack1 or ent.headhitboxattack2 or ent.spinehitboxattack1 or ent.spinehitboxattack2 or
		ent.headhitboxjattack1 or ent.spinehitboxjattack1) and not ent.isnme
end

function SDebugHitBoxPlayer:onAdd(ent) -- tiny function
	-- debugheadhitboxp1
	if ent.headhitboxattack1 then
		ent.debugheadhitboxp1 = Pixel.new(0xaa0000, 0.5, ent.headhitboxattack1.w, ent.headhitboxattack1.h)
		ent.debugheadhitboxp1:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugheadhitboxp1)
		ent.debugheadhitboxp1:setVisible(self.showbox[1]) -- granular debugging
	end
	-- debugheadhitboxp2
	if ent.headhitboxattack2 then
		ent.debugheadhitboxp2 = Pixel.new(0xaa5500, 0.5, ent.headhitboxattack2.w, ent.headhitboxattack2.h)
		ent.debugheadhitboxp2:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugheadhitboxp2)
		ent.debugheadhitboxp2:setVisible(self.showbox[2]) -- granular debugging
	end
	-- debugspinehitboxk1
	if ent.spinehitboxattack1 then
		ent.debugspinehitboxk1 = Pixel.new(0x005500, 0.5, ent.spinehitboxattack1.w, ent.spinehitboxattack1.h)
		ent.debugspinehitboxk1:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugspinehitboxk1)
		ent.debugspinehitboxk1:setVisible(self.showbox[3]) -- granular debugging
	end
	-- debugspinehitboxk2
	if ent.spinehitboxattack2 then
		ent.debugspinehitboxk2 = Pixel.new(0x00aa00, 0.5, ent.spinehitboxattack2.w, ent.spinehitboxattack2.h)
		ent.debugspinehitboxk2:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugspinehitboxk2)
		ent.debugspinehitboxk2:setVisible(self.showbox[4]) -- granular debugging
	end
	-- debugheadhitboxjp1
	if ent.headhitboxjattack1 then
		ent.debugheadhitboxjp1 = Pixel.new(0xaaaa00, 0.5, ent.headhitboxjattack1.w, ent.headhitboxjattack1.h)
		ent.debugheadhitboxjp1:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugheadhitboxjp1)
		ent.debugheadhitboxjp1:setVisible(self.showbox[5]) -- granular debugging
	end
	-- debugspinehitboxjk1
	if ent.spinehitboxjattack1 then
		ent.debugspinehitboxjk1 = Pixel.new(0x00ff00, 0.5, ent.spinehitboxjattack1.w, ent.spinehitboxjattack1.h)
		ent.debugspinehitboxjk1:setAnchorPoint(0.5, 0.5)
		ent.spritelayer:addChild(ent.debugspinehitboxjk1)
		ent.debugspinehitboxjk1:setVisible(self.showbox[6]) -- granular debugging
	end
end

function SDebugHitBoxPlayer:onRemove(ent) -- tiny function
	if ent.headhitboxattack1 then ent.spritelayer:removeChild(ent.debugheadhitboxp1) end
	if ent.headhitboxattack2 then ent.spritelayer:removeChild(ent.debugheadhitboxp2) end
	if ent.spinehitboxattack1 then ent.spritelayer:removeChild(ent.debugspinehitboxk1) end
	if ent.spinehitboxattack2 then ent.spritelayer:removeChild(ent.debugspinehitboxk2) end
	if ent.headhitboxjattack1 then ent.spritelayer:removeChild(ent.debugheadhitboxjp1) end
	if ent.spinehitboxjattack1 then ent.spritelayer:removeChild(ent.debugspinehitboxjk1) end
end

function SDebugHitBoxPlayer:process(ent, dt) -- tiny function
	local function fun()
		if ent.headhitboxattack1 then
			ent.debugheadhitboxp1:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.headhitboxattack1.x*ent.flip), ent.headhitboxattack1.y))
		end
		if ent.headhitboxattack2 then
			ent.debugheadhitboxp2:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.headhitboxattack2.x*ent.flip), ent.headhitboxattack2.y))
		end
		if ent.spinehitboxattack1 then
			ent.debugspinehitboxk1:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.spinehitboxattack1.x*ent.flip), ent.spinehitboxattack1.y))
		end
		if ent.spinehitboxattack2 then
			ent.debugspinehitboxk2:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.spinehitboxattack2.x*ent.flip), ent.spinehitboxattack2.y))
		end
		if ent.headhitboxjattack1 then
			ent.debugheadhitboxjp1:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.headhitboxjattack1.x*ent.flip), ent.headhitboxjattack1.y))
		end
		if ent.spinehitboxjattack1 then
			ent.debugspinehitboxjk1:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.spinehitboxjattack1.x*ent.flip), ent.spinehitboxjattack1.y))
		end
		Core.yield(1)
	end
	Core.asyncCall(fun)
end

This System displays the player hit boxes when available.

sDebugHurtBoxNme.lua

"sDebugHurtBoxNme.lua" in the "_S" folder. The code:

SDebugHurtBoxNme = Core.class()

function SDebugHurtBoxNme:init(xtiny) -- tiny function
	xtiny.processingSystem(self) -- called once on init and every update
end

function SDebugHurtBoxNme:filter(ent) -- tiny function
	return (ent.headhurtbox or ent.spinehurtbox) and not ent.isplayer1
end

function SDebugHurtBoxNme:onAdd(ent) -- tiny function
	-- debugheadhurtbox
	ent.debugheadhurtbox = Pixel.new(0x5500ff, 0.5, ent.headhurtbox.w, ent.headhurtbox.h)
	ent.debugheadhurtbox:setAnchorPoint(0.5, 0.5)
	ent.spritelayer:addChild(ent.debugheadhurtbox)
	-- debugspinehurtbox
	ent.debugspinehurtbox = Pixel.new(0xff00ff, 0.5, ent.spinehurtbox.w, ent.spinehurtbox.h)
	ent.debugspinehurtbox:setAnchorPoint(0.5, 0.5)
	ent.spritelayer:addChild(ent.debugspinehurtbox)
end

function SDebugHurtBoxNme:onRemove(ent) -- tiny function
	if not ent.isdestructibleobject then -- isdestructibleobject is somehow already removed!
		ent.spritelayer:removeChild(ent.debugheadhurtbox)
		ent.spritelayer:removeChild(ent.debugspinehurtbox)
	end
end

function SDebugHurtBoxNme:process(ent, dt) -- tiny function
	local function fun()
		ent.debugheadhurtbox:setPosition(ent.pos+vector(ent.collbox.w/2+(ent.headhurtbox.x*ent.flip), ent.headhurtbox.y))
		ent.debugspinehurtbox:setPosition(ent.pos+vector(ent.collbox.w/2+(ent.spinehurtbox.x*ent.flip), ent.spinehurtbox.y))
		Core.yield(1)
	end
	Core.asyncCall(fun)
end

This System displays the enemies and breakable objects hurt boxes.

sDebugHurtBoxPlayer.lua

"sDebugHurtBoxPlayer.lua" in the "_S" folder. The code:

SDebugHurtBoxPlayer = Core.class()

function SDebugHurtBoxPlayer:init(xtiny) -- tiny function
	xtiny.processingSystem(self) -- called once on init and every update
end

function SDebugHurtBoxPlayer:filter(ent) -- tiny function
	return (ent.headhurtbox or ent.spinehurtbox) and not ent.isnme
end

function SDebugHurtBoxPlayer:onAdd(ent) -- tiny function
	-- debugheadhurtbox
	ent.debugheadhurtbox = Pixel.new(0x5500ff, 0.5, ent.headhurtbox.w, ent.headhurtbox.h)
	ent.debugheadhurtbox:setAnchorPoint(0.5, 0.5)
	ent.spritelayer:addChild(ent.debugheadhurtbox)
	-- debugspinehurtbox
	ent.debugspinehurtbox = Pixel.new(0xff00ff, 0.5, ent.spinehurtbox.w, ent.spinehurtbox.h)
	ent.debugspinehurtbox:setAnchorPoint(0.5, 0.5)
	ent.spritelayer:addChild(ent.debugspinehurtbox)
end

function SDebugHurtBoxPlayer:onRemove(ent) -- tiny function
	ent.spritelayer:removeChild(ent.debugheadhurtbox)
	ent.spritelayer:removeChild(ent.debugspinehurtbox)
end

function SDebugHurtBoxPlayer:process(ent, dt) -- tiny function
	ent.debugheadhurtbox:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.headhurtbox.x*ent.flip), ent.headhurtbox.y))
	ent.debugspinehurtbox:setPosition(ent.pos + vector(ent.collbox.w/2+(ent.spinehurtbox.x*ent.flip), ent.spinehurtbox.y))
end

This System displays the player hurt boxes.

sDebugSpriteSorting.lua

"sDebugSpriteSorting.lua" in the "_S" folder. The code:

SDebugSpriteSorting = Core.class()

function SDebugSpriteSorting:init(xtiny) -- tiny function
	xtiny.processingSystem(self) -- called once on init and every update
end

function SDebugSpriteSorting:filter(ent) -- tiny function
	return ent.sprite
end

function SDebugSpriteSorting:onAdd(ent) -- tiny function
	-- debugposition
	ent.debugposition = Pixel.new(0xaa5500, 1, 16, 16)
	ent.debugposition:setAnchorPoint(0.5, 0.5)
	if ent.isplayer1 then ent.debugposition:setColor(0xaa5500, 1) end
	ent.spritelayer:addChild(ent.debugposition)
	-- debugstartyposition
	ent.debugstartyposition = Pixel.new(0xaa557f, 1, 16, 16)
	ent.debugstartyposition:setAnchorPoint(0.5, 0.5)
	if ent.isplayer1 then ent.debugstartyposition:setColor(0xaa557f, 1) end
	ent.spritelayer:addChild(ent.debugstartyposition)
end

function SDebugSpriteSorting:onRemove(ent) -- tiny function
	ent.spritelayer:removeChild(ent.debugposition)
	ent.spritelayer:removeChild(ent.debugstartyposition)
end

function SDebugSpriteSorting:process(ent, dt) -- tiny function
	ent.debugposition:setPosition(ent.pos)
	ent.debugstartyposition:setPosition(ent.pos.x, ent.positionystart)
end

This System displays the actors y position.

Next?

Congratulations! We have finished our game.

Let's add the final scene: YOU WIN!


Prev.: Tuto tiny-ecs beatemup Part 10 Systems 2
Next: Tuto tiny-ecs beatemup Part 12 You Win


Tutorial - tiny-ecs beatemup