Difference between revisions of "Tuto tiny-ecs 2d platformer Part 6 ECS Components"

From GiderosMobile
(Created page with "__TOC__ == Components == As we have seen in the previous chapter, components are abilities we add to an Entity. Entities can and will share the same components. Let's contin...")
 
Line 11: Line 11:
 
CBody = Core.class()
 
CBody = Core.class()
  
function CBody:init(xspeed, xjumpspeed)
+
function CBody:init(xmass, xspeed, xupspeed, xextra)
 
-- body physics properties
 
-- body physics properties
 +
self.mass = xmass or 1
 +
self.currmass = self.mass
 
self.vx = 0
 
self.vx = 0
 
self.vy = 0
 
self.vy = 0
 
self.speed = xspeed
 
self.speed = xspeed
 
self.currspeed = self.speed
 
self.currspeed = self.speed
self.jumpspeed = xjumpspeed
+
self.upspeed = xupspeed
self.currjumpspeed = self.jumpspeed
+
self.currupspeed = self.upspeed
self.isonfloor = true
+
if xextra then
self.isgoingup = false
+
self.inputbuffer = 1*8 -- 1*8, 2*8
 +
self.currinputbuffer = self.inputbuffer
 +
self.coyotetimer = 1.65*8 -- 1.5*8, 2*8, 12
 +
self.currcoyotetimer = self.coyotetimer
 +
self.jumpcount = 1 -- 2
 +
self.currjumpcount = self.jumpcount
 +
self.candash = true -- true, false XXX
 +
self.dashtimer = 1*8 -- 1*8 -- 0.5*8
 +
self.currdashtimer = self.dashtimer
 +
self.dashmultiplier = 1.5 -- 1.5
 +
self.dashcooldown = 4*8 -- 4*8, cooldown before performing another dash
 +
self.currdashcooldown = self.dashcooldown
 +
end
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The ''CBody:init'' function signature has only two parameters: the speed on the x axis and the jumpspeed.
+
The ''CBody:init'' function signature has four parameters: the body ''mass'', the ''speed'' on the x axis, the ''upspeed'' on the y axis and the ''extra'' body variables.
  
We store other variables to keep track of an Entity current state.
+
'''note''': some entities will have a body but without the extra parameters, for example a moving platform
  
 
  '''Components are usually small pieces of code, which is nice!'''
 
  '''Components are usually small pieces of code, which is nice!'''
Line 43: Line 57:
 
That's all we need to tell a System this Entity has a collision box. We store the Entity collision box width and height to be used by systems.
 
That's all we need to tell a System this Entity has a collision box. We store the Entity collision box width and height to be used by systems.
  
=== HURT BOX ===
+
== Shield ==
Hurt boxes are not components per se, but they use the collision box size in their parameters. I use two hurt boxes for flexibility: a head hurt box and a spine hurt box.
+
This is not an ECS component per se but I added some shield to the player1. I think I should have created a component for it but that will do for now.
  
Hurt boxes are rectangular areas the Entity will receive damage to when overlapping another Entity hit box. Hurt boxes are simply tables holding some variables:
+
When you press the shield action key, the shield is activated.
* is it active or is the Entity in recovery mode
 
* its x and y position
 
* its size
 
 
 
== ANIMATION ==
 
In the previous chapter we already added the Animation Component and created the basic animations: idle, walk, jump, ... . This time we add the attacks animations ("'''ePlayer1.lua'''"):
 
<syntaxhighlight lang="lua">
 
-- self.animation:createAnim(g_ANIM_PUNCH_ATTACK1_R, 50, 51) -- 28, 31, no or low anticipation / quick hit / no or low overhead is best
 
self.animation.anims[g_ANIM_PUNCH_ATTACK1_R] = {}
 
self.animation.anims[g_ANIM_PUNCH_ATTACK1_R][1] = self.animation.myanimsimgs[49]
 
self.animation.anims[g_ANIM_PUNCH_ATTACK1_R][2] = self.animation.myanimsimgs[52]
 
self.animation.anims[g_ANIM_PUNCH_ATTACK1_R][3] = self.animation.myanimsimgs[54]
 
self.animation:createAnim(g_ANIM_PUNCH_ATTACK2_R, 50, 54) -- low or mid anticipation / quick hit / low or mid overhead is best
 
-- self.animation:createAnim(g_ANIM_KICK_ATTACK1_R, 62, 63) -- 35, 41, no or low anticipation / quick hit / no or low overhead is best
 
self.animation.anims[g_ANIM_KICK_ATTACK1_R] = {}
 
self.animation.anims[g_ANIM_KICK_ATTACK1_R][1] = self.animation.myanimsimgs[62]
 
self.animation.anims[g_ANIM_KICK_ATTACK1_R][2] = self.animation.myanimsimgs[64]
 
self.animation.anims[g_ANIM_KICK_ATTACK1_R][3] = self.animation.myanimsimgs[67]
 
self.animation:createAnim(g_ANIM_KICK_ATTACK2_R, 62, 68) -- low or mid anticipation / quick hit / low or mid overhead is best
 
...
 
</syntaxhighlight>
 
 
 
We give our animations a name plus the starting image and the ending image in the spritesheet. The animations names were declared in the '''"main.lua"''' file. Here it is better to have quick animations with few images.
 
 
 
The code just above demonstrates two ways to create animations. We can either use:
 
* ''CAnimation:createAnim'' function when the images are contiguous in the spritesheet (g_ANIM_PUNCH_ATTACK2_R, g_ANIM_KICK_ATTACK2_R)
 
* manually create the animation table when the images are not contiguous in the spritesheet (g_ANIM_PUNCH_ATTACK1_R, g_ANIM_KICK_ATTACK1_R)
 
 
 
This gives us maximum flexibility!
 
 
 
When we are done with our animations we can do some clean up.
 
 
 
=== HIT BOX ===
 
Hit boxes are not components per se, but they are somewhat related to the attacks animations. I used two kind of hit boxes: the hit boxes targeting the head and the hit boxes targeting the spine.
 
 
 
Depending on the attack performed, the hit box will be different in size and will target either another Entity head or spine hurt box. Hit boxes like hurt boxes are tables:
 
* is it active, the Entity is performing an attack or not
 
* the animation frame the hit box becomes active
 
* the animation frame the hit box is no longer active
 
* the damage it deals
 
* its x and y position
 
* its size
 
 
 
== SHADOW ==
 
The Shadow Component adds an Entity a shadow to give more depth to the game. You can create a file called "'''cShadow.lua'''" in the '''"_C"''' folder. The code:
 
<syntaxhighlight lang="lua">
 
CShadow = Core.class()
 
 
 
function CShadow:init(xparentw, xshadowsx, xshadowsy)
 
self.sprite = Bitmap.new(Texture.new("gfx/fx/shadow.png"))
 
local sx = (self.sprite:getWidth()><xparentw)/(self.sprite:getWidth()<>xparentw)
 
self.sprite:setScale(xshadowsx or sx, xshadowsy or sx)
 
self.sprite:setAnchorPoint(0.5, 0.5)
 
-- self.sprite:setAlpha(0.5)
 
self.sprite:setColorTransform(0, 0, 0, 0.65)
 
end
 
</syntaxhighlight>
 
 
 
The CShadow Component creates a bitmap shadow below our Entity. You can give the shadow a width and a scale (optional). We will create a System to position the shadow in the next chapters.
 
  
 
== Next? ==
 
== Next? ==

Revision as of 02:56, 8 September 2025

Components

As we have seen in the previous chapter, components are abilities we add to an Entity. Entities can and will share the same components.

Let's continue adding abilities to our player1.

BODY

The Body Component adds an Entity the ability to move both on the x and y axis. You can create a file called "cBody.lua" in the "_C" folder. The code:

CBody = Core.class()

function CBody:init(xmass, xspeed, xupspeed, xextra)
	-- body physics properties
	self.mass = xmass or 1
	self.currmass = self.mass
	self.vx = 0
	self.vy = 0
	self.speed = xspeed
	self.currspeed = self.speed
	self.upspeed = xupspeed
	self.currupspeed = self.upspeed
	if xextra then
		self.inputbuffer = 1*8 -- 1*8, 2*8
		self.currinputbuffer = self.inputbuffer
		self.coyotetimer = 1.65*8 -- 1.5*8, 2*8, 12
		self.currcoyotetimer = self.coyotetimer
		self.jumpcount = 1 -- 2
		self.currjumpcount = self.jumpcount
		self.candash = true -- true, false XXX
		self.dashtimer = 1*8 -- 1*8 -- 0.5*8
		self.currdashtimer = self.dashtimer
		self.dashmultiplier = 1.5 -- 1.5
		self.dashcooldown = 4*8 -- 4*8, cooldown before performing another dash
		self.currdashcooldown = self.dashcooldown
	end
end

The CBody:init function signature has four parameters: the body mass, the speed on the x axis, the upspeed on the y axis and the extra body variables.

note: some entities will have a body but without the extra parameters, for example a moving platform
Components are usually small pieces of code, which is nice!

COLLISION BOX

The CollisionBox Component adds an Entity a collision box. You can create a file called "cCollisionBox.lua" in the "_C" folder. The code:

CCollisionBox = Core.class()

function CCollisionBox:init(xcollwidth, xcollheight)
	self.w = xcollwidth
	self.h = xcollheight
end

That's all we need to tell a System this Entity has a collision box. We store the Entity collision box width and height to be used by systems.

Shield

This is not an ECS component per se but I added some shield to the player1. I think I should have created a component for it but that will do for now.

When you press the shield action key, the shield is activated.

Next?

The player1 Entity and its components are done, now using almost the same components let's create our enemies...


Prev.: Tuto tiny-ecs 2d platformer Part 5 ePlayer1
Next: Tuto tiny-ecs 2d platformer Part 7 Enemies


Tutorial - tiny-ecs 2d platformer