Difference between revisions of "Tuto tiny-ecs demo Part 9 Player Shoots Enemies Die"

From GiderosMobile
(Created page with "__TOC__ In this chapter we will make the player1 able to "shoot" and hurt a enemies. This will be done in two parts: first enabling the player1 "shoot" action, then hurting...")
 
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
__TOC__
 
__TOC__
  
In this chapter we will make the player1 able to "shoot" and hurt a enemies.
+
In this chapter we will make the player1 able to "shoot" and "hurt" enemies.
  
 
This will be done in two parts: first enabling the player1 "shoot" action, then hurting the enemies with some fx and make them "die".
 
This will be done in two parts: first enabling the player1 "shoot" action, then hurting the enemies with some fx and make them "die".
  
== Player1 can "Shoot" ==
+
== Player1 can Shoot ==
 
We implement player1 can shoot in the '''SDynamicBodies''' system.
 
We implement player1 can shoot in the '''SDynamicBodies''' system.
  
Line 20: Line 20:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
In the init function we add the list of enemies to the function signature and we make that list available to the other functions.
+
In the '''init''' function we add the list of enemies to the function signature and we make that list available to the other functions.
  
== World addEntity ==
+
Then in the '''process''' function, we check if the player presses the ''action1'' button (the spacebar) and we set a random enemy in the '''nmes''' list to be hurt.
We need to add the enemy1 entity to tiny-ecs world. Let's add a couple of them.
 
 
 
Please go to the "''LevelX.lua''" file and complete the code as follow:
 
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 +
function SDynamicBodies:process(ent, dt) -- tiny function
 +
-- ...
 +
-- actions (player1)
 +
if ent.isplayer1 and ent.isaction1 then
 +
ent.isaction1 = false
 +
if #self.nmes > 0 then -- check nmes list is not empty
 +
self.nmes[math.random(#self.nmes)].isdirty = true
 +
else -- nmes list is empty
 +
print("you killed everybody!")
 +
end
 +
end
 +
-- move
 +
ent.x += ent.body.vx * dt
 +
ent.sprite:setPosition(ent.x, ent.y)
 +
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
When we add an enemy1 entity to tiny-ecs world, we also add it to an '''nmes''' list so we can iterate through them in our game.
+
I set the ''hurt'' behavior as being the flag ''isdirty'' (some of my Box2D leftovers).
  
'''You can run the demo and you should see ten enemies placed randomly on the x axis'''.
+
So every time the player presses the spacebar, a random enemy from the nmes list will get hurt.
  
== Enemy add AI Component ==
+
== Enemies can die ==
Our enemy1 entities don't do anything yet. Let's equip them with an Artificial Intelligence component.
+
In order to hurt an enemy we need to add a new System. The system will decrease an enemy ''health'' which will eventually "die".
  
In the components folder "_C", create a file called "''cAI.lua''" for example, and copy the following code:
+
In the systems folder "_S", create a file called "''sNme1.lua''" for example, and copy the following code:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 +
SNme1 = Core.class()
 +
 +
function SNme1:init(xtiny, xnmes) -- 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.nmes = xnmes
 +
end
 +
 +
function SNme1:filter(ent) -- tiny function
 +
return ent.isnme
 +
end
 +
 +
function SNme1:onAdd(ent) -- tiny function
 +
end
 +
 +
function SNme1:onRemove(ent) -- tiny function
 +
print("SNme1:onRemove")
 +
end
 +
 +
function SNme1:process(ent, dt) -- tiny function
 +
for i = #self.nmes, 1, -1 do -- scan in reverse
 +
if self.nmes[i].isdirty then -- hit
 +
self.nmes[i].health -= 1
 +
self.nmes[i].washurt = 5 -- timer for a flash effect
 +
self.nmes[i].sprite:setColorTransform(2, 0, 0, 3) -- the flash effect (a bright red color)
 +
self.nmes[i].isdirty = false
 +
if self.nmes[i].health <= 0 then -- dead :-(
 +
self.tiny.tworld:removeEntity(self.nmes[i]) -- sprite removed from sprite layer in SDrawable
 +
self.nmes[i] = nil -- remove from table
 +
table.remove(self.nmes, i) -- remove from table
 +
end
 +
end
 +
end
 +
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Here, in the '''init''' function, we store an entity starting position and a delta x and y to set how far it can travel.
+
In this system, when an entity is dirty (hurt), we decrease its health, set a timer for a flashing effect and if it dies, we remove it from tiny-ecs world and the '''nmes''' list.
  
We can now attach this AI component to our enemy1 entity in "''eNme1.lua''":
+
Please note the sprite is removed from the sprite layer in the '''SDrawable''' system:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 +
function SDrawable:onRemove(ent) -- tiny function
 +
ent.spritelayer:removeChild(ent.sprite)
 +
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''You can run the demo and the enemies should move to the right'''.
+
Let's add the flashing effect to the '''SDynamicBodies''' system like so:
 
 
== Enemy AI System ==
 
To make our enemies intelligent we need to create an AI system.
 
 
 
In the systems folder "_S", create a file called "''sAI.lua''" for example, and copy the following code:
 
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 +
function SDynamicBodies:process(ent, dt) -- tiny function
 +
-- hurt fx
 +
if ent.washurt and ent.washurt > 0 then
 +
ent.washurt -= 1
 +
if ent.washurt <= 0 then
 +
ent.sprite:setColorTransform(1, 1, 1, 1)
 +
end
 +
end
 +
-- movement
 +
if ent.isleft and not ent.isright then -- LEFT
 +
ent.body.vx = -ent.body.speed
 +
elseif ent.isright and not ent.isleft then -- RIGHT
 +
ent.body.vx = ent.body.speed
 +
-- ...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This is a simple AI system, which switches an entity direction when it reaches some limits (delta x, delta y).
+
If an entity counter ''washurt'' is greater than 0, we decrease it. When the counter reaches zero we set the entity sprite color back to normal.
  
Finally we need to add this AI system to tiny-ecs world.
+
== Action ==
 +
To see the result of our work, we need to add the '''SNme1''' system to tiny-ecs world.
  
Please go to the "''LevelX.lua''" file and complete the code as follow:
+
In the "''levelX.lua''" file add the '''SNme1''' system:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 +
-- ...
 +
-- add systems to tiny-ecs
 +
self.tiny.tworld:add(
 +
SDrawable.new(self.tiny),
 +
SDynamicBodies.new(self.tiny, nmes), -- add the nmes list here too!
 +
SPlayer1Control.new(self.tiny),
 +
SAI.new(self.tiny),
 +
SNme1.new(self.tiny, nmes)
 +
)
 +
-- ...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''You can run the demo and the enemies should be less dumb ;-)'''
+
'''Remember we changed the ''SDynamicBodies'' init function signature, so you need to add the new parameter to the System here too'''!
 +
 
 +
That's it!
 +
 
 +
'''You can run the demo and press the spacebar. A random enemy should get hit and eventually die, until you kill everyone'''.
  
 
== Next? ==
 
== Next? ==
In the next part, we make the player1 "shoots" and the enemies "die" :-(
+
In the last part, we conclude.
  
  
 
Prev.: [[Tuto tiny-ecs demo Part 8 Enemies]]</br>
 
Prev.: [[Tuto tiny-ecs demo Part 8 Enemies]]</br>
'''Next: xxx'''
+
'''Next: [[Tuto tiny-ecs demo Part 10 Conclusion]]'''
  
  
 
'''[[Tutorial - tiny-ecs demo]]'''
 
'''[[Tutorial - tiny-ecs demo]]'''
 
{{GIDEROS IMPORTANT LINKS}}
 
{{GIDEROS IMPORTANT LINKS}}

Latest revision as of 01:43, 22 December 2023

In this chapter we will make the player1 able to "shoot" and "hurt" enemies.

This will be done in two parts: first enabling the player1 "shoot" action, then hurting the enemies with some fx and make them "die".

Player1 can Shoot

We implement player1 can shoot in the SDynamicBodies system.

Please go to the "sDynamicBodies.lua" file to add some code.

SDynamicBodies = Core.class()

function SDynamicBodies:init(xtiny, xnmes) -- 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.nmes = xnmes -- a list of nmes we can hurt
end
-- ...

In the init function we add the list of enemies to the function signature and we make that list available to the other functions.

Then in the process function, we check if the player presses the action1 button (the spacebar) and we set a random enemy in the nmes list to be hurt.

function SDynamicBodies:process(ent, dt) -- tiny function
	-- ...
	-- actions (player1)
	if ent.isplayer1 and ent.isaction1 then
		ent.isaction1 = false
		if #self.nmes > 0 then -- check nmes list is not empty
			self.nmes[math.random(#self.nmes)].isdirty = true
		else -- nmes list is empty
			print("you killed everybody!")
		end
	end
	-- move
	ent.x += ent.body.vx * dt
	ent.sprite:setPosition(ent.x, ent.y)
end

I set the hurt behavior as being the flag isdirty (some of my Box2D leftovers).

So every time the player presses the spacebar, a random enemy from the nmes list will get hurt.

Enemies can die

In order to hurt an enemy we need to add a new System. The system will decrease an enemy health which will eventually "die".

In the systems folder "_S", create a file called "sNme1.lua" for example, and copy the following code:

SNme1 = Core.class()

function SNme1:init(xtiny, xnmes) -- 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.nmes = xnmes
end

function SNme1:filter(ent) -- tiny function
	return ent.isnme
end

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

function SNme1:onRemove(ent) -- tiny function
	print("SNme1:onRemove")
end

function SNme1:process(ent, dt) -- tiny function
	for i = #self.nmes, 1, -1 do -- scan in reverse
		if self.nmes[i].isdirty then -- hit
			self.nmes[i].health -= 1
			self.nmes[i].washurt = 5 -- timer for a flash effect
			self.nmes[i].sprite:setColorTransform(2, 0, 0, 3) -- the flash effect (a bright red color)
			self.nmes[i].isdirty = false
			if self.nmes[i].health <= 0 then -- dead :-(
				self.tiny.tworld:removeEntity(self.nmes[i]) -- sprite removed from sprite layer in SDrawable
				self.nmes[i] = nil -- remove from table
				table.remove(self.nmes, i) -- remove from table
			end
		end
	end
end

In this system, when an entity is dirty (hurt), we decrease its health, set a timer for a flashing effect and if it dies, we remove it from tiny-ecs world and the nmes list.

Please note the sprite is removed from the sprite layer in the SDrawable system:

function SDrawable:onRemove(ent) -- tiny function
	ent.spritelayer:removeChild(ent.sprite)
end

Let's add the flashing effect to the SDynamicBodies system like so:

function SDynamicBodies:process(ent, dt) -- tiny function
	-- hurt fx
	if ent.washurt and ent.washurt > 0 then
		ent.washurt -= 1
		if ent.washurt <= 0 then
			ent.sprite:setColorTransform(1, 1, 1, 1)
		end
	end
	-- movement
	if ent.isleft and not ent.isright then -- LEFT
		ent.body.vx = -ent.body.speed
	elseif ent.isright and not ent.isleft then -- RIGHT
		ent.body.vx = ent.body.speed
	-- ...

If an entity counter washurt is greater than 0, we decrease it. When the counter reaches zero we set the entity sprite color back to normal.

Action

To see the result of our work, we need to add the SNme1 system to tiny-ecs world.

In the "levelX.lua" file add the SNme1 system:

	-- ...
	-- add systems to tiny-ecs
	self.tiny.tworld:add(
		SDrawable.new(self.tiny),
		SDynamicBodies.new(self.tiny, nmes), -- add the nmes list here too!
		SPlayer1Control.new(self.tiny),
		SAI.new(self.tiny),
		SNme1.new(self.tiny, nmes)
	)
	-- ...

Remember we changed the SDynamicBodies init function signature, so you need to add the new parameter to the System here too!

That's it!

You can run the demo and press the spacebar. A random enemy should get hit and eventually die, until you kill everyone.

Next?

In the last part, we conclude.


Prev.: Tuto tiny-ecs demo Part 8 Enemies
Next: Tuto tiny-ecs demo Part 10 Conclusion


Tutorial - tiny-ecs demo