Difference between revisions of "Tuto tiny-ecs demo Part 8 Enemies"

From GiderosMobile
(Created page with "__TOC__ We continue with our tiny-ecs demo. It is time to add some "enemies". == Entity enemy1 == First we create an entity of type enemy1. In the entites folder "_E", crea...")
 
 
(3 intermediate revisions by the same user not shown)
Line 28: Line 28:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
We start by adding some ids, a sprite layer and a sprite to see our enemy1. The sprite here is a Pixel with a random color.
+
We start by adding some ids, a sprite layer and a sprite. The sprite here is a Pixel with a random color.
  
 
We add some more parameters like position and health.
 
We add some more parameters like position and health.
  
 
Finally we add the body component so the entity can move.
 
Finally we add the body component so the entity can move.
 +
 +
'''Please note in the init parameters, there are two unused yet variables: dx and dy. They will be used when we add an artificial intelligence (AI) component later'''.
  
 
'''With ECS it is easy to build your game, you add/remove parameters and components as you need'''.
 
'''With ECS it is easy to build your game, you add/remove parameters and components as you need'''.
  
 
== World addEntity ==
 
== World addEntity ==
We add a couple of enemy1 entities to tiny-ecs world.
+
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:
 
Please go to the "''LevelX.lua''" file and complete the code as follow:
Line 44: Line 46:
 
-- tiny-ecs
 
-- tiny-ecs
 
self.tiny = require "classes/tiny-ecs"
 
self.tiny = require "classes/tiny-ecs"
self.tiny.world = self.tiny.world()
+
self.tiny.tworld = self.tiny.world()
 
-- some enemies (xspritelayer, x, y, dx, dy)
 
-- some enemies (xspritelayer, x, y, dx, dy)
 
local nmes = {}
 
local nmes = {}
 
for i = 1, 10 do -- we create 10 enemies
 
for i = 1, 10 do -- we create 10 enemies
 
nmes[i] = ENme1.new(self.camera, math.random(24)*16, 10*16, math.random(12)*16, 0)
 
nmes[i] = ENme1.new(self.camera, math.random(24)*16, 10*16, math.random(12)*16, 0)
self.tiny.world:addEntity(nmes[i])
+
self.tiny.tworld:addEntity(nmes[i])
 
end
 
end
 
-- the player (xspritelayer, x, y)
 
-- the player (xspritelayer, x, y)
 
self.player1 = EPlayer1.new(self.camera, 12*16, 10*16)
 
self.player1 = EPlayer1.new(self.camera, 12*16, 10*16)
self.tiny.world:addEntity(self.player1)
+
self.tiny.tworld:addEntity(self.player1)
 
...
 
...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''You can run the demo and you should be able to see ten enemies placed randomly on the x axis'''.
+
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.
  
== And a System to move our actors ==
+
'''You can run the demo and you should see ten enemies placed randomly on the x axis'''.
Now we add another system which will be responsible for moving the actors (entities).
 
  
In the same systems folder "_S", create a file called ''sDynamicBodies.lua'' for example, and copy the following code:
+
== Enemy add AI Component ==
 +
Our enemy1 entities don't do anything yet. Let's equip them with an Artificial Intelligence component.
 +
 
 +
In the components folder "_C", create a file called "''cAI.lua''" for example, and copy the following code:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
SDynamicBodies = Core.class()
+
CAI = Core.class()
  
function SDynamicBodies:init(xtiny) -- tiny function
+
function CAI:init(x, y, dx, dy)
self.tiny = xtiny -- ref so we can remove entities from tiny system
+
self.startpositionx = x
self.tiny.processingSystem(self) -- called once on init and every update
+
self.startpositiony = y
 +
self.dx = dx -- delta x
 +
self.dy = dy -- delta y
 
end
 
end
 +
</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.
 +
 +
We can now attach this AI component to our enemy1 entity in "''eNme1.lua''":
 +
<syntaxhighlight lang="lua">
 +
ENme1 = Core.class()
  
function SDynamicBodies:filter(ent) -- tiny function
+
function ENme1:init(xspritelayer, x, y, dx, dy)
return ent.isactor and ent.body -- only actors with body component
+
-- ...
 +
self.health = 10
 +
-- BODY COMPONENT: function CBody:init(xspeed, xjumpspeed)
 +
self.body = CBody.new(4*16, 6*16) -- xspeed, xjumpspeed
 +
self.body.defaultmass = 1
 +
self.body.currmass = self.body.defaultmass
 +
-- AI COMPONENT: function CAI:init(x, y, dx, dy)
 +
self.ai = CAI.new(self.x, self.y, dx, dy)
 +
if self.ai.dx then self.isright = true end -- start moving our enemy1
 +
if self.ai.dy then self.isdown = true end -- start moving our enemy1
 
end
 
end
 +
</syntaxhighlight>
 +
 +
'''You can run the demo and the enemies should move to the right'''.
 +
 +
== 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">
 +
SAI = Core.class()
  
function SDynamicBodies:onAdd(ent) -- tiny function
+
function SAI:init(xtiny) -- tiny function
 +
xtiny.processingSystem(self) -- called once on init and every update
 
end
 
end
  
function SDynamicBodies:onRemove(ent) -- tiny function
+
function SAI:filter(ent) -- tiny function
 +
return ent.ai
 
end
 
end
  
function SDynamicBodies:process(ent, dt) -- tiny function
+
function SAI:onAdd(ent) -- tiny function
-- velocity
+
end
if ent.isleft and not ent.isright then -- LEFT
+
 
ent.body.vx = -ent.body.speed
+
function SAI:onRemove(ent) -- tiny function
elseif ent.isright and not ent.isleft then -- RIGHT
+
end
ent.body.vx = ent.body.speed
+
 
else
+
function SAI:process(ent, dt) -- tiny function
ent.body.vx = 0
+
if ent.ai.dx and ent.ai.dy then -- DIAGONAL
 +
if ent.x >= ent.ai.startpositionx + ent.ai.dx then
 +
ent.isleft, ent.isright = true, false
 +
ent.isup, ent.isdown = true, false
 +
elseif ent.x <= ent.ai.startpositionx then
 +
ent.isleft, ent.isright = false, true
 +
ent.isup, ent.isdown = false, true
 +
end
 +
elseif ent.ai.dx then -- HORIZONTAL
 +
if ent.x >= ent.ai.startpositionx + ent.ai.dx then
 +
ent.isleft, ent.isright = true, false
 +
elseif ent.x <= ent.ai.startpositionx then
 +
ent.isleft, ent.isright = false, true
 +
end
 +
elseif ent.ai.dy then -- VERTICAL
 +
if ent.y >= ent.ai.startpositiony + ent.ai.dy then
 +
ent.isup, ent.isdown = true, false
 +
elseif ent.y <= ent.ai.startpositiony then
 +
ent.isup, ent.isdown = false, true
 +
end
 
end
 
end
-- move
 
ent.x += ent.body.vx * dt
 
ent.sprite:setPosition(ent.x, ent.y)
 
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
All systems follow the same pattern, they are easy to create!
+
This is a simple AI system, which switches an entity direction when it reaches some limits (delta x, delta y).
  
Here, in the '''init''' function, we create a reference to the ''xtiny'' parameter, so we can use it later to add or remove actors from tiny-ecs world.
+
Finally we need to add this AI system to tiny-ecs world.
  
Then, we tell tiny-ecs that this system needs to be '''updated''' each game loop (cf: [[Tuto_tiny-ecs_demo_Part_3_tiny-ecs_World]], '''self.tiny.world:update(dt)''').
+
Please go to the "''LevelX.lua''" file and complete the code as follow:
 
+
<syntaxhighlight lang="lua">
In the '''filter''' function, we tell tiny-ecs that this system applies to entities with an '''id''' of ''isactor'' and ''body'' ('''remember that a component can serve as an id''').
+
...
 +
-- the player (xspritelayer, x, y)
 +
self.player1 = EPlayer1.new(self.camera, 12*16, 10*16)
 +
self.tiny.tworld:addEntity(self.player1)
 +
-- add systems to tiny-ecs
 +
self.tiny.tworld:add(
 +
SDrawable.new(self.tiny),
 +
SDynamicBodies.new(self.tiny),
 +
SPlayer1Control.new(self.tiny),
 +
SAI.new(self.tiny)
 +
)
 +
...
 +
</syntaxhighlight>
  
Finally, in the '''process''' function, we check if an actor is going left or right to add velocity to its body. The velocity will change the actor position.
+
'''You can run the demo and the enemies should be less dumb ;-)'''
  
 
== Next? ==
 
== Next? ==
In the next part, we ...
+
In the next part, we make the player1 "shoots" and the enemies "die" :-(
  
  
 
Prev.: [[Tuto tiny-ecs demo Part 7 Systems to move actors]]</br>
 
Prev.: [[Tuto tiny-ecs demo Part 7 Systems to move actors]]</br>
'''Next: xxx'''
+
'''Next: [[Tuto tiny-ecs demo Part 9 Player Shoots Enemies Die]]'''
  
  
 
'''[[Tutorial - tiny-ecs demo]]'''
 
'''[[Tutorial - tiny-ecs demo]]'''
 
{{GIDEROS IMPORTANT LINKS}}
 
{{GIDEROS IMPORTANT LINKS}}

Latest revision as of 07:47, 21 December 2023

We continue with our tiny-ecs demo. It is time to add some "enemies".

Entity enemy1

First we create an entity of type enemy1.

In the entites folder "_E", create a file called "eNme1.lua" for example and copy the following code:

ENme1 = Core.class()

function ENme1:init(xspritelayer, x, y, dx, dy)
	-- ids
	self.isnme = true
	self.isactor = true
	-- sprite
	self.spritelayer = xspritelayer
	self.sprite = Pixel.new(math.random(0xffffff), 1, 32, 64)
	-- params
	self.x = x
	self.y = y
	self.health = 10
	-- BODY COMPONENT: function CBody:init(xspeed, xjumpspeed)
	self.body = CBody.new(4*16, 6*16) -- xspeed, xjumpspeed
	self.body.defaultmass = 1
	self.body.currmass = self.body.defaultmass
end

We start by adding some ids, a sprite layer and a sprite. The sprite here is a Pixel with a random color.

We add some more parameters like position and health.

Finally we add the body component so the entity can move.

Please note in the init parameters, there are two unused yet variables: dx and dy. They will be used when we add an artificial intelligence (AI) component later.

With ECS it is easy to build your game, you add/remove parameters and components as you need.

World addEntity

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:

	...
	-- tiny-ecs
	self.tiny = require "classes/tiny-ecs"
	self.tiny.tworld = self.tiny.world()
	-- some enemies (xspritelayer, x, y, dx, dy)
	local nmes = {}
	for i = 1, 10 do -- we create 10 enemies
		nmes[i] = ENme1.new(self.camera, math.random(24)*16, 10*16, math.random(12)*16, 0)
		self.tiny.tworld:addEntity(nmes[i])
	end
	-- the player (xspritelayer, x, y)
	self.player1 = EPlayer1.new(self.camera, 12*16, 10*16)
	self.tiny.tworld:addEntity(self.player1)
	...

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.

You can run the demo and you should see ten enemies placed randomly on the x axis.

Enemy add AI Component

Our enemy1 entities don't do anything yet. Let's equip them with an Artificial Intelligence component.

In the components folder "_C", create a file called "cAI.lua" for example, and copy the following code:

CAI = Core.class()

function CAI:init(x, y, dx, dy)
	self.startpositionx = x
	self.startpositiony = y
	self.dx = dx -- delta x
	self.dy = dy -- delta y
end

Here, in the init function, we store an entity starting position and a delta x and y to set how far it can travel.

We can now attach this AI component to our enemy1 entity in "eNme1.lua":

ENme1 = Core.class()

function ENme1:init(xspritelayer, x, y, dx, dy)
	-- ...
	self.health = 10
	-- BODY COMPONENT: function CBody:init(xspeed, xjumpspeed)
	self.body = CBody.new(4*16, 6*16) -- xspeed, xjumpspeed
	self.body.defaultmass = 1
	self.body.currmass = self.body.defaultmass
	-- AI COMPONENT: function CAI:init(x, y, dx, dy)
	self.ai = CAI.new(self.x, self.y, dx, dy)
	if self.ai.dx then self.isright = true end -- start moving our enemy1
	if self.ai.dy then self.isdown = true end -- start moving our enemy1
end

You can run the demo and the enemies should move to the right.

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:

SAI = Core.class()

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

function SAI:filter(ent) -- tiny function
	return ent.ai
end

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

function SAI:onRemove(ent) -- tiny function
end

function SAI:process(ent, dt) -- tiny function
	if ent.ai.dx and ent.ai.dy then -- DIAGONAL
		if ent.x >= ent.ai.startpositionx + ent.ai.dx then
			ent.isleft, ent.isright = true, false
			ent.isup, ent.isdown = true, false
		elseif ent.x <= ent.ai.startpositionx then
			ent.isleft, ent.isright = false, true
			ent.isup, ent.isdown = false, true
		end
	elseif ent.ai.dx then -- HORIZONTAL
		if ent.x >= ent.ai.startpositionx + ent.ai.dx then
			ent.isleft, ent.isright = true, false
		elseif ent.x <= ent.ai.startpositionx then
			ent.isleft, ent.isright = false, true
		end
	elseif ent.ai.dy then -- VERTICAL
		if ent.y >= ent.ai.startpositiony + ent.ai.dy then
			ent.isup, ent.isdown = true, false
		elseif ent.y <= ent.ai.startpositiony then
			ent.isup, ent.isdown = false, true
		end
	end
end

This is a simple AI system, which switches an entity direction when it reaches some limits (delta x, delta y).

Finally we need to add this AI system to tiny-ecs world.

Please go to the "LevelX.lua" file and complete the code as follow:

	...
	-- the player (xspritelayer, x, y)
	self.player1 = EPlayer1.new(self.camera, 12*16, 10*16)
	self.tiny.tworld:addEntity(self.player1)
	-- add systems to tiny-ecs
	self.tiny.tworld:add(
		SDrawable.new(self.tiny),
		SDynamicBodies.new(self.tiny),
		SPlayer1Control.new(self.tiny),
		SAI.new(self.tiny)
	)
	...

You can run the demo and the enemies should be less dumb ;-)

Next?

In the next part, we make the player1 "shoots" and the enemies "die" :-(


Prev.: Tuto tiny-ecs demo Part 7 Systems to move actors
Next: Tuto tiny-ecs demo Part 9 Player Shoots Enemies Die


Tutorial - tiny-ecs demo