Dusk Engine

Newbie question…

I have inserted rectangle object in Tiled and named is as “enemy”. In Corona I try to replace the rectangle placeholder with image/sprite sheet.

    for object in map.layer["npc"].nameIs("enemy") do       -- something like this maybe? object.image = display.newImageRect( "enemy.png", 40, 40 )     end

Thanks in advance :slight_smile:

One question Caleb:

I want to do a fast endless runner sample, based on your spin demo. My question: Is it possible to use the spin map file as a reappearing map somehow? I mean when reaching the left or right border of the map the same map (or another) is shown directly next to the original map… and when the character is moving to the border of the next map another map is shown next to this one, so a seamless movement can be created using the same map more than once?

Thx for your help!

I don’t know if this is the good way but I made in for loop variable newObject which gets object’s x and y. Then I just remove the object and insert the newObject.

Something like this:

[lua]

    for object in map.layer[“npc”].object[“enemy”] do
     local newObject = display.newImageRect( “enemy.png”, 40, 40 )

     newObject.x = object.x

     newObject.y = object.y

     object:removeSelf()

     object = nil

     map.layer[“npc”]:insert(newObject)
    end

[/lua]

I hope this was what you were looking for :smiley: Oh and I guess if you have multiple “enemy” named objects in npc layer you need to use:

[lua]

    for object in map.layer[“npc”].objects() do

       if object.name==“enemy” then

         – etc.

       end

    end

[/lua]

I have noticed one small problem if you are using physics: bodyType needs to be static, because when it is dynamic the newObjects further from player wont be there when player arrives near further newObjects. I think they just start dropping when the game loads because the map is not yet loaded under them.

I am sure Caleb has some solution to that. I am eager to hear if there is a better way to do this. 

I am having a hard time to make Tiled’s animationEditor and collisionEditor work in Corona. Is there some kind of custom property required to make them work?

For animation I have tried custom properties like:

!isSprite! = true,

anim:enabled = true

anim:options = !!! start: 1 count: 10 time: 1000

Thanks Painconfess!

The solution replacing Tiled objects seems logical to me. What I’m trying to achieve is this: https://www.youtube.com/watch?v=2_KB4tOTH6w

I’m pretty sure that Dusk doesn’t support animationEditor or collisionEditor of the Tiled editor.

This sounds reasonable also: “bodyType needs to be static, because when it is dynamic the newObjects further from player wont be there when player arrives near further newObjects. I think they just start dropping when the game loads because the map is not yet loaded under them.

Hopefully Caleb could comment all this :slight_smile:

Hey, guys, sorry for the delay. I’ve been out of town for the weekend.

@tonshadow:

You should probably just destroy and rebuild maps as the player goes from section to section. I would recommend first loading the map data for each map, or, if you have a lot of maps, for each map directly “adjacent” to the current map (where the player can reach it by going through only one door). The actual building of the map is pretty fast, and is really a constant amount of time - once the data’s been loaded, building a million-tile map and building a five-tile map takes about the same time. So destroying a map and rebuilding it when the player goes through a door shouldn’t be a problem.

@Aatos Media:

For my game, I’m doing the same thing. I’m using the dev branch’s object culling, so I added an object listener which creates/destroys the “real” object (created programmatically) when the object’s “host” object is created or destroyed. I encapsulated it into a part of my game’s engine, so now I can define an object type and just say how to create it and how to destroy it, then the game engine finds objects with that particular type and tacks on the listener. This probably won’t be really necessary; I’m having to use culling 'cause I’m planning on having hugely enormous “zones”. If your maps aren’t overly big or don’t have too many objects, you should be able just to create the object as you wrote. Don’t forget to insert the object into the object’s “host” object’s layer.

@c.noeth:

What you might be looking for is edge modes. Add a property to whatever layers you want to wrap around (tile layers only, currently), “edgeModeLeft/Right/Top/Bottom”, and set it to “wrap”. Then, when the map moves past its edge, the tile layer will wrap around instead of stopping at the edge. Other values are “stop” (the default) and “clamp” (repeat the tile at the edge).

@Painconfess:

Do not remove the object and replace it with the new one. This is just asking for bugs - as Dusk advances and object culling becomes non-dev-branch, objects might have special properties, culling will break, errors will occur, and your app will disintegrate into a pile of smoking debris. Sorry for such harshness, but I don’t want you to use an approach which will break soon… You can just leave the object where it is and make it invisible, or you can make it a data object (!isData!). Doing that should keep things working well into the future :).
 

@Painconfess #2:

!isSprite! shouldn’t be there, all you need is anim:enabled and anim:options. Make sure the animation options are correct.

@Aatos Media #2:

If you need some code for replacing objects, let me know and I’ll get some together.

Dusk supports animations from Tiled via properties; it doesn’t currently support the animation editor or collision editor (good gosh, I didn’t even know that existed! Dusk needs to keep up! :D)

  • Caleb

@Aatos Media #2:

If you need some code for replacing objects, let me know and I’ll get some together.

Example code would be greatly appreciated, thanks in advance :slight_smile:

About the Painconfess’s approach: Do you mean that replacing is ok, but you shouldn’t remove the original object created with Tiled?

Thank you for the warning ! :slight_smile: I was using the objects in Tiled to easily apply my forexample enemies to the right coordinates by replacing. Now I am thinking is it possible to do the enemies in Tiled with animations with different animationsequences and in program add the eventListeners for moving, collisioning, shooting, hitting, jumping, changing animation sequence etc.

Would the anim:options with many sequences be some thing like this:    anim:options = !!!name: walkleft start: 1 count 4 time: 1000!!! name: walkright start: 5 count: 9 time: 1000!!! name: jump frames: {10,15,16} time: 1000

Oh and is there a solution for object not being able to be dynamic like me and Aatos Media discussed about?

Adding a new object into the object layer is fine, but deleting the original one Dusk created is un-fine.

Bang notation would use nested tables for the anim:options with multiple sequences:

anim:options = !!! {name: walkleft start: 1 count: 4 time: 1000}, {name: walkright start: 5 count: 9 time: 1000}

As for dynamic objects, the best way to do that is to create/delete the object as the object’s “host” is created or deleted. That way, it’ll move with the culling. The sample code at the end of this post has a simple solution for this.

Also, I forgot to mention, there’s a dedicated iterator for objects with a particular name. It’s not any faster than checking each object, but it’s clearer in your code:

for object in map.layer["objects"].nameIs("objectName") do end

And, as for the most robust object “replacing” sample code, here’s some simplified and trimmed from my personal game engine. It’s a function which registers an object type on the map, which then creates and deletes the object according to parameters when the object’s “host” is created or deleted by culling. All you have to do is pass a “params” table to it, with several fields: ‘build’, a function which creates the object and returns it, ‘remove’, a function which deletes the object, and ‘objectType’, a string equal to the type this object should be “bound” to.

This code requires the dev branch of Dusk.

local function addObjectType(params) params.objects = params.objects or {} local function buildObject(event) local obj = params.build(event) event.object.builtObject = obj obj.mapObject = event.object params.objects[obj] = obj end     for layer in map.objectLayers() do layer.addObjectListener("type", params.objectType, "drawn", buildObject) layer.addObjectListener("type", params.objectType, "erased", function(event) params.objects[event.object.builtObject] = nil params.remove(event.object.builtObject) end) end objectTypes[#objectTypes + 1] = params end
  • Caleb

Thanks Caleb for the example code! Maybe it’s just me but I don’t know how to use it. I have too many questions (for examle, ’cause culling his happening all the time, should this function be called from the game loop?), but maybe the easiest way is that if you could add a demo of this to Dusk release?

You have mentioned ”large” and ”small” maps - like you don’t necessary need something if the map is small. What is a small map? For example if culling is not necessary in some cases, it would make things a lot easier - and just in case - is this right way to disable the culling:

dusk.setPreference("enableTileCulling", false)

p.s. I’m really looking forward to see your game and Dusk in real action :wink:

To use my code:

local objectType = {} objectType.objectType = "mySpecialObjectType" -- A function which creates your custom object objectType.build = function(event) local object = display.newRect(0, 0, event.object.width, event.object.height) object.x, object.y = event.object.x, event.object.y event.object.parent:insert(object) return object end -- A function which deletes your custom object objectType.remove = function(object) display.remove(object) end addObjectType(objectType) -- Now, all objects in your map with type 'mySpecialObjectType' will have a listener which calls 'build' and 'remove' as the object is drawn and culled - thereby making a custom object which is still culled.

The easiest way to make object types is with separate modules. It even gives you a sort of object-oriented feel. This code only needs to be called once. It’s like a “hey, Dusk, do this and this when you draw and erase an object” function.

Since you get control of the way objects are created, in my game engine, I’ve added a lot of bells and whistles - fit mode and aspect ratio, listeners, etc. - but unfortunately most of the code had game-engine-specific dependencies in it :(.

Large and small maps kind of depend on how much you’ve got going on. Maps which only have tiles can usually get relatively large before culling is required, but the exact size depends on your hardware. For a single-layer tile map completely filled with 32x32 tiles, I can get about 3 screens full of tiles before lag starts getting noticeable. Object layers depend on the number of objects. Without object culling from the dev branch on, you’ll likely be able to get quite a few objects in before lag starts coming to get you.

And, if you’re using the dev branch, you can do that to disable tile culling, or, for object culling, switch out the word “Tile” for “Object”.

  • Caleb

Tried to codes above (pasted the first example code starting “local function addObjectType(params)” and then “local objectType = {}”. I replaced Dusk folder with the latest Dusk Dev Release. But I get an error message:

Attempt to get length of global 'objectTypes' (a nil value) stack traceback:     main.lua:373: in function 'addObjectType'     main.lua:394: in main chunk

The line is:

objectTypes[#objectTypes + 1] = params

If I comment the line, project runs, but I assume that the line needed somehow :wink:

Just a confirmation - should the type value of the object in Tiled be “mySpecialObjectType”?

That line just inserts the object type into a storage table. You can remove that line if you want. If you don’t, just make a table called “objectTypes”, then, each time you add an object type, you’ll get it added to the objectTypes table.

The parameters’ objectType is what the Tiled object type needs to be. So if you create, say, an object type for moving platform, and set its objectType to “movingPlatform”, your Tiled objects will have to be of type “movingPlatform”.

  • Caleb

I am having troubles with animating my enemy object in Tiled, I exported the spritesheet as a tileset and set the tilesize same as frame size. Then I put the right custom properties for animation but nothing happens. I am able to animate my ground’s tileset tiles in tilelayer though… so why not the same with object layer?

So I am guessing this is not very good way to do things and just go with the replacing method? Or did I just do something wrong?

Only tile layers currently support animation. To make animated tiles, you’ll have to either use a tile layer or the replacing method.

  • Caleb

The object culling is working pretty fine now :slight_smile:

A few questions:

****

If I add Box2D physics body to the object, the parent object/host (object.event) has it also, which is not wanted. I can set the parent invisible, but the body is still there. I tried to add custom property to the object in Tiled !isData! = true, but no change. Maybe I didn’t do it the right way…

Can I set the isData-value with LUA? And what exactly is isData?

I placed the host off screen (object.event.y=-500) and the problem was solved, but is this proper way?

****

If I want to place the player a bit more left of the screen, is this the right way: map.layer[”ground”].setCameraOffset(-15, 3)?

****

Please check this 10 sek video: http://aatosmedia.fi/tmp/objectculling.mov

I tried to use the object culling code above. After the orange object is created, it moves to the right. Now when the player goes right and the objects host object is culled, the orange object disappears.

I was wondering if there is a way to force culling to happen a bit more ”later”. I assume that now about “one screen” is not culled and all others are. So is it possible to set that for example “two screens” are not culled? Or is there an another way to solve this problem.

I hope you got the point :wink:

For your first question, what do you mean? Are you adding physics to the “child” object and the host object is getting it as well?

objectType.build = function(event) local obj = display.newRect(0, 0, 100, 100) physics.addBody(obj, ...) -- The host object is getting this?!? return obj end

!isData! is a property you can add to objects in Tiled that makes them retain all their properties but not be an actual display object. Culling is not available for !isData! objects, but I’ll likely add it soon. You can’t add isData programmatically, because it has to be attached to an object when the map is created.

Second question: Yup, that’s correct.

Third question: I use objects in Tiled sort of like boundaries for my child/built objects. Culling will activate as soon as the entire host object goes off-screen, so you can make the object bigger to keep it from being destroyed too soon. For example, I use Tiled objects for my moving platforms by making them the entire width or height of the platform’s moving path; then, the platform is deleted after it and its moving path is completely off-screen.

  • Caleb

1st

My bad - I forgot object layer’s physics settings - sorry :wink:

3nd

Ok. This sounds pretty nice actually. This way I can visually draw set the distance of moving platforms or enemies - great!

I am trying to use your addObjectType(params) function, but it just don’t replace the objects in Tiled with the same objectType.

this is how my build function looks like:

[lua]

        objectType.build = function(event)

          local object = display.newSprite( sheetPic, sheetSequenceData)

          object.myName = “Enemy”

          physics.addBody( object, “static”, {radius = 25} )

          object:setSequence( “spinRight” )

          object:play()

          object.x, object.y = event.object.x, event.object.y

          event.object.parent:insert(object)

          return object

        end

[/lua]

EDIT:

Got it working, I thought you needed to give custom property for object in Tiled like objectType = Enemy, but I just noticed the Type field under the Object properties.

But now I noticed the object in Tiled is still visible when I for example shoot the enemy. I am guessing the !isData! is the right way to do in Tiled object, but how do I set object !isData! ? Is the removeSelf() function right way to remove the shooted enemies?

@Painconfess:

To hide the object, just set the Dusk preference ‘virtualObjectsVisible’ to false before loading your map.

dusk.setPreference("virtualObjectsVisible", false)
  • Caleb