Difference between revisions of "Tuto tiny-ecs demo Part 10 Conclusion"

From GiderosMobile
(Created page with "__TOC__ 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...")
 
 
(3 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" enemies.
+
So this is the last chapter.
  
This will be done in two parts: first enabling the player1 "shoot" action, then hurting the enemies with some fx and make them "die".
+
== Adding Buildings ==
 +
Let's finish the '''tiny-ecs demo''' by adding some buildings to our level1.
  
== Player1 can Shoot ==
+
In the entities folder "_E", let's add a file called "''eBuilding.lua''" for example.
We implement player1 can shoot in the '''SDynamicBodies''' system.
 
  
Please go to the "''sDynamicBodies.lua''" file to add some code.
+
This is the code for an '''EBuilding''' entity:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
SDynamicBodies = Core.class()
+
EBuilding = Core.class()
  
function SDynamicBodies:init(xtiny, xnmes) -- tiny function
+
function EBuilding:init(xspritelayer, x, y, w, h)
self.tiny = xtiny -- ref so we can remove entities from tiny system
+
-- sprite
self.tiny.processingSystem(self) -- called once on init and every update
+
self.spritelayer = xspritelayer
self.nmes = xnmes -- a list of nmes we can hurt
+
self.sprite = Pixel.new(math.random(0xffffff), 1, w, h)
 +
self.sprite:setAnchorPoint(0.5, 1)
 +
-- params
 +
self.x = x
 +
self.y = y
 
end
 
end
-- ...
 
 
</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.
+
The only thing here is to change the anchor point of the '''EBuilding''' entity.
  
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.
+
Now in the "''LevelX.lua''" file we add some buildings to tiny-ecs world:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
function SDynamicBodies:process(ent, dt) -- tiny function
 
 
-- ...
 
-- ...
-- actions (player1)
+
-- tiny-ecs
if ent.isplayer1 and ent.isaction1 then
+
if self.tiny == nil then
ent.isaction1 = false
+
self.tiny = require "classes/tiny-ecs"
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
 
end
-- move
+
self.tiny.tworld = self.tiny.world()
ent.x += ent.body.vx * dt
+
-- some deco (xspritelayer, x, y, w, h)
ent.sprite:setPosition(ent.x, ent.y)
+
for i = 1, 8 do -- 8 random buildings
end
+
self.tiny.tworld:addEntity(
 +
EBuilding.new(self.camera,
 +
math.random(myappwidth), 14*16,
 +
math.random(4*16, myappwidth/4), math.random(8, 12)*16
 +
)
 +
)
 +
end
 +
-- some enemies (xspritelayer, x, y, dx, dy)
 +
local nmes = {}
 +
for i = 1, 10 do -- we create 10 enemies
 +
-- ...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
I set the ''hurt'' behavior as being the flag ''isdirty'' (some of my Box2D leftovers).
+
We add 8 randomly positionned and sized EBuilding entities.
 
 
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:
 
<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>
 
  
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.
+
'''I hope you like the demo'''!
  
Please note the sprite is removed from the sprite layer in the '''SDrawable''' system:
+
== Gideros Project ==
<syntaxhighlight lang="lua">
+
In the project I added an '''SDebugDraw''' system.
function SDrawable:onRemove(ent) -- tiny function
 
ent.spritelayer:removeChild(ent.sprite)
 
end
 
</syntaxhighlight>
 
  
Let's add the flashing effect to the '''SDynamicBodies''' system like so:
+
'''[[Media:tiny-ecs_demo.zip]]''' '''(tip: right click and save link as)'''
<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>
 
  
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.
+
== Conclusion ==
 +
This was my take on using '''tiny-ecs'''. To sum up:
 +
* tiny-ecs has a world
 +
* a world is made of entities and systems
 +
* entities have ids
 +
* entities can have components
 +
* components can serve as ids
 +
* a system filters the entities to act upon based on entities ids
 +
* a system can run once or every update
  
== Action ==
+
'''I really enjoy making games using the ECS paradigm. I hope to have given you the keys to experiment with it'''!
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:
 
<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>
 
  
'''Remember we changed the ''SDynamicBodies'' init function signature, so you need to add the new parameter to the System here too'''!
+
'''Thanks for reading'''!
  
That's it!
+
== Further reading ==
 +
One last link if you want to know more about ECS:
  
'''You can run the demo and press the spacebar. A random enemy should get hit and eventually die, until you kill everyone'''.
+
'''[https://github.com/SanderMertens/ecs-faq#what-is-ecs github SanderMertens what is ecs]'''
  
  

Latest revision as of 15:29, 22 December 2023

So this is the last chapter.

Adding Buildings

Let's finish the tiny-ecs demo by adding some buildings to our level1.

In the entities folder "_E", let's add a file called "eBuilding.lua" for example.

This is the code for an EBuilding entity:

EBuilding = Core.class()

function EBuilding:init(xspritelayer, x, y, w, h)
	-- sprite
	self.spritelayer = xspritelayer
	self.sprite = Pixel.new(math.random(0xffffff), 1, w, h)
	self.sprite:setAnchorPoint(0.5, 1)
	-- params
	self.x = x
	self.y = y
end

The only thing here is to change the anchor point of the EBuilding entity.

Now in the "LevelX.lua" file we add some buildings to tiny-ecs world:

	-- ...
	-- tiny-ecs
	if self.tiny == nil then
		self.tiny = require "classes/tiny-ecs"
	end
	self.tiny.tworld = self.tiny.world()
	-- some deco (xspritelayer, x, y, w, h)
	for i = 1, 8 do -- 8 random buildings
		self.tiny.tworld:addEntity(
			EBuilding.new(self.camera,
				math.random(myappwidth), 14*16,
				math.random(4*16, myappwidth/4), math.random(8, 12)*16
			)
		)
	end
	-- some enemies (xspritelayer, x, y, dx, dy)
	local nmes = {}
	for i = 1, 10 do -- we create 10 enemies
	-- ...

We add 8 randomly positionned and sized EBuilding entities.

I hope you like the demo!

Gideros Project

In the project I added an SDebugDraw system.

Media:tiny-ecs_demo.zip (tip: right click and save link as)

Conclusion

This was my take on using tiny-ecs. To sum up:

  • tiny-ecs has a world
  • a world is made of entities and systems
  • entities have ids
  • entities can have components
  • components can serve as ids
  • a system filters the entities to act upon based on entities ids
  • a system can run once or every update

I really enjoy making games using the ECS paradigm. I hope to have given you the keys to experiment with it!


Thanks for reading!

Further reading

One last link if you want to know more about ECS:

github SanderMertens what is ecs


Prev.: Tuto tiny-ecs demo Part 9 Player Shoots Enemies Die
END


Tutorial - tiny-ecs demo