Here's the code that enables a camera system like the Color Switch

********* Update (7/19/2016) **********

After 3 frustrating weeks of not being able to build a camera system like the one in Color Switch, I finally got it! The camera system I built follows the player only when the player is at the center, but doesn’t if it’s below it.

It took me at least twelve different variations and approximately 50 hours to get this to work. I almost felt like quitting my project because I couldn’t figure out why there was always a gap between the object and the center in my old code. But now I have it and the code is in my most recent post down below for anybody to use. The key here is to never give up and never give in.

May you all succeed in your projects.

-Dan

********* Previous Note (7/10/2016) **************

I am developing a camera movement that follows the player object only when its top touches the center line of the display. To visuathat the camera movement activates at the right moment, I have created a center line. But for whatever reason, the camera movement activates even before the object touches the center line, sometimes 2 to 4 pixels prior to reaching the center line. There’s usually a gap for a brief moment then it snaps to the midline.

Here’s the code:

----------------------------------------------------------------------------------------- -- Camera Module ----------------------------------------------------------------------------------------- local physics = require "physics" physics.start() physics.setDrawMode( "hybrid" ) physics.setGravity( 0, 20 ) local cX, cY = display.contentCenterX, display.contentCenterY local w, h = display.contentWidth, display.contentHeight local worldGrp = display.newGroup() worldGrp.anchorX = 0.5; worldGrp.anchorY = 1 worldGrp.x = cX; worldGrp.y = h local platform = display.newRect( worldGrp, 0, 0, w, 30) platform.anchorX = 0.5; platform.anchorY = 1; physics.addBody( platform, "static" , { bounce = 0 }) local boxJump = display.newRect( worldGrp, 0, -50 , 50, 50 ); boxJump.anchorY = 0; physics.addBody( boxJump, "dynamic", { density = 1, bounce = 0 }) boxJump.isFixedRotation = true local topHalfArea = display.newRect( cX, cY, w, h/2 ) topHalfArea.anchorY = 1 topHalfArea:setFillColor( 0, 0, 0, 0.5) local function jump( event ) if event.phase == "began" then boxJump:applyLinearImpulse( 0, -60, boxJump.x, boxJump.y ) end return true end Runtime:addEventListener( "touch", jump ) -- Dear Readers: The problem Starts Here \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* local camera = {} function camera.init( object ) object.startY = object.y end local centerLine = display.newRect( worldGrp, 0, -cY, w, 1) local center = -cY function camera.update( object, world ) -- Calculate how far we moved last frame local dY = object.y - object.startY --\*\* -- Save our new "last" position object.startY = object.y -- If object top reaches the midpoint of the display, then move the world if object.y \<= center then world.y = world.y - dY center = center + dY -- Update Center centerLine.y = center -- Update Center Line for Display end end camera.init( boxJump ) boxJump.enterFrame = function( self ) camera.update( self, worldGrp ) end Runtime:addEventListener( "enterFrame", boxJump )

To assist your understanding of this issue, I have also collected some enterframe data about what is exactly happening frame by frame in a simulation run. Shown below, each frame displays the Y-positions of the player object and the center. Both the player object and the center line are placed in a display group with Y anchor being 1 and the default position being display.contentHeight so as a quick demonstration, here it is:

      – Crude Demonstration of the Display


  •                                          -

-                                          -

-                                          -

-                                          -

------------------------------------- -240 = Center-Y

-                                          -

-                                          -

-                                          -

-                                          -

------------------------------------- 0 = Starting Point

Now, the first two frames show positional data just before the top of the player object reaches the center. The last one is when it “reaches” the center and additional data is displayed. At this part, it doesn’t make any sense. The player object is at -272 rounded in y-position, so technically it should be placed above the midline which is is at -240. But, in display, it’s always below the midline and there’s a gap. No matter how many simulations I run, this anomaly is always present. What is causing this and what is your input on fixing this?

19:59:28.444  New Frame
19:59:28.444  dY is:    -17.599990844727
19:59:28.444  object is currently at:    -196.04893493652
19:59:28.444  center is currently at:    -240

19:59:28.491  New Frame
19:59:28.491  dY is:    -38.533325195313
19:59:28.491  object is currently at:    -234.58226013184
19:59:28.491  center is currently at:    -240

19:59:28.522  New Frame
19:59:28.522  dY is:    -37.866653442383
19:59:28.522  object is currently at:    -272.44891357422
19:59:28.522  center is currently at:    -240
19:59:28.522  object is at    -272.44891357422
19:59:28.522  center before Update:    -240
19:59:28.522  center after Update:    -277.86665344238
 

The code is:

function camera.update( object, world ) --print( boxJump.y ) -- Calculate how far we moved last frame print("New Frame") local dY = object.y - object.startY --\*\* print("dY is:", dY) -- Save our new "last" position object.startY = object.y print("object is currently at:", object.y) print("center is currently at:", center) -- If object crossed the displays midpoint, then move the world if object.y \<= center then print("center before Update:", center ) world.y = world.y - dY --center = object.y center = center + dY print("center after Update:", center) centerLine.y = center print( dy+ d2) -- Error deliberately placed to stop the frame when the player "reaches" the midline print("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*") end end

This is not being ignored. I don’t think should be in the newbie questions. I am just don’t have the will power right now. :) 

Haha I understand. I just wanted to be thorough for the sake of being clear with my problem. But, I guess too much information can throw people off too.

It’s quite frustrating though. I’ve been trying to resolve this issue for days right now and I made barely any progress in the first mobile game I’m working on as a result of this. Some motivational feedback from peeps is much appreciated too :slight_smile:

I don’t know if this will help at all but here you go. I did not write this code but I use it for my camera system
https://gist.github.com/GymbylCoding/8675733

I’ve looked at that and it doesn’t seem to help :confused: Have you tried copying and pasting the code into the simulator to see if you get the same issue? I’m wondering if it’s just some glitch with my simulator that’s producing a gap and snap.

Fixed set fps to 60 in config.lua

I got it! I finally fixed it! The 60 fps won’t actually cut it since gaps will still occur when object velocity is high. What was ultimately the cause was how delta Y was calculated to set the position of the midline and transform the world.

delta Y calculation had to be done after the object crosses the center line, and the calculation is done by taking the difference of the object.y and centerline.y, not by taking the difference between the y coordinate of the object at one frame and the previous frame.

Here’s the code sample that fixes the gap issue and produces a smooth running camera operation similar to Color Switch. The background file is also attached below the code.

----------------------------------------------------------------------------------------- -- Camera Module Sample that Works Like "Color Switch" ----------------------------------------------------------------------------------------- local physics = require "physics" physics.start() physics.setDrawMode( "hybrid" ) physics.setGravity( 0, 10 ) local cX, cY = display.contentCenterX, display.contentCenterY local w, h = display.contentWidth, display.contentHeight local worldGrp = display.newGroup() worldGrp.anchorX = 0.5; worldGrp.anchorY = 1 worldGrp.x = cX; worldGrp.y = h local whiteBackground = display.newRect( worldGrp, 0, 0, w, h \* 6 ) whiteBackground.anchorX = 0.5; whiteBackground.anchorY = 1; whiteBackground.x = 0; whiteBackground.y = 0 local background = display.newImageRect( worldGrp, "bg-test.png", w, h \* 6 ) background.anchorX = 0.5; background.anchorY = 1; background.x = 0; background.y = 0 local platform = display.newRect( worldGrp, 0, 0, w, 5) platform.anchorX = 0.5; platform.anchorY = 1; physics.addBody( platform, "static" , { bounce = 0 }) local boxJump = display.newRect( worldGrp, 0, -50 , 50, 50 ); boxJump.anchorY = 0; physics.addBody( boxJump, "dynamic", { density = 1, bounce = 0 }) boxJump.isFixedRotation = true local topHalfArea = display.newRect( cX, cY, w, h/2 ) topHalfArea.anchorY = 1 topHalfArea:setFillColor( 0, 0, 0, 0.5) local function jump( event ) if event.phase == "began" then boxJump:applyLinearImpulse( 0, -30, boxJump.x, boxJump.y ) end return true end Runtime:addEventListener( "touch", jump ) local camera = {} function camera.init( object ) object.startY = object.y end local centerLine = display.newRect( worldGrp, 0, -cY, w, 0.5) physics.addBody( centerLine, "static", { isSensor = true }) local center = -cY function camera.update( object, world ) if object.y \< centerLine.y then local dY = object.y - centerLine.y centerLine.y = centerLine.y + dY world.y = world.y - dY end end

Nice :slight_smile:

The sample code looked good at 60 fps so I assumed that was the fix

To assist your understanding of this issue, I have also collected some enterframe data about what is exactly happening frame by frame in a simulation run. Shown below, each frame displays the Y-positions of the player object and the center. Both the player object and the center line are placed in a display group with Y anchor being 1 and the default position being display.contentHeight so as a quick demonstration, here it is:

      – Crude Demonstration of the Display


  •                                          -

-                                          -

-                                          -

-                                          -

------------------------------------- -240 = Center-Y

-                                          -

-                                          -

-                                          -

-                                          -

------------------------------------- 0 = Starting Point

Now, the first two frames show positional data just before the top of the player object reaches the center. The last one is when it “reaches” the center and additional data is displayed. At this part, it doesn’t make any sense. The player object is at -272 rounded in y-position, so technically it should be placed above the midline which is is at -240. But, in display, it’s always below the midline and there’s a gap. No matter how many simulations I run, this anomaly is always present. What is causing this and what is your input on fixing this?

19:59:28.444  New Frame
19:59:28.444  dY is:    -17.599990844727
19:59:28.444  object is currently at:    -196.04893493652
19:59:28.444  center is currently at:    -240

19:59:28.491  New Frame
19:59:28.491  dY is:    -38.533325195313
19:59:28.491  object is currently at:    -234.58226013184
19:59:28.491  center is currently at:    -240

19:59:28.522  New Frame
19:59:28.522  dY is:    -37.866653442383
19:59:28.522  object is currently at:    -272.44891357422
19:59:28.522  center is currently at:    -240
19:59:28.522  object is at    -272.44891357422
19:59:28.522  center before Update:    -240
19:59:28.522  center after Update:    -277.86665344238
 

The code is:

function camera.update( object, world ) --print( boxJump.y ) -- Calculate how far we moved last frame print("New Frame") local dY = object.y - object.startY --\*\* print("dY is:", dY) -- Save our new "last" position object.startY = object.y print("object is currently at:", object.y) print("center is currently at:", center) -- If object crossed the displays midpoint, then move the world if object.y \<= center then print("center before Update:", center ) world.y = world.y - dY --center = object.y center = center + dY print("center after Update:", center) centerLine.y = center print( dy+ d2) -- Error deliberately placed to stop the frame when the player "reaches" the midline print("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*") end end

This is not being ignored. I don’t think should be in the newbie questions. I am just don’t have the will power right now. :) 

Haha I understand. I just wanted to be thorough for the sake of being clear with my problem. But, I guess too much information can throw people off too.

It’s quite frustrating though. I’ve been trying to resolve this issue for days right now and I made barely any progress in the first mobile game I’m working on as a result of this. Some motivational feedback from peeps is much appreciated too :slight_smile:

I don’t know if this will help at all but here you go. I did not write this code but I use it for my camera system
https://gist.github.com/GymbylCoding/8675733

I’ve looked at that and it doesn’t seem to help :confused: Have you tried copying and pasting the code into the simulator to see if you get the same issue? I’m wondering if it’s just some glitch with my simulator that’s producing a gap and snap.

Fixed set fps to 60 in config.lua

I got it! I finally fixed it! The 60 fps won’t actually cut it since gaps will still occur when object velocity is high. What was ultimately the cause was how delta Y was calculated to set the position of the midline and transform the world.

delta Y calculation had to be done after the object crosses the center line, and the calculation is done by taking the difference of the object.y and centerline.y, not by taking the difference between the y coordinate of the object at one frame and the previous frame.

Here’s the code sample that fixes the gap issue and produces a smooth running camera operation similar to Color Switch. The background file is also attached below the code.

----------------------------------------------------------------------------------------- -- Camera Module Sample that Works Like "Color Switch" ----------------------------------------------------------------------------------------- local physics = require "physics" physics.start() physics.setDrawMode( "hybrid" ) physics.setGravity( 0, 10 ) local cX, cY = display.contentCenterX, display.contentCenterY local w, h = display.contentWidth, display.contentHeight local worldGrp = display.newGroup() worldGrp.anchorX = 0.5; worldGrp.anchorY = 1 worldGrp.x = cX; worldGrp.y = h local whiteBackground = display.newRect( worldGrp, 0, 0, w, h \* 6 ) whiteBackground.anchorX = 0.5; whiteBackground.anchorY = 1; whiteBackground.x = 0; whiteBackground.y = 0 local background = display.newImageRect( worldGrp, "bg-test.png", w, h \* 6 ) background.anchorX = 0.5; background.anchorY = 1; background.x = 0; background.y = 0 local platform = display.newRect( worldGrp, 0, 0, w, 5) platform.anchorX = 0.5; platform.anchorY = 1; physics.addBody( platform, "static" , { bounce = 0 }) local boxJump = display.newRect( worldGrp, 0, -50 , 50, 50 ); boxJump.anchorY = 0; physics.addBody( boxJump, "dynamic", { density = 1, bounce = 0 }) boxJump.isFixedRotation = true local topHalfArea = display.newRect( cX, cY, w, h/2 ) topHalfArea.anchorY = 1 topHalfArea:setFillColor( 0, 0, 0, 0.5) local function jump( event ) if event.phase == "began" then boxJump:applyLinearImpulse( 0, -30, boxJump.x, boxJump.y ) end return true end Runtime:addEventListener( "touch", jump ) local camera = {} function camera.init( object ) object.startY = object.y end local centerLine = display.newRect( worldGrp, 0, -cY, w, 0.5) physics.addBody( centerLine, "static", { isSensor = true }) local center = -cY function camera.update( object, world ) if object.y \< centerLine.y then local dY = object.y - centerLine.y centerLine.y = centerLine.y + dY world.y = world.y - dY end end

Nice :slight_smile:

The sample code looked good at 60 fps so I assumed that was the fix