Difference between revisions of "Animated Sprite Factory"

From GiderosMobile
(added example)
 
(13 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
__TOC__
 
__TOC__
<languages />
+
Here you will find various resources to help you create games and apps in Gideros Studio.
<translate>Here you will find various resources to help you create games and apps in Gideros Studio.</translate>
 
<br/>
 
<translate>'''note''': You may have to provide your own assets (fonts, gfx, …).</translate>
 
<br/>
 
  
=== <translate>Description</translate> ===
+
'''note''': You may have to provide your own assets (fonts, gfx, ).</br>
This section deals with animating any of your sprites (player, enemies, collectibles, ...). It can be used either in conjunction with cbump, liquidfun or as a standalone class.
+
'''note 2''': You can copy/paste the code :-)
  
=== <translate>Animation Sprite Factory (player, enemies, collectibles, npcs, ...)</translate> ===
+
=== Description ===
This animation sprite factory class allows you to control all your characters parameters like speed, animations, ...
+
This section deals with animating any of your sprites (player, enemies, collectibles, ...). It can be used either in conjunction with cbump, liquidfun(box2d) or as standalone.
<source lang="lua">
 
Sprite_Maker = Core.class(Sprite)
 
  
function Sprite_Maker:init(xname, xspritesheet, xcols, xrows, xposx, xposy)
+
=== Spritesheet Animations (player, enemies, collectibles, npcs, ...) ===
-- settings
+
This is an example of how to animate using a spritesheet.
self.name = xname
 
self.x = xposx
 
self.y = xposy
 
self.vx = 0
 
self.vy = 0
 
self.flip = 1
 
self.isonfloor = false
 
self.isattacking = false
 
self.lives = 1
 
self.accel = 500
 
self.maxspeed = 200
 
self.jumpspeed = 980
 
  
-- animations
+
==== If you are using a class ====
 +
<syntaxhighlight lang="lua">
 +
Player = Core.class(Sprite)
 +
 
 +
function Player:init()
 +
-- spritesheet animations
 +
local spritesheettex = Texture.new("gfx/playable/mr_man.png")
 +
local cols, rows = 8, 6
 +
self.spritesheetimgs = {} -- table that will hold all the images in the sprite sheet
 +
self.anims = {} -- table that will hold all our animations ("idle", "run", ...)
 
self.currentanim = ""
 
self.currentanim = ""
 
self.frame = 0
 
self.frame = 0
self.animspeed = 1 / 8
+
self.animspeed = 1 / 7
 
self.animtimer = self.animspeed
 
self.animtimer = self.animspeed
 
+
-- 1 retrieve all anims in spritesheet
-- retrieve all anims in texture
+
local w, h = spritesheettex:getWidth() / cols, spritesheettex:getHeight() / rows
local myanimstex = Texture.new(xspritesheet)
+
local spritesheettexregion = nil
local cellw = myanimstex:getWidth() / xcols
+
for r = 1, rows do
local cellh = myanimstex:getHeight() / xrows
+
for c = 1, cols do
local myanims_list = {}
+
spritesheettexregion = TextureRegion.new(spritesheettex, (c - 1) * w, (r - 1) * h, w, h)
for r = 1, xrows do
+
self.spritesheetimgs[#self.spritesheetimgs + 1] = spritesheettexregion
for c = 1, xcols do
 
local myanimstexregion = TextureRegion.new(
 
myanimstex, (c - 1) * cellw, (r - 1) * cellh, cellw, cellh)
 
myanims_list[#myanims_list + 1] = myanimstexregion
 
 
end
 
end
 
end
 
end
 +
-- 2 create animations
 +
self:createAnim("idle", 1, 4)
 +
self:createAnim("run", 9, 14)
 +
self.currentanim = "run"
 +
-- 3 we can now create the player
 +
self.bitmap = Bitmap.new(self.spritesheetimgs[1])
 +
self.bitmap:setAnchorPoint(0.5, 0.5)
 +
self.bitmap:setScale(2)
 +
self:addChild(self.bitmap)
 +
-- LISTENERS
 +
self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
 +
end
  
-- create anims
+
-- PLAYER LOOP
self.anims = {}
+
function Player:onEnterFrame(e)
if self.name == "player1" then -- you can adapt your name here!
+
-- animations
self:createAnim("idle", 1, 2, myanims_list)
+
if self.currentanim ~= "" then
self:createAnim("jump_up", 38, 38, myanims_list)
+
self.animtimer = self.animtimer - e.deltaTime
self:createAnim("jump_down", 39, 39, myanims_list)
+
if self.animtimer <= 0 then
self:createAnim("walk", 13, 16, myanims_list)
+
self.frame += 1
self:createAnim("shoot", 67, 70, myanims_list)
+
self.animtimer = self.animspeed
elseif self.name == "enemy01" then -- you can adapt your name here!
+
if self.frame > #self.anims[self.currentanim] then
self:createAnim("walk", 1, 7, myanims_list)
+
self.frame = 1
elseif self.name == "enemy02" then -- you can adapt your name here!
+
end
self:createAnim("walk", 1, 5, myanims_list)
+
self.bitmap:setTextureRegion(self.anims[self.currentanim][self.frame])
elseif self.name == "coin01" then -- you can adapt your name here!
+
end
self:createAnim("walk", 1, 6, myanims_list)
 
end
 
 
 
-- the bitmap
 
self.bmp = Bitmap.new(myanims_list[1]) -- starting bmp texture
 
self.bmp:setAnchorPoint(0.5, 0.5)
 
if self.name == "player1" then -- adapt name here
 
self.w = self.bmp:getWidth() / 2
 
self.h = self.bmp:getHeight() - 0
 
-- set position inside sprite
 
self.bmp:setPosition(self.w / 2, self.h / 2 - 0 / 2)
 
elseif self.name == "enemy01" then -- adapt name here
 
self.w = self.bmp:getWidth() / 2
 
self.h = self.bmp:getHeight() - 0
 
-- set position inside sprite
 
self.bmp:setPosition(self.w / 2, self.h / 2 - 0 / 2)
 
elseif self.name == "enemy02" then -- adapt name here
 
self.w = self.bmp:getWidth() / 8
 
self.h = self.bmp:getHeight() - 0
 
-- set position inside sprite
 
self.bmp:setPosition(self.w / 2, self.h / 2 - 0 / 2)
 
else
 
self.w = self.bmp:getWidth()
 
self.h = self.bmp:getHeight()
 
-- set position inside sprite
 
self.bmp:setPosition(self.w / 2, self.h / 2)
 
end
 
 
 
-- collisions debugging
 
local mypixel = Pixel.new(0xff0000, 0.5, self.w, self.h)
 
 
 
-- our sprite is ready
 
local mysprite = Sprite.new()
 
mysprite:addChild(self.bmp)
 
mysprite:addChild(mypixel) -- debug
 
self:addChild(mysprite)
 
 
 
-- hero controls
 
if self.name == "player1" then
 
self.iskeyleft = false
 
self.iskeyright = false
 
self.iskeyup = false
 
self.iskeydown = false
 
self.iskeyspace = false
 
 
 
self:addEventListener(Event.KEY_DOWN, self.onKeyDown, self)
 
self:addEventListener(Event.KEY_UP, self.onKeyUp, self)
 
 
end
 
end
 +
self.bitmap:setPosition(128, 64)
 
end
 
end
  
 
-- FUNCTIONS
 
-- FUNCTIONS
function Sprite_Maker:createAnim(xanimname, xstart, xfinish, xanimslist)
+
function Player:createAnim(xanimname, xstart, xfinish)
 
self.anims[xanimname] = {}
 
self.anims[xanimname] = {}
 
for i = xstart, xfinish do
 
for i = xstart, xfinish do
self.anims[xanimname][#self.anims[xanimname] + 1] = xanimslist[i]
+
self.anims[xanimname][#self.anims[xanimname] + 1] = self.spritesheetimgs[i]
 
end
 
end
 
end
 
end
 +
</syntaxhighlight>
  
-- KEYS HANDLER
+
==== If you are not using a class ====
function Sprite_Maker:onKeyDown(e)
+
<syntaxhighlight lang="lua">
-- keys pressed
+
-- spritesheet animations
if e.keyCode == KeyCode.LEFT then self.iskeyleft = true end
+
local spritesheettex = Texture.new("gfx/hero/HQ_Trooper_all.png") -- change accordingly
if e.keyCode == KeyCode.RIGHT then self.iskeyright = true end
+
local cols, rows = 6, 13 -- change accordingly
if e.keyCode == KeyCode.UP then self.iskeyup = true end
+
local spritesheetimgs = {} -- table that will hold all the images in the sprite sheet
if e.keyCode == KeyCode.DOWN then self.iskeydown = true end
+
local anims = {} -- table that will hold all our animations ("idle", "run", ...)
if e.keyCode == KeyCode.SPACE then self.iskeyspace = true end
+
local currentanim = ""
 +
local frame = 0
 +
local animspeed = 1 / 7 -- change accordingly
 +
local animtimer = animspeed
 +
 
 +
-- 1 retrieve all anims in spritesheet
 +
local w, h = spritesheettex:getWidth() / cols, spritesheettex:getHeight() / rows
 +
local spritesheettexregion = nil
 +
for r = 1, rows do
 +
for c = 1, cols do
 +
spritesheettexregion = TextureRegion.new(spritesheettex, (c - 1) * w, (r - 1) * h, w, h)
 +
spritesheetimgs[#spritesheetimgs + 1] = spritesheettexregion
 +
end
 
end
 
end
  
function Sprite_Maker:onKeyUp(e)
+
-- 2 create animations
-- keys released
+
function createAnim(xanimname, xstart, xfinish)
if e.keyCode == KeyCode.LEFT then self.iskeyleft = false end
+
anims[xanimname] = {}
if e.keyCode == KeyCode.RIGHT then self.iskeyright = false end
+
for i = xstart, xfinish do
if e.keyCode == KeyCode.UP then self.iskeyup = false end
+
anims[xanimname][#anims[xanimname] + 1] = spritesheetimgs[i]
if e.keyCode == KeyCode.DOWN then self.iskeydown = false end
+
end
if e.keyCode == KeyCode.SPACE then self.iskeyspace = false end
 
 
end
 
end
</source>
+
createAnim("idle", 1, 2)
 +
createAnim("run", 25, 30)
  
=== <translate>Example</translate> ===
+
-- 3 we can now create the player
<source lang="lua">
+
local bitmap = Bitmap.new(spritesheetimgs[1])
-- stage
+
bitmap:setAnchorPoint(0.5, 0.5)
local player1 = Sprite_Maker.new("player1", "gfx/hero/HQ_Trooper_all.png", 6, 13, 64, 128)
+
bitmap:setPosition(128, 64)
player1.lives = 3
+
stage:addChild(bitmap)
stage:addChild(player1)
+
currentanim = "idle"
local coin = Sprite_Maker.new("coin01", "gfx/coins/coin_20_x01.png", 6, 1, 128, 128)
+
--currentanim = "run"
coin:setScale(3)
 
coin.animspeed = 1 / 3
 
stage:addChild(coin)
 
  
 
-- GAME LOOP
 
-- GAME LOOP
stage:addEventListener(Event.ENTER_FRAME, function(e)
+
function onEnterFrame(e)
updatePlayer(player1, e.deltaTime)
+
if currentanim ~= "" then
updateCollectibles(coin, e.deltaTime)
+
animtimer = animtimer - e.deltaTime
end)
+
if animtimer <= 0 then
 
+
frame += 1
-- FUNCTIONS
+
animtimer = animspeed
function updatePlayer(xsprite, dt)
+
if frame > #anims[currentanim] then
-- anim state
+
frame = 1
if xsprite.vx == 0 then
 
xsprite.currentanim = "idle"
 
elseif xsprite.vx ~= 0 then
 
xsprite.currentanim = "walk"
 
end
 
-- keyboard handling
 
if xsprite.iskeyright then
 
xsprite.vx += xsprite.accel * dt
 
if xsprite.vx > xsprite.maxspeed then xsprite.vx = xsprite.maxspeed end
 
xsprite.flip = 1
 
elseif xsprite.iskeyleft then
 
xsprite.vx -= xsprite.accel * dt
 
if xsprite.vx < -xsprite.maxspeed then xsprite.vx = -xsprite.maxspeed end
 
xsprite.flip = -1
 
else
 
xsprite.vx = 0
 
end
 
-- anim loop
 
if xsprite.currentanim ~= "" then
 
xsprite.animtimer = xsprite.animtimer - dt
 
if xsprite.animtimer <= 0 then
 
xsprite.frame += 1
 
xsprite.animtimer = xsprite.animspeed
 
if xsprite.frame > #xsprite.anims[xsprite.currentanim] then
 
xsprite.frame = 1
 
 
end
 
end
xsprite.bmp:setTextureRegion(xsprite.anims[xsprite.currentanim][xsprite.frame])
+
bitmap:setTextureRegion(anims[currentanim][frame])
 
end
 
end
 
end
 
end
-- move & flip
 
xsprite.x += xsprite.vx * dt
 
xsprite.y += xsprite.vy * dt
 
xsprite:setPosition(xsprite.x, xsprite.y)
 
xsprite.bmp:setScale(xsprite.flip, 1)
 
 
end
 
end
 +
stage:addEventListener(Event.ENTER_FRAME, onEnterFrame)
 +
</syntaxhighlight>
  
function updateCollectibles(xsprite, dt)
+
==== In your game ====
-- anim state
+
Then all you need to do is create an instance of the player in your game class.
xsprite.currentanim = "walk"
+
<syntaxhighlight lang="lua">
-- anim loop
+
local myhero = Player.new()
if xsprite.currentanim ~= "" then
+
</syntaxhighlight>
xsprite.animtimer = xsprite.animtimer - dt
+
 
if xsprite.animtimer <= 0 then
+
=== Assets ===
xsprite.frame += 1
+
You can pick the files from opengameart.org:
xsprite.animtimer = xsprite.animspeed
+
* https://opengameart.org/content/space-soldier-resize-64x64
if xsprite.frame > #xsprite.anims[xsprite.currentanim] then
+
* https://opengameart.org/content/pixel-coins-asset
xsprite.frame = 1
 
end
 
xsprite.bmp:setTextureRegion(xsprite.anims[xsprite.currentanim][xsprite.frame])
 
end
 
end
 
-- show
 
xsprite:setPosition(xsprite.x, xsprite.y)
 
xsprite.bmp:setScale(xsprite.flip, 1)
 
end
 
</source>
 
  
<!--
 
=== <translate>A YouTube Video</translate> ===
 
A step by step video on how to use this platformer template. Enjoy!
 
  
https://www.youtube.com/watch?v=WPcbsgOCnLU
+
{{GIDEROS IMPORTANT LINKS}}
-->
 

Latest revision as of 22:51, 18 November 2023

Here you will find various resources to help you create games and apps in Gideros Studio.

note: You may have to provide your own assets (fonts, gfx, …).
note 2: You can copy/paste the code :-)

Description

This section deals with animating any of your sprites (player, enemies, collectibles, ...). It can be used either in conjunction with cbump, liquidfun(box2d) or as standalone.

Spritesheet Animations (player, enemies, collectibles, npcs, ...)

This is an example of how to animate using a spritesheet.

If you are using a class

Player = Core.class(Sprite)

function Player:init()
	-- spritesheet animations
	local spritesheettex = Texture.new("gfx/playable/mr_man.png")
	local cols, rows = 8, 6
	self.spritesheetimgs = {} -- table that will hold all the images in the sprite sheet
	self.anims = {} -- table that will hold all our animations ("idle", "run", ...)
	self.currentanim = ""
	self.frame = 0
	self.animspeed = 1 / 7
	self.animtimer = self.animspeed
	-- 1 retrieve all anims in spritesheet
	local w, h = spritesheettex:getWidth() / cols, spritesheettex:getHeight() / rows
	local spritesheettexregion = nil
	for r = 1, rows do
		for c = 1, cols do
			spritesheettexregion = TextureRegion.new(spritesheettex, (c - 1) * w, (r - 1) * h, w, h)
			self.spritesheetimgs[#self.spritesheetimgs + 1] = spritesheettexregion
		end
	end
	-- 2 create animations
	self:createAnim("idle", 1, 4)
	self:createAnim("run", 9, 14)
	self.currentanim = "run"
	-- 3 we can now create the player
	self.bitmap = Bitmap.new(self.spritesheetimgs[1])
	self.bitmap:setAnchorPoint(0.5, 0.5)
	self.bitmap:setScale(2)
	self:addChild(self.bitmap)
	-- LISTENERS
	self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end

-- PLAYER LOOP
function Player:onEnterFrame(e)
	-- animations
	if self.currentanim ~= "" then
		self.animtimer = self.animtimer - e.deltaTime
		if self.animtimer <= 0 then
			self.frame += 1
			self.animtimer = self.animspeed
			if self.frame > #self.anims[self.currentanim] then
				self.frame = 1
			end
			self.bitmap:setTextureRegion(self.anims[self.currentanim][self.frame])
		end
	end
	self.bitmap:setPosition(128, 64)
end

-- FUNCTIONS
function Player:createAnim(xanimname, xstart, xfinish)
	self.anims[xanimname] = {}
	for i = xstart, xfinish do
		self.anims[xanimname][#self.anims[xanimname] + 1] = self.spritesheetimgs[i]
	end
end

If you are not using a class

-- spritesheet animations
local spritesheettex = Texture.new("gfx/hero/HQ_Trooper_all.png") -- change accordingly
local cols, rows = 6, 13 -- change accordingly
local spritesheetimgs = {} -- table that will hold all the images in the sprite sheet
local anims = {} -- table that will hold all our animations ("idle", "run", ...)
local currentanim = ""
local frame = 0
local animspeed = 1 / 7 -- change accordingly
local animtimer = animspeed

-- 1 retrieve all anims in spritesheet
local w, h = spritesheettex:getWidth() / cols, spritesheettex:getHeight() / rows
local spritesheettexregion = nil
for r = 1, rows do
	for c = 1, cols do
		spritesheettexregion = TextureRegion.new(spritesheettex, (c - 1) * w, (r - 1) * h, w, h)
		spritesheetimgs[#spritesheetimgs + 1] = spritesheettexregion
	end
end

-- 2 create animations
function createAnim(xanimname, xstart, xfinish)
	anims[xanimname] = {}
	for i = xstart, xfinish do
		anims[xanimname][#anims[xanimname] + 1] = spritesheetimgs[i]
	end
end
createAnim("idle", 1, 2)
createAnim("run", 25, 30)

-- 3 we can now create the player
local bitmap = Bitmap.new(spritesheetimgs[1])
bitmap:setAnchorPoint(0.5, 0.5)
bitmap:setPosition(128, 64)
stage:addChild(bitmap)
currentanim = "idle"
--currentanim = "run"

-- GAME LOOP
function onEnterFrame(e)
	if currentanim ~= "" then
		animtimer = animtimer - e.deltaTime
		if animtimer <= 0 then
			frame += 1
			animtimer = animspeed
			if frame > #anims[currentanim] then
				frame = 1
			end
			bitmap:setTextureRegion(anims[currentanim][frame])
		end
	end
end
stage:addEventListener(Event.ENTER_FRAME, onEnterFrame)

In your game

Then all you need to do is create an instance of the player in your game class.

local myhero = Player.new()

Assets

You can pick the files from opengameart.org: