Tuto tiny-ecs beatemup Part 11 Systems 3

From GiderosMobile
Revision as of 02:46, 24 November 2024 by MoKaLux (talk | contribs) (wip)

The Systems 3

A couple more systems to add and we are done. Those systems apply on the breakable objects and the collectibles.

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)

sSpritesSorting.lua.lua

"sSpritesSorting.lua.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

XXX.lua

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

This System uses the Bump plugin to check for collisions between the actors collision boxes:

  • runs once on init and every game loop (process)
  • in init we pass the Bump world the actors live in
  • we define Bump collision filter
  • we check if player1 collides with a collectible actor and tag the collectible as dirty
  • finally we set the actor position and flip its bitmap in the direction it is going
  • I experimented with asyncCall to test if we could gain some frames per second ;-)

Next?

Next we add the systems for the breakable objects and the collectibles and we are almost done with the game!


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


Tutorial - tiny-ecs beatemup