Changing A Sprite's Mind?

You can move a sprite by a set number of pixels in a single frame with moveSprite(sprite, velX, velY), however as with the rest of the movement functions this isn’t processed until mte.update() executes. The same goes for sendSpriteTo; the screen position of the sprite won’t update until mte.update() executes.

As for the Y coordinate being capped, is this happening when you try to move the sprite outside of the map? It sounds like something is still constraining its position. Is the X coordinate similarly capped when you move to high or low X  positions as well?

hey dyson,

Thanks for the reply, i had started another topic, with same issue (i didn’t notice the reply here).

Yes I agree, I think for some reason the Y movement is being capped. 

the game I am writing is like frogger.  Where the user starts at the bottom of the screen/ level and hops through a number of lanes to get to the top.

The movement that hops the player around works fine. The error appears to happen when the player dies at certain positions in the map. This is when I call cancelSpriteMove (just incase player is moving) then moveSpriteTo move the player back to the spawn point.

I think the problem may have to do with the distance the player has to move when he dies. normal movement of player only causes limited X/Y movement in calls to moveSpriteTo. movement is also limited when player dies lower down in the level. The problem occurs when player dies when he is higher up in the map. cancelSpriteMove/ moveSpriteTo gets called as above but at  these higher positions the Y value of sprite does not change.  What happens is the player moves to desired X coord but the Y does not change. Strangely the sprite will sometimes jump to the spawn point, on successive calls to moveSpriteTo.

Any ideas why?

UPDATE: Misread the end of your message, I will test out the X movement and see if it is capped when moving a similar distance to that which is presented in the Y movement,during mentioned failure cases.

Best,

Steven 

Yes, I can confirm, that the failure to update either the X or Y coordinate when calling MoveSpriteTo is dependent upon the distance. I start experiencing failure at distances of  5* CELL_WIDTH and above.

The fact that it fails at 5* CELL WIDTH and above may be due to the fact that this distance exceeds 1/2 of the view able area in given dimension ? The view-able area in my game is approx 8* CELL_WIDTH. CELL_WIDTH being 32px, HD 64px@2x, SUPER HD 128px@4x

this cant be right

Well, that tells me where the problem is starting, but I’m not having much success duplicating it on my end. If you’re willing to email your project to me I’ll have a look at it.

Hey I can’t send over clients source,but ill try to put together a simple project to replicate issue. 

ok, I have spent morning rebuilding a demo app to demonstrate this problem. What I have found is that the problem occurs when I try to move the player as a result of a box2d collision. 

Ive tried setting a timer and moving the player after some time has passed, but this doesn’t seem to fix the problem.

What I will try to do next is remove the physics body from the sprite then add a new one  after the respawn has occured.

below is code that presents the problem

\_G.w = display.contentWidth \_G.h = display.contentHeight \_G.W = display.contentWidth \_G.H = display.contentHeight \_G.centerX = w/2 \_G.centerY = h/2 \_G.displayWidth = (display.contentWidth - display.screenOriginX\*2) \_G.displayHeight = (display.contentHeight - display.screenOriginY\*2) \_G.unusedWidth = \_G.displayWidth - \_G.w \_G.unusedHeight = \_G.displayHeight - \_G.h local vehicleCollisionFilter = nil--{ categoryBits = 1, maskBits = 16 }; local playerCollisionFilter = nil--{ categoryBits = 2, maskBits = 14 }; local DPad = require("dpad") --load map local mte = require("mte") mte.enableBox2DPhysics() mte.physics.start() mte.physics.setGravity(0, 0) mte.physics.setDrawMode("hybrid") mte.loadTileSet("newyork\_bg\_tiles", "newyork\_bg\_tiles.png") mte.loadTileSet("newyork\_objects", "newyork\_objects.png") mte.loadMap("new\_york") -- load dpad local dpad = DPad.create(0, \_G.displayHeight-30) dpad.isVisible = true --go to correct position on map local map = mte.getMap(); local marg = 400; local CELL\_WIDTH = 64; mte.goto({locX = 1, locY = 1, blockScaleX = 64, blockScaleY = 64, cullingMargin={top=marg,left=marg, right=marg, bottom=marg }}); local diffHeight = ((map.height)\*CELL\_WIDTH) - \_G.displayHeight ; mte.moveCameraTo({levelPosX = (map.width\*CELL\_WIDTH)/2, levelPosY = (((map.height)\*CELL\_WIDTH)/2 )+(diffHeight/2), time=1, easing="linear"}); -- add circle/player to mte local circle = display.newCircle(10,10,10); local setup ={ name = "circle", kind = "sprite", layer = 1, locX = 12, locY =13, levelWidth = circle.width , levelHeight = circle.height } mte.addSprite(circle,setup) -- set up physics for circle/player local halfwidth = 8; local halfheight =8; local playerShape = { halfwidth, halfheight , -halfwidth, halfheight , -halfwidth, -halfheight , halfwidth, -halfheight } mte.physics.addBody( circle,"dynamic", {friction = 0.2, bounce = 0.0, density = 1, shape = playerShape, filter = playerCollisionFilter, isSensor=true, isBullet=true }) circle.isFixedRotation = true circle.isSensor = true; circle.isBodyActive = true circle.objectType = "player" function collisionHandler( event ) if event.phase == "began" then local type1 = event.target.objectType local type2 = event.other.objectType print("collisionHandler " .. type2); if(type2=="vehicle") then local gotopos = mte.convert("locToLevelPos", 12, 13, 1) mte.moveSpriteTo({levelPosX=gotopos.x, levelPosY=gotopos.y,sprite=circle,time=1 }) elseif (type2=="pickup") then end end end circle:addEventListener ( "collision", collisionHandler ) function createCollidableVehicle(locx,locy,name) local circleVeh = display.newCircle(10,10,15); local halfwidth = 16; local halfheight =16; local playerShape = { halfwidth, halfheight , -halfwidth, halfheight , -halfwidth, -halfheight , halfwidth, -halfheight } --circleVeh:setFillColor(255,0,0) local setup ={ name = name, kind = "sprite", layer = 1, locX = locx, locY =locy, levelWidth = circleVeh.width , levelHeight = circleVeh.height } mte.addSprite(circleVeh,setup) mte.physics.addBody( circleVeh,"dynamic", {friction = 0.2, bounce = 0.0, density = 1, shape = playerShape, filter = vehicleCollisionFilter, isSensor=true, isBullet=true }) circleVeh.isFixedRotation = true circleVeh.isSensor = true; circleVeh.isBodyActive = true circleVeh.objectType = "vehicle" end -- create static collidable vehicles createCollidableVehicle(9,9,"vehicle1"); createCollidableVehicle(8,9,"vehicle2"); createCollidableVehicle(6,9,"vehicle3"); createCollidableVehicle(5,9,"vehicle4"); --START--------------UTILITY FUNCTIONS------------------------- function pointAngle(xA, yA, xB, yB) local angle = math.atan2(yB - yA, xB - xA) if (angle \< 0) then angle = math.abs(angle) else angle = 2 \* math.pi - angle end return math.deg(angle) end -- Distance between two given points function pointDistance(xA, yA, xB, yB) local xDistance = xB - xA local yDistance = yB - yA return math.sqrt((xDistance \* xDistance) + (yDistance \* yDistance)) end -- Is a point inside a circle? function pointInCircle(xA, yA, xCircle, yCircle, radiusCircle) return (pointDistance(xCircle, yCircle, xA, yA) \<= radiusCircle) end --END--------------UTILITY FUNCTIONS------------------------- local offset = 20; --move object function move (player, angle) local newX = player.locX; local newY =player.locY; local jumpDistance = 1; if((angle \>= 315 and angle \<= 359) or (angle \>=0 and angle \<= 45)) then newX = player.locX + jumpDistance; elseif (angle \<= 315 and angle \>= 225) then newY = player.locY + jumpDistance; elseif (angle \<= 225 and angle \>= 135) then newX = player.locX - jumpDistance; elseif (angle \>= 45 and angle \<= 135) then newY = player.locY - jumpDistance; end print("moveSpriteTo locX " ..newX .." locY " ..newY ) local gotopos = mte.convert("locToLevelPos", newX, newY, 1) mte.moveSpriteTo({levelPosX=gotopos.x-offset, levelPosY=gotopos.y-offset,sprite=player,time=1}) end ---handle touches on dpad and move player local function touchManager(event) if (event.phase == "began") then end if (event.phase == "cancelled" or event.phase == "ended") then print("click") if( pointInCircle(event.x, event.y, dpad.x, dpad.y, 50) )then local angle = DPad.getAngle(dpad, event) print(angle); if(angle) then move(circle, angle) else print("respawn"); local gotopos = mte.convert("locToLevelPos", 12, 13, 1) mte.moveSpriteTo({levelPosX=gotopos.x-offset, levelPosY=gotopos.y-offset,sprite=circle,time=1 }) end end end return true end Runtime:addEventListener("touch", touchManager) --do game loop local g\_timelast = 0; --[[the main game Loop]]-- local function dogameloop() local tm = system.getTimer(); local millisecondspassed = tm-g\_timelast; local dt = (millisecondspassed) / (1000/30); g\_timelast =tm; mte.update(); end Runtime:addEventListener ( "enterFrame", dogameloop );

ok here is the fix: note the essential physics.removeBody call in  collisionHandler function

\_G.w = display.contentWidth \_G.h = display.contentHeight \_G.W = display.contentWidth \_G.H = display.contentHeight \_G.centerX = w/2 \_G.centerY = h/2 \_G.displayWidth = (display.contentWidth - display.screenOriginX\*2) \_G.displayHeight = (display.contentHeight - display.screenOriginY\*2) \_G.unusedWidth = \_G.displayWidth - \_G.w \_G.unusedHeight = \_G.displayHeight - \_G.h local vehicleCollisionFilter = nil--{ categoryBits = 1, maskBits = 16 }; local playerCollisionFilter = nil--{ categoryBits = 2, maskBits = 14 }; local DPad = require("dpad") --load map local mte = require("mte") mte.enableBox2DPhysics() mte.physics.start() mte.physics.setGravity(0, 0) mte.physics.setDrawMode("hybrid") mte.loadTileSet("newyork\_bg\_tiles", "newyork\_bg\_tiles.png") mte.loadTileSet("newyork\_objects", "newyork\_objects.png") mte.loadMap("new\_york") -- load dpad local dpad = DPad.create(0, \_G.displayHeight-30) dpad.isVisible = true --go to correct position on map local map = mte.getMap(); local marg = 400; local CELL\_WIDTH = 64; mte.goto({locX = 1, locY = 1, blockScaleX = 64, blockScaleY = 64, cullingMargin={top=marg,left=marg, right=marg, bottom=marg }}); local diffHeight = ((map.height)\*CELL\_WIDTH) - \_G.displayHeight ; mte.moveCameraTo({levelPosX = (map.width\*CELL\_WIDTH)/2, levelPosY = (((map.height)\*CELL\_WIDTH)/2 )+(diffHeight/2), time=1, easing="linear"}); -- add circle/player to mte local circle = display.newCircle(10,10,10); local setup ={ name = "circle", kind = "sprite", layer = 1, locX = 12, locY =13, levelWidth = circle.width , levelHeight = circle.height } mte.addSprite(circle,setup) -- set up physics for circle/player local halfwidth = 8; local halfheight =8; local playerShape = { halfwidth, halfheight , -halfwidth, halfheight , -halfwidth, -halfheight , halfwidth, -halfheight } function addPlayerPhysics() mte.physics.addBody( circle,"dynamic", {friction = 0.2, bounce = 0.0, density = 1, shape = playerShape, filter = playerCollisionFilter, isSensor=true, isBullet=true }) circle.isFixedRotation = true circle.isSensor = true; circle.isBodyActive = true circle.objectType = "player" end addPlayerPhysics(); function collisionHandler( event ) if event.phase == "began" then local type1 = event.target.objectType local type2 = event.other.objectType print("collisionHandler " .. type2); if(type2=="vehicle") then timer.performWithDelay( 50, function() mte.physics.removeBody(circle); local gotopos = mte.convert("locToLevelPos", 12, 13, 1) mte.moveSpriteTo({levelPosX=gotopos.x, levelPosY=gotopos.y,sprite=circle,time=1 }) timer.performWithDelay( 50, function() addPlayerPhysics() end); end); elseif (type2=="pickup") then end end end circle:addEventListener ( "collision", collisionHandler ) function createCollidableVehicle(locx,locy,name) local circleVeh = display.newCircle(10,10,15); local halfwidth = 16; local halfheight =16; local playerShape = { halfwidth, halfheight , -halfwidth, halfheight , -halfwidth, -halfheight , halfwidth, -halfheight } --circleVeh:setFillColor(255,0,0) local setup ={ name = name, kind = "sprite", layer = 1, locX = locx, locY =locy, levelWidth = circleVeh.width , levelHeight = circleVeh.height } mte.addSprite(circleVeh,setup) mte.physics.addBody( circleVeh,"dynamic", {friction = 0.2, bounce = 0.0, density = 1, shape = playerShape, filter = vehicleCollisionFilter, isSensor=true, isBullet=true }) circleVeh.isFixedRotation = true circleVeh.isSensor = true; circleVeh.isBodyActive = true circleVeh.objectType = "vehicle" end -- create static collidable vehicles createCollidableVehicle(9,9,"vehicle1"); createCollidableVehicle(8,9,"vehicle2"); createCollidableVehicle(6,9,"vehicle3"); createCollidableVehicle(5,9,"vehicle4"); --START--------------UTILITY FUNCTIONS------------------------- function pointAngle(xA, yA, xB, yB) local angle = math.atan2(yB - yA, xB - xA) if (angle \< 0) then angle = math.abs(angle) else angle = 2 \* math.pi - angle end return math.deg(angle) end -- Distance between two given points function pointDistance(xA, yA, xB, yB) local xDistance = xB - xA local yDistance = yB - yA return math.sqrt((xDistance \* xDistance) + (yDistance \* yDistance)) end -- Is a point inside a circle? function pointInCircle(xA, yA, xCircle, yCircle, radiusCircle) return (pointDistance(xCircle, yCircle, xA, yA) \<= radiusCircle) end --END--------------UTILITY FUNCTIONS------------------------- local offset = 20; --move object function move (player, angle) local newX = player.locX; local newY =player.locY; local jumpDistance = 1; if((angle \>= 315 and angle \<= 359) or (angle \>=0 and angle \<= 45)) then newX = player.locX + jumpDistance; elseif (angle \<= 315 and angle \>= 225) then newY = player.locY + jumpDistance; elseif (angle \<= 225 and angle \>= 135) then newX = player.locX - jumpDistance; elseif (angle \>= 45 and angle \<= 135) then newY = player.locY - jumpDistance; end print("moveSpriteTo locX " ..newX .." locY " ..newY ) local gotopos = mte.convert("locToLevelPos", newX, newY, 1) mte.moveSpriteTo({levelPosX=gotopos.x-offset, levelPosY=gotopos.y-offset,sprite=player,time=1}) end ---handle touches on dpad and move player local function touchManager(event) if (event.phase == "began") then end if (event.phase == "cancelled" or event.phase == "ended") then print("click") if( pointInCircle(event.x, event.y, dpad.x, dpad.y, 50) )then local angle = DPad.getAngle(dpad, event) print(angle); if(angle) then move(circle, angle) else print("respawn"); local gotopos = mte.convert("locToLevelPos", 12, 13, 1) mte.moveSpriteTo({levelPosX=gotopos.x-offset, levelPosY=gotopos.y-offset,sprite=circle,time=1 }) end end end return true end Runtime:addEventListener("touch", touchManager) --do game loop local g\_timelast = 0; --[[the main game Loop]]-- local function dogameloop() local tm = system.getTimer(); local millisecondspassed = tm-g\_timelast; local dt = (millisecondspassed) / (1000/30); g\_timelast =tm; mte.update(); end Runtime:addEventListener ( "enterFrame", dogameloop );

I’m glad you found a solution!

Could you email me the demo app you built to debug this problem? It should be possible to alter the engine so that removing the physics body isn’t necessary, but I can’t seem to reproduce the problem on my end.

yes, what is your email address?

Best,

Steven

My email address is dyson122 (at) hotmail.com.

email sent with attachment bugexample.zip.

/s

Thanks steven3,

I’ve found the cause of the problem and I’m in the process of fixing it now. You will still need to allow a small delay for the Physics API to finish resolving the collision, but it won’t be necessary to remove the physics body. The workaround as you wrote it should still work as well, if you’d rather not go back and change it later.

great stuff :slight_smile: !