Changing A Sprite's Mind?

Hey Dyson - apologies for yet another question :slight_smile:

Having a few problems with my AI and Pathfinding/Field of View Implementation.

Currently I have a bot who wanders around a Map using moveSpriteTo(); however when the Bot detects the player I generate a new array of steps and call moveSpriteTo() with the new waypoint.

The problem however is that when it reaches moveSpriteTo(), it obviously fails on the following condition:

[lua]

if not objects[parameters.sprite].isMoving and holdSprite ~= parameters.sprite then

[/lua]

I believe that the sprite is obviously still moving from the previous call and the isMoving flag is set to true. 

So is there anyway to “interrupt” a current Move; I was thinking of adding a method that toggles this property, but just wanted to check whether there was an “official” way or if I’m just doing something really stupid.

Many thanks,

Dammit - just noticed cancelSpriteMove; haven’t check it yet, but I guess the clue is in the title :slight_smile:

I wish there was a like button on corona so I could like your last sentence, haha!

I wish there was a like button on corona so I could like your last sentence, haha!

I am having problems with:

cancelSpriteMove

sendSpriteTo

and

moveSpriteTo

How can I move a sprite to a fixed position without calling moveSpriteTo. I need a function that will update the sprite position immediately as I am using custom easing functions. moveSpriteTo is time based so doesn’t give the frame based control over movement that I need and sendSpriteTo is very unpredictable as the position I send a sprite to only seems to be updated if i call moveSpriteTo afterward.

 calling cancelspritemove then moveSpriteTo in that order  seems to fail when the sprite is a certain positions within the map. (sprite moves to a random position or doesn’t move at all, or randomly jumps to desired position after a successive moveSpriteTo call )

I think I remember sendSpriteTo working nicely before I repositioned the camera (i.e I was able to use sendSpriteTo to move the sprite each frame without error). But after moving camera I am forced to use the moveSpriteTo and cancelspritemove which in turn introduces the unpredictable behaviour.

UPDATE-- seems that the desired Y coordinate is being capped when the sprite is located at lower Y  positions within map, in these positions moveSpriteTo only moves the character to the supplied X coord. But past a certain Y value both X and Y positions are being updated as expected.

Best,

Steven

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: !

I am having problems with:

cancelSpriteMove

sendSpriteTo

and

moveSpriteTo

How can I move a sprite to a fixed position without calling moveSpriteTo. I need a function that will update the sprite position immediately as I am using custom easing functions. moveSpriteTo is time based so doesn’t give the frame based control over movement that I need and sendSpriteTo is very unpredictable as the position I send a sprite to only seems to be updated if i call moveSpriteTo afterward.

 calling cancelspritemove then moveSpriteTo in that order  seems to fail when the sprite is a certain positions within the map. (sprite moves to a random position or doesn’t move at all, or randomly jumps to desired position after a successive moveSpriteTo call )

I think I remember sendSpriteTo working nicely before I repositioned the camera (i.e I was able to use sendSpriteTo to move the sprite each frame without error). But after moving camera I am forced to use the moveSpriteTo and cancelspritemove which in turn introduces the unpredictable behaviour.

UPDATE-- seems that the desired Y coordinate is being capped when the sprite is located at lower Y  positions within map, in these positions moveSpriteTo only moves the character to the supplied X coord. But past a certain Y value both X and Y positions are being updated as expected.

Best,

Steven