Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

RG Tiled + Behaviors (Entity Component System)
Started by roaminggamer Jul 24 2018 05:30 PM

9 replies to this topic
[TOPIC CONTROLS]
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

Ugh... I just typed up a long post about this, and then promptly destroyed it by accident.

 

So, apologies if this is not super illuminating, but I just can't bring myself to type it again. :(

 

RGTiled

SSK2 include a "Tiled Level Loader and Drawing Library' called RGTiled.  It is similar to many of the other loaders you can find (list below), but also includes these features:

  • Supports embedded and external tilesets.
  • Supports defining bodies using Tiled physics editor. (Default, Rectangle, Polygon.)
    • Supports multi-body too.
    • Circular bodies can not be edited, but can be defined from properties.
  • Can edit physics properties from Tiled
  • One-line Load
  • One-line Drawing
  • ForEach Iterator
  • User Defined Builders - You can provide custom code for just those objects that need more features than are available via the standard RGTiled standar features.
  • Behaviors - Attach code to objects by defining named properies w/ optional arguments to the behavior.
  • Stitchers - i.e. Stitch multiple levels together.

There is way too much to discuss here so I made a video and as time permits I'll make more posts, demos etc.

 

 

Other Tiled Loaders++

 

Behaviors / Scripted Entity Component System

 

I added a new feature to SSK that allows you to pre-define arbitrary packages of code and to 'late attach and configure' them.

 

While I call these Behaviors, you may be more familiar with the term 'Entity Component System'.

 

These packages let you give display objects arbitrary complex behaviors in just a few lines of code.

 

When time permits I will make some examples, videos, etc.  for I'll just tease you with some random code.

local obj = display.newCircle( centerX, centerY, 40 )

-- Silly way to give the object an initial color, make it jiggle, take focus when you touch it,
-- and change color when you touch and release it.

ssk.behaviors.add( obj, "b_fillColor",  "color=FF33dd" )
ssk.behaviors.add( obj, "b_jiggler", "x1 = -10, x2 = 10, y1 = 0, y2 = 0, period = 100"  )
ssk.behaviors.add( obj, "b_touch_color", { began_color = "#FF0000", end_color = "#FFFFFF"} )
ssk.behaviors.add( obj, "b_touch_focus" )

The jiggler behavior:

-- =============================================================
-- Copyright Roaming Gamer, LLC. 2008-2018 (All Rights Reserved)
-- =============================================================
local mRand = math.random
local getTimer = system.getTimer
--
local mod = {}

function mod.new( settings )
   local behavior = {}
   behavior.ll = {} -- local listeners   obj:event() )   ==> ex: obj:addEventListener( "collision" )
   behavior.gl = {} -- global listeners  Runtime:event() ==> ex: Runtime:addEventListener( "enterFrame", obj )
   --
   --table.dump(settings)
   local x0
   local y0
   local lastT
   local x1 = settings.x1 or 0
   local y1 = settings.y1 or 0
   local x2 = settings.x2 or 0
   local y2 = settings.y2 or 0
   local period = settings.period or 0
   --
   function behavior.onCreate( obj ) 
      lastT = getTimer()
      x0 = obj.x
      y0 = obj.y
   end
   --   
   function behavior.gl.enterFrame( self ) 
      local curT = getTimer()
      if( curT - lastT   <  period ) then return end
      lastT = curT
      self.x = x0 + mRand(x1, x2)
      self.y = y0 + mRand(y1, y2)
   end
   --
   return behavior
end

return mod

The touch color behavior:

-- =============================================================
-- Copyright Roaming Gamer, LLC. 2008-2018 (All Rights Reserved)
-- =============================================================
local mod = {}

function mod.new( settings )   
   local behavior = {}
   behavior.ll = {} -- local listeners   obj:event() )   ==> ex: obj:addEventListener( "collision" )
   behavior.gl = {} -- global listeners  Runtime:event() ==> ex: Runtime:addEventListener( "enterFrame", obj )
   --
   local beganColor = settings.began_color or {1,0,0,1} 
   local endedColor = settings.end_color or {1,1,1,1} 
   if( type(beganColor) == "string" ) then
      beganColor = hexcolor(beganColor)
   end
   if( type(endedColor) == "string" ) then
      endedColor = hexcolor(endedColor)
   end
   -- Ensure we have a four-value color coded
   for i = 1, 4 do
      beganColor[i] = (beganColor[i] ~= nil) and beganColor[i] or 1
      endedColor[i] = (endedColor[i] ~= nil) and endedColor[i] or 1
   end
   --
   function behavior.ll.touch( self, event ) 
      if( event.phase == "began" ) then
         self:setFillColor(unpack(beganColor))
      elseif( event.phase == "ended" ) then
         self:setFillColor(unpack(endedColor))
      end
      return true
   end
   --
   return behavior
end

return mod

The 'take focus on touch' behavior:

-- =============================================================
-- Copyright Roaming Gamer, LLC. 2008-2018 (All Rights Reserved)
-- =============================================================
local mod = {}

function mod.new( settings )   
   local behavior = {}
   behavior.ll = {} -- local listeners   obj:event() )   ==> ex: obj:addEventListener( "collision" )
   behavior.gl = {} -- global listeners  Runtime:event() ==> ex: Runtime:addEventListener( "enterFrame", obj )
   --
   function behavior.ll.touch( self, event ) 
      if( event.phase == "began" ) then
         behavior._isFocus = true
         display.getCurrentStage():setFocus( self, event.id )
      elseif( behavior._isFocus ) then
         if( event.phase == "ended" ) then
            timer.performWithDelay( 1,
               function()
                  behavior._isFocus = false
                  display.getCurrentStage():setFocus( self, nil )
               end )
         end
      end
      return true
   end
   --
   return behavior
end


return mod


Edited by roaminggamer, 24 July 2018 - 05:36 PM.


[TOPIC: post.html]
#2

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

As an interesting side-effect/feature, if you use 'Behaviors' you can now add as many instances of the same listener type to an object as you want to an object.

 

i.e. If you have ever wished you could have two collision listeners for the same object, it is now possible.  In fact, this is the core enabling feature that allows the Behaviors/ECS code to function.

 

You can now quite literally do this:

local obj = display.newCircle( centerX, centerY, 40 )

local function collision1( self, event )
   ... some code
end

local function collision2( self, event )
   ... some code
end

ssk.behaviors.addEventListener( obj, 'collision', collision1 )
ssk.behaviors.addEventListener( obj, 'collision', collision2 )



[TOPIC: post.html]
#3

Blex

[GLOBAL: userInfoPane.html]
Blex
  • Corona Geek

  • 1,199 posts
  • Corona SDK

Are you going to update the SSK2 docs about this feature being a work in progress? That might throw some people off.



[TOPIC: post.html]
#4

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

I'm working on it, but I have limited time and need to earn $ first.  :(



[TOPIC: post.html]
#5

Blex

[GLOBAL: userInfoPane.html]
Blex
  • Corona Geek

  • 1,199 posts
  • Corona SDK

Just finished watching the video, great job with the loader! The behaviors are particularly interesting.

 

Also, a quick question, does RGTiled support collection of images as well as tilesets, or just tilesets?

 

PS: Good luck with your game development!



[TOPIC: post.html]
#6

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

Sorry for the terminology confusion.  This is a problem in game design.  Loosey goosey usage of terms causing issues.

 

I believe, Tiled uses the term 'tile set' for both 'collections' (of discrete images) and 'images in a sheet'

 

 

RGTiled only supports 'collections' of images.  i.e. Discrete images, not multiple images in a sheet.

 

Click 'New Tileset' button, then choose: 'Collection of Images'.  Then choose either 'embed in map' true or false. Both are supported.

 

 

The other option 'based on tileset image'.... well I have no idea what it does.



[TOPIC: post.html]
#7

Blex

[GLOBAL: userInfoPane.html]
Blex
  • Corona Geek

  • 1,199 posts
  • Corona SDK

The based on tileset image makes a non-embedded TSX file with the separated into tile sizes of your choosing.

 

Honestly, I've always found the collection of images to be better than the tileset. The problem is the separation of the tiles, they may not always come out evenly.



[TOPIC: post.html]
#8

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

I still think there is some confusion here.

 

1. I use discrete images ONLY.  I do not use a single sheet of images.

 

2. I prefer the 'not embedded' option because it produces a *.tsx file that I can then copy (along with the images folder) into other projects.

 

I find the 'emedded' option to be terrible because it is completely non-portable.



[TOPIC: post.html]
#9

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 7,544 posts
  • Corona SDK

I'll make some videos on my process later when I get a chance and that will clarify all of this.

 

:)



[TOPIC: post.html]
#10

Blex

[GLOBAL: userInfoPane.html]
Blex
  • Corona Geek

  • 1,199 posts
  • Corona SDK

Cool, thanks!




[topic_controls]
[/topic_controls]