Physics not updating when moving a group

Hi all -

So I’m having a problem with creating an infinite scrolling level. My player is a dynamic object, and the level objects are static. They are in their own group. This had been working beautifully, however, when I move the group a large distance in a single frame (as I would need to when creating the “conveyer” effect) the physics stays in the old position. It doesn’t update in the debugger, but the player gets stuck on the old position.

The basic principle is this:

  1. Move the game group (player) when the player is flicked upwards (keeps player on screen)
  2. Move the two “platform” groups along with the player (move in opposite direction, to show scrolling)
  3. When the bottom group is offscreen, move it to the top and continue scrolling (like a conveyer)
  • This demonstration should run as is - just hacked it out of my main project. This is NOT using two platform groups yet, rather it moves the only platform group down by 200 units (during the jump) to illustrate the issue. Pull back and release the player, you should see them fly into the air, and on the way down land on the old physics.

I’ve tried both static an kinematic bodies for the platforms… Any ideas?

[lua]-- Setup the game
– Turn off the status bar
display.setStatusBar(display.HiddenStatusBar);

– Setup graphics
local physics = require(“physics”);
physics.start();
physics.setDrawMode(“debug”);
physics.setGravity(0, 9.8);
physics.setScale(60);

– Setup the background group
local gameGroup = display.newGroup();
gameGroup.x = 0;

– Platforms group
local platformGroup1 = display.newGroup();
platformGroup1.x = 0;

– Ground object
local ground = display.newRect(450, 0, 320, 5);
ground.x = 160;
ground.y = 440;
ground.objectType = “ground”
–groundPhysics = { -160, 0, 160, 0, 160, 10, -160, 10 };
physics.addBody(ground, “static”, { friction=1.0, bounce=0.0, shape=groundPhysics });
gameGroup:insert(ground);

– Setup a sprite for the player
playerInstance = display.newRect(100, 423, 32, 32);
playerInstance.x = 100;
playerInstance.y = 400;
gameGroup:insert(playerInstance);
physics.addBody(playerInstance, “dynamic”, { density=0.4, friction=0.15, bounce=0.1 });
playerInstance.isFixedRotation = true;
playerInstance.objectType = “player”;
playerInstance.isBullet = true;

– Setup some vars on the playerInstance
playerInstance.isFalling = false;
playerInstance.xVel = 0;
playerInstance.yVel = 0;

– Jump platforms in the first group
local jumpPlat1Grp1 = display.newRect(150, 200, 50, 10);
jumpPlat1Grp1.objectType = “jumpPlatform”
local jumpPlat2Grp1 = display.newRect(10, 10, 50, 10);
jumpPlat2Grp1.objectType = “jumpPlatform”
local jumpPlat3Grp1 = display.newRect(80, 100, 50, 10);
jumpPlat3Grp1.objectType = “jumpPlatform”

platformGroup1:insert(jumpPlat1Grp1);
physics.addBody(jumpPlat1Grp1, “static”, { friction=0.3} );
platformGroup1:insert(jumpPlat2Grp1);
physics.addBody(jumpPlat2Grp1, “static”, { friction=0.3} );
platformGroup1:insert(jumpPlat3Grp1);
physics.addBody(jumpPlat3Grp1, “static”, { friction=0.3} );
– Use this function when warping a player to avoid physics instability
local function warpPlayerInX(xPosition)

– Store the linear velocity to preserve it later
local xVel, yVel = playerInstance:getLinearVelocity();

playerInstance.bodyType = “kinematic”;
playerInstance:setLinearVelocity(0, 0);
playerInstance.angularVelocity = 0; – Probably not needed since we restrict this

playerInstance.x = xPosition;

playerInstance.bodyType = “dynamic”;
playerInstance:setLinearVelocity(xVel, yVel);

end
– The main loop
local function onEnterFrame(event)

– Move the game world to keep the player onscreen
if playerInstance.y <= 200 then
gameGroup.y = -playerInstance.y + 200;
– THIS IS WHERE I AM DOING THE JUMP - NOTE, the EXTRA 200 AT THE BEGINNING, IS THE TEST VALUE, AS SOON AS THIS IS REMOVED, EVERYTHING WORKS FINE
platformGroup1.y = 200 + (-playerInstance.y + 200);
end

if playerInstance.x < 0 then
warpPlayerInX(320);
elseif playerInstance.x > 320 then
warpPlayerInX(0);
end

end

– When the player makes a tap event
local function onTouch(event)

local t = event.target;
local phase = event.phase;

if phase == “began” then
– Make the object the topmost object
local parent = t.parent;
parent:insert(t);
display:getCurrentStage():setFocus(t);

– Prevents spurious messages being sent
t.isFocus = true;

– Store the initial position
t.x0 = event.x - t.x;
t.y0 = event.y - t.y;

elseif t.isFocus == true then

if phase == “moved” then

elseif phase == “ended” or phase == “cancelled” then

local xForce = (-1 * (event.x - playerInstance.x)) * 0.02;

if (xForce > 0.3) then
xForce = 0.3;
end

local yForce = (-1 * (event.y - playerInstance.y)) * 0.03;
if (yForce < -1.8) then
yForce = -1.8;
end

playerInstance:applyLinearImpulse( 0, yForce, playerInstance.x + 16, playerInstance.y + 32);

display.getCurrentStage():setFocus(nil);
t.isFocus = false;

end

end

end
local function preCol(self, event)

local player = self;
local collidedWith = event.other;

if (collidedWith.objectType == “ground”) then
return true; – We don’t care about the ground
end

– Check to see if the player is above the platform
if (player.y < collidedWith.y) then
return true;
end

print(“preCollision”);

– Set the player to sensor while travelling throuh an object
player.isSensor = true;

end

local function onCollision(self, event)

local player = self;
local collidedWith = event.other;
local phase = event.phase;

if (collidedWith.objectType == “ground”) then
return true; – We don’t care about the ground
end

if (phase == “began”) then
print(collidedWith.objectType…" began");
elseif (phase == “ended”) then
print(collidedWith.objectType…" end");
player.isSensor = false;
end
end

– Setup the event listeners
– Collision event listeners
playerInstance.preCollision = preCol;
playerInstance:addEventListener(“preCollision”, playerInstance);
playerInstance.collision = onCol;
playerInstance:addEventListener(“onCollision”, playerInstance);
playerInstance.collision = onCollision;
playerInstance:addEventListener(“collision”, playerInstance);

– Update event listeners
Runtime:addEventListener(“enterFrame”, onEnterFrame);

– Input event listeners
playerInstance:addEventListener(“touch”, onTouch);[/lua] [import]uid: 41286 topic_id: 17687 reply_id: 317687[/import]

Ah - so I’ve found a reference that seems to indicate that physics objects must all be in the same group… is this correct? This seems like a rather limiting restriction… [import]uid: 41286 topic_id: 17687 reply_id: 67456[/import]

Hi foniks - you would be correct about not placing physics objects in different groups;

_When working with Corona display groups and Box2D, it is important to keep in mind that Box2D expects all physics objects to share a global coordinate system. This means that a set of ungrouped Corona objects will work well, and a set of objects that are all added to the same display group should also work, since they will share the internal coordinates of that group – this is demonstrated in the “EggBreaker” sample code, which uses a single moving display group to create a “moving camera” effect.

However, unexpected results may occur if physical objects are added to different display groups, especially if the groups are then moved in different directions. The “hybrid” draw mode makes these issues much easier to diagnose, since it lets you overlay the physics engine’s collision boxes and shapes on top of the Corona renderer._

Link: http://developer.anscamobile.com/content/game-edition-box2d-physics-engine

Peach [import]uid: 52491 topic_id: 17687 reply_id: 67495[/import]

Thanks for that - that clarifies the issue.

Actually the Hybrid draw mode made things more confusing, as it didn’t accurately update the physics objects at all. So the colliding object looked like it was floating in mid air. [import]uid: 41286 topic_id: 17687 reply_id: 67693[/import]