Unforseen consequences while translating map. Some ToDo is undone or forgotten?

Greetings! Step by step my platformer game skeleton grows and now is time to scroll map. I need to hold focus of «camera» on my character while moving him. 

Easiest way is to center main character on screen while translating map in direction that is opposite to char’s moving direction, right?

But, when I doing this like in sticker knight platformer example, the behaviour is strange: map flips somwhere out of screen. 

I decided to write my own translation controller, when I have suddenly found that physics translations of my map are not corresponding to same I expected. Can you look at this problematic example? I need your thoughts about it)

Realy, it’s very hard for me to dig over the whole code of ponytiled and platformer to understand it. Even so, I realy tried to do. 

Maybe I need to pull-out all physic objects to some separate list-layer and translate it/them to some deltas.

Now I got stuck on this problem because in hybrid mode I see that physic shapes of bodies are corresponding their places. And the only way to move «static» objects is translating, isn’t?

Hi.  I typed up an answer then borked it by clicking the wrong button… so this second post will be a little less verbose.  Sorry.
 

  1. Thanks for posting the link.  I did not however look and instead going directly to solution.
     

  2. The trick to making this work is proper display group hierarchy and only moving the parent group, not child groups.
     

  3. If you’re having physics issues, you are changing the alignment of groups relative to each other and this is borking you up.
     

  4. Here is ONE way to do it.
     
    Make The Layers

    local layers = display.newGroup() layers.world = display.newGroup() layers.under = display.newGroup() layers.content = display.newGroup() layers.over = display.newGroup() – Insert layers into sceneGroup if you’re using composer.* sceneGroup:insert( layers ) layers:insert( layers.world ) layers.world:insert( layers.under ) layers.world:insert( layers.content ) layers.world:insert( layers.over ) – Now you have this BOTTOM TO TOP layering all packaged in – layers which has named fields refering to the groups for easy use – sceneGroup – if using composer – VERY BOTTOM – layers – world (child of layers) – under (child of world) – content (child of world) – over (child of world) – VERY TOP

Add Content In Correct Layers
 
Never add content to layers.world.  This is your camera layer and should only contain the child groups we created.

local player = display.newImageRect( layers.content, ... ) -- add body, etc. local ground = display.newImageRect( layers.under, ... ) local cloud = display.newImageRect( layers.over, ... ) local enemy = display.newImageRect( layers.content, ... ) -- add body, etc. .. more as needed

The Camera Code
You are essentially talking about a camera above.  This is a tracking camera.

local function attachCamera( trackObj, world, params ) params = params or {} local lockX = params.lockX local lockY = params.lockY local lx = 0 local ly = 0 lx = params.lx or trackObj.x ly = params.ly or trackObj.y world.enterFrame = function( event ) local dx = 0 local dy = 0 if(not lockX) then dx = trackObj.x - lx end if(not lockY) then dy = trackObj.y - ly end if(dx ~= 0 or dy ~= 0) then world:translate(-dx,-dy) lx = trackObj.x ly = trackObj.y end return false end Runtime:addEventListener( "enterFrame", world ) world.finalize = function( self ) Runtime:removeEventListener( "enterFrame", self ) end world:addEventListener( "finalize" ) end

Start Tracking Player
The function above supports a few options and you can explore them.  I’ll show a call that matches your usage as I understand it:

-- \> Attach camera code to world and player and start tracking player -- \> Ignore Y movement, only track horizontal movement. -- \> Player may not be in center of screen, so assume it is not and track it at whatever -- offset it is at. attachCamera( player, layers.world, { lockY = true } )

That is it.  This code updates the position of the world group ONLY and thus keeps all the other groups aligned, avoiding the physics problem you are seeing.

**UPDATE** I Modified the camera code above.  I forgot it was using some SSK2 features
 
 
Note: As always, SSK2 supplies code for this kind of thing you may be able to extract:

Final note…

My camera code will not look good if you move the player with transition.*

I don’t know of of any way to make a nice camera to track an object moved with transition.

The issue is that transition.* is out of sync with enterFrame and the expressed X and Y values of objects in the frame.

Why? I have never been able to work it out.

Sorry for all the updates, but I had to ‘purify’ the example and removed all the SSK2 bits and pieces.  I also simplified the camera code a bit for your consumption.

Yes, I have found I can insert character into layer using «map:findLayer(“name”)» function and it works.

Everything needs to be in order. You placed a perfect understandable example, and now I see how this system works!

Top layer I need to handle UI and HUD. Middle layers are filled with players, map, props, gibs, enemies, coins and so on. And lower layer Is for parallaxes and backgrounds. And sub-layers to separate near/far objects. The main detail is that physics is connected to this layering system. In other words physics coordinate counting system will work with object only in the case when they both are in the same group, right?

Tip: You can have layers above world that are children of ‘layers’ and inserted after inserting ‘world’ for your UI elements.

This will float them above world content and they won’t move when the world moves.
 

local layers = display.newGroup() layers.world = display.newGroup() layers.under = display.newGroup() layers.content = display.newGroup() layers.over = display.newGroup() layers.interface = display.newGroup() -- Insert layers into sceneGroup if you're using composer.\* sceneGroup:insert( layers ) layers:insert( layers.world ) layers:insert( layers.interface ) layers.world:insert( layers.under ) layers.world:insert( layers.content ) layers.world:insert( layers.over )

Thank you! Very nice and clean! Copied to my «templates» folder!

Works like a charm!

https://www.youtube.com/watch?v=eZcM9uoA3yA&feature=youtu.be

The issue is that transition.* is out of sync with enterFrame and the expressed X and Y values of objects in the frame.

 

Why? I have never been able to work it out.

 

We can avoid flickering by moving camera and world by adding whole pixels, not halfs or quarters or decimals, only round pixels.

I don’t prefer forces because you can’t control your char very smoothly: or you have no friction, or unnecessary bounce, or your speed up to the mountain versus from the mountain versus speed on flat platform will be very different, or you need to apply greater mass with greater gravity (event in sticker knight gravity is 30), or greater forces to move your object that causes snatches… I retried more than hundred different options for simple platformer and moving by adding (not continuous transition) is smoothest. And also you need to apply different variable forces if player wants to change direction of character while jumping…

Hi.  I typed up an answer then borked it by clicking the wrong button… so this second post will be a little less verbose.  Sorry.
 

  1. Thanks for posting the link.  I did not however look and instead going directly to solution.
     

  2. The trick to making this work is proper display group hierarchy and only moving the parent group, not child groups.
     

  3. If you’re having physics issues, you are changing the alignment of groups relative to each other and this is borking you up.
     

  4. Here is ONE way to do it.
     
    Make The Layers

    local layers = display.newGroup() layers.world = display.newGroup() layers.under = display.newGroup() layers.content = display.newGroup() layers.over = display.newGroup() – Insert layers into sceneGroup if you’re using composer.* sceneGroup:insert( layers ) layers:insert( layers.world ) layers.world:insert( layers.under ) layers.world:insert( layers.content ) layers.world:insert( layers.over ) – Now you have this BOTTOM TO TOP layering all packaged in – layers which has named fields refering to the groups for easy use – sceneGroup – if using composer – VERY BOTTOM – layers – world (child of layers) – under (child of world) – content (child of world) – over (child of world) – VERY TOP

Add Content In Correct Layers
 
Never add content to layers.world.  This is your camera layer and should only contain the child groups we created.

local player = display.newImageRect( layers.content, ... ) -- add body, etc. local ground = display.newImageRect( layers.under, ... ) local cloud = display.newImageRect( layers.over, ... ) local enemy = display.newImageRect( layers.content, ... ) -- add body, etc. .. more as needed

The Camera Code
You are essentially talking about a camera above.  This is a tracking camera.

local function attachCamera( trackObj, world, params ) params = params or {} local lockX = params.lockX local lockY = params.lockY local lx = 0 local ly = 0 lx = params.lx or trackObj.x ly = params.ly or trackObj.y world.enterFrame = function( event ) local dx = 0 local dy = 0 if(not lockX) then dx = trackObj.x - lx end if(not lockY) then dy = trackObj.y - ly end if(dx ~= 0 or dy ~= 0) then world:translate(-dx,-dy) lx = trackObj.x ly = trackObj.y end return false end Runtime:addEventListener( "enterFrame", world ) world.finalize = function( self ) Runtime:removeEventListener( "enterFrame", self ) end world:addEventListener( "finalize" ) end

Start Tracking Player
The function above supports a few options and you can explore them.  I’ll show a call that matches your usage as I understand it:

-- \> Attach camera code to world and player and start tracking player -- \> Ignore Y movement, only track horizontal movement. -- \> Player may not be in center of screen, so assume it is not and track it at whatever -- offset it is at. attachCamera( player, layers.world, { lockY = true } )

That is it.  This code updates the position of the world group ONLY and thus keeps all the other groups aligned, avoiding the physics problem you are seeing.

**UPDATE** I Modified the camera code above.  I forgot it was using some SSK2 features
 
 
Note: As always, SSK2 supplies code for this kind of thing you may be able to extract:

Final note…

My camera code will not look good if you move the player with transition.*

I don’t know of of any way to make a nice camera to track an object moved with transition.

The issue is that transition.* is out of sync with enterFrame and the expressed X and Y values of objects in the frame.

Why? I have never been able to work it out.

Sorry for all the updates, but I had to ‘purify’ the example and removed all the SSK2 bits and pieces.  I also simplified the camera code a bit for your consumption.

Yes, I have found I can insert character into layer using «map:findLayer(“name”)» function and it works.

Everything needs to be in order. You placed a perfect understandable example, and now I see how this system works!

Top layer I need to handle UI and HUD. Middle layers are filled with players, map, props, gibs, enemies, coins and so on. And lower layer Is for parallaxes and backgrounds. And sub-layers to separate near/far objects. The main detail is that physics is connected to this layering system. In other words physics coordinate counting system will work with object only in the case when they both are in the same group, right?

Tip: You can have layers above world that are children of ‘layers’ and inserted after inserting ‘world’ for your UI elements.

This will float them above world content and they won’t move when the world moves.
 

local layers = display.newGroup() layers.world = display.newGroup() layers.under = display.newGroup() layers.content = display.newGroup() layers.over = display.newGroup() layers.interface = display.newGroup() -- Insert layers into sceneGroup if you're using composer.\* sceneGroup:insert( layers ) layers:insert( layers.world ) layers:insert( layers.interface ) layers.world:insert( layers.under ) layers.world:insert( layers.content ) layers.world:insert( layers.over )

Thank you! Very nice and clean! Copied to my «templates» folder!

Works like a charm!

https://www.youtube.com/watch?v=eZcM9uoA3yA&feature=youtu.be

The issue is that transition.* is out of sync with enterFrame and the expressed X and Y values of objects in the frame.

 

Why? I have never been able to work it out.

 

We can avoid flickering by moving camera and world by adding whole pixels, not halfs or quarters or decimals, only round pixels.

I don’t prefer forces because you can’t control your char very smoothly: or you have no friction, or unnecessary bounce, or your speed up to the mountain versus from the mountain versus speed on flat platform will be very different, or you need to apply greater mass with greater gravity (event in sticker knight gravity is 30), or greater forces to move your object that causes snatches… I retried more than hundred different options for simple platformer and moving by adding (not continuous transition) is smoothest. And also you need to apply different variable forces if player wants to change direction of character while jumping…