Bug: "<object>.isBodyActive = false" doesn't seem to work

I’ve noted one issue with my game now that I’m porting it to MTE.  It relies on setting the main player physics body off, then back on, at certain points in the game.  It does this successfully pre-MTE using “player.isBodyActive = false”.  

With MTE it doesn’t seem to work.  I replicated this in the MTE example:  Platformer-BasicPHYSICS0v984-7

If you “player.isBodyActive = false” you note the body still has physic enabled.

mte.physics.addBody(player, "dynamic", {friction = 0.2, bounce = 0.0, density = 1, filter = { categoryBits = 1, maskBits = 1 } }) player.isFixedRotation = true player.isBodyActive = false &nbsp;-- \<== SET IT HERE

Is it possible to get a fix for this Dyson?  (or if I’m missing something let me know)

I’ll have to look into that on my end. MTE turns objects on and off depending on their screen position, so if the object’s onscreen the engine’s turning it back on every time you try to turn it off. I’ll have to figure out some way to differentiate between the player’s input and the engine’s, but it should be doable. I’ll have more information on that as I start to update the relevant section of code.

EDIT:

I’ll be adding an option to completely disable the engine’s automated physics state management so that a physics object will stay on or off as set by the player no matter where it is on the screen. If you don’t want to wait you can go into mte.lua and comment out everything from line 9869 to 9924:

--Handle Offscreen Physics if object.bodyType and masterGroup[i].vars.camera then if object.offscreenPhysics then local tempX, tempY = masterGroup.parent:localToContent(object.contentBounds.xMin, object.contentBounds.yMin) local leftTop = {masterGroup[i]:contentToLocal(tempX, tempY)} tempX, tempY = masterGroup.parent:localToContent(object.contentBounds.xMax, object.contentBounds.yMax) local rightBottom = {masterGroup[i]:contentToLocal(tempX, tempY)} left = math.ceil(leftTop[1] / map.tilewidth) - 1 top = math.ceil(leftTop[2] / map.tileheight) - 1 right = math.ceil(rightBottom[1] / map.tilewidth) + 1 bottom = math.ceil(rightBottom[2] / map.tileheight) + 1 if not object.bounds or (object.bounds[1] ~= left or object.bounds[2] ~= top or object.bounds[3] ~= right or object.bounds[4] ~= bottom) then if object.physicsRegion then for p = 1, #object.physicsRegion, 1 do local lx = object.physicsRegion[p][1] local ly = object.physicsRegion[p][2] if (lx \< masterGroup[i].vars.camera[1] or lx \> masterGroup[i].vars.camera[3]) or (ly \< masterGroup[i].vars.camera[2] or ly \> masterGroup[i].vars.camera[4]) then updateTile2({locX = object.physicsRegion[p][1], locY = object.physicsRegion[p][2], layer = object.physicsRegion[p][3], tile = -1, owner = object }) end end end object.physicsRegion = nil object.physicsRegion = {} for lx = left, right, 1 do for ly = top, bottom, 1 do for j = 1, #map.layers, 1 do if (lx \< masterGroup[j].vars.camera[1] or lx \> masterGroup[j].vars.camera[3]) or (ly \< masterGroup[j].vars.camera[2] or ly \> masterGroup[j].vars.camera[4]) then local owner = updateTile2({locX = lx, locY = ly, layer = j, onlyPhysics = false, owner = object}) if owner then object.physicsRegion[#object.physicsRegion + 1] = {lx, ly, j} end end end end end object.bounds = {left, top, right, bottom} end else local locX = math.ceil(object.x / map.tilewidth) local locY = math.ceil(object.y / map.tilewidth) if (locX \< masterGroup[i].vars.camera[1] - 1 or locX \> masterGroup[i].vars.camera[3] + 1) or (locY \< masterGroup[i].vars.camera[2] - 1 or locY \> masterGroup[i].vars.camera[4] + 1) then object.isBodyActive = false elseif (locX \< masterGroup[i].vars.camera[1] or locX \> masterGroup[i].vars.camera[3]) or (locY \< masterGroup[i].vars.camera[2] or locY \> masterGroup[i].vars.camera[4]) then object.isAwake = false object.isBodyActive = true else object.isAwake = true object.isBodyActive = true end end end

just confirming for this particular item:  In this case the player is always on the screen (i.e. as opposed to the separate post I had about a wide object).  It’s as if MTE is not letting me set the physics properties for the player as I want.  

With this in mind Dyson I’m guessing the suggestion above (as it seems to be more Handle Offscreen Physics sadf  related) wouldn’t work would it?

The code above executes every frame for every object and sets it’s isBodyActive and isAwake properties according to it’s position. It doesn’t matter if the sprite is always onscreen, MTE will still set isBodyActive to true each time update executes. Commenting out the code will prevent this from happening to your onscreen player sprite. You’ll be able to turn it on and off whenever you like. This block from the above code is the one causing the behavior:

local locX = math.ceil(object.x / map.tilewidth) local locY = math.ceil(object.y / map.tilewidth) if (locX \< masterGroup[i].vars.camera[1] - 1 or locX \> masterGroup[i].vars.camera[3] + 1) or (locY \< masterGroup[i].vars.camera[2] - 1 or locY \> masterGroup[i].vars.camera[4] + 1) then object.isBodyActive = false elseif (locX \< masterGroup[i].vars.camera[1] or locX \> masterGroup[i].vars.camera[3]) or (locY \< masterGroup[i].vars.camera[2] or locY \> masterGroup[i].vars.camera[4]) then object.isAwake = false object.isBodyActive = true else object.isAwake = true object.isBodyActive = true --Turns the object on every frame end

If the object is more than 1 location from the screen edge, it is turned off. If the object is less then 1 location from the screen edge, but still off the edge, it is turned on but put to sleep. Otherwise the sprite is onscreen and it is both turned on and set to awake.

thanks Dyson - worked well as a work around to these two items, i.e. (a) isBodyActive = false not working and (b) wide objects turning off when they are still on the screen (i.e. part of them still on the screen). I’m assuming these are really work arounds until you get a chance to resolve?  

I’m hoping this work around only applies to objects not tiles?  i.e. like it’s not now having the impact of turning off culling for all the tiles for my level?  (just double checking).  

PS.  Noted there’s actually two sections in the code like this.  The second section is called “Handle Offscreen Physics (ISO)”, so I’m wondering if I should comment this out too?   Seems I didn’t have to to get it to work, but I’m kind of curious what this section is (with the “ISO” appended to it)?

The workaround only applies to objects. Tiles will continue to cull and render as normal.

The ISO section handles the same function but on isometric maps. You can ignore that unless you’re using an isometric map. Many of the code sections are divided between ISO and non-ISO, because Isometric maps have a few special needs when it comes to positioning and translation between the rectangular map data and isometric output.

I’ll have to look into that on my end. MTE turns objects on and off depending on their screen position, so if the object’s onscreen the engine’s turning it back on every time you try to turn it off. I’ll have to figure out some way to differentiate between the player’s input and the engine’s, but it should be doable. I’ll have more information on that as I start to update the relevant section of code.

EDIT:

I’ll be adding an option to completely disable the engine’s automated physics state management so that a physics object will stay on or off as set by the player no matter where it is on the screen. If you don’t want to wait you can go into mte.lua and comment out everything from line 9869 to 9924:

--Handle Offscreen Physics if object.bodyType and masterGroup[i].vars.camera then if object.offscreenPhysics then local tempX, tempY = masterGroup.parent:localToContent(object.contentBounds.xMin, object.contentBounds.yMin) local leftTop = {masterGroup[i]:contentToLocal(tempX, tempY)} tempX, tempY = masterGroup.parent:localToContent(object.contentBounds.xMax, object.contentBounds.yMax) local rightBottom = {masterGroup[i]:contentToLocal(tempX, tempY)} left = math.ceil(leftTop[1] / map.tilewidth) - 1 top = math.ceil(leftTop[2] / map.tileheight) - 1 right = math.ceil(rightBottom[1] / map.tilewidth) + 1 bottom = math.ceil(rightBottom[2] / map.tileheight) + 1 if not object.bounds or (object.bounds[1] ~= left or object.bounds[2] ~= top or object.bounds[3] ~= right or object.bounds[4] ~= bottom) then if object.physicsRegion then for p = 1, #object.physicsRegion, 1 do local lx = object.physicsRegion[p][1] local ly = object.physicsRegion[p][2] if (lx \< masterGroup[i].vars.camera[1] or lx \> masterGroup[i].vars.camera[3]) or (ly \< masterGroup[i].vars.camera[2] or ly \> masterGroup[i].vars.camera[4]) then updateTile2({locX = object.physicsRegion[p][1], locY = object.physicsRegion[p][2], layer = object.physicsRegion[p][3], tile = -1, owner = object }) end end end object.physicsRegion = nil object.physicsRegion = {} for lx = left, right, 1 do for ly = top, bottom, 1 do for j = 1, #map.layers, 1 do if (lx \< masterGroup[j].vars.camera[1] or lx \> masterGroup[j].vars.camera[3]) or (ly \< masterGroup[j].vars.camera[2] or ly \> masterGroup[j].vars.camera[4]) then local owner = updateTile2({locX = lx, locY = ly, layer = j, onlyPhysics = false, owner = object}) if owner then object.physicsRegion[#object.physicsRegion + 1] = {lx, ly, j} end end end end end object.bounds = {left, top, right, bottom} end else local locX = math.ceil(object.x / map.tilewidth) local locY = math.ceil(object.y / map.tilewidth) if (locX \< masterGroup[i].vars.camera[1] - 1 or locX \> masterGroup[i].vars.camera[3] + 1) or (locY \< masterGroup[i].vars.camera[2] - 1 or locY \> masterGroup[i].vars.camera[4] + 1) then object.isBodyActive = false elseif (locX \< masterGroup[i].vars.camera[1] or locX \> masterGroup[i].vars.camera[3]) or (locY \< masterGroup[i].vars.camera[2] or locY \> masterGroup[i].vars.camera[4]) then object.isAwake = false object.isBodyActive = true else object.isAwake = true object.isBodyActive = true end end end

just confirming for this particular item:  In this case the player is always on the screen (i.e. as opposed to the separate post I had about a wide object).  It’s as if MTE is not letting me set the physics properties for the player as I want.  

With this in mind Dyson I’m guessing the suggestion above (as it seems to be more Handle Offscreen Physics sadf  related) wouldn’t work would it?

The code above executes every frame for every object and sets it’s isBodyActive and isAwake properties according to it’s position. It doesn’t matter if the sprite is always onscreen, MTE will still set isBodyActive to true each time update executes. Commenting out the code will prevent this from happening to your onscreen player sprite. You’ll be able to turn it on and off whenever you like. This block from the above code is the one causing the behavior:

local locX = math.ceil(object.x / map.tilewidth) local locY = math.ceil(object.y / map.tilewidth) if (locX \< masterGroup[i].vars.camera[1] - 1 or locX \> masterGroup[i].vars.camera[3] + 1) or (locY \< masterGroup[i].vars.camera[2] - 1 or locY \> masterGroup[i].vars.camera[4] + 1) then object.isBodyActive = false elseif (locX \< masterGroup[i].vars.camera[1] or locX \> masterGroup[i].vars.camera[3]) or (locY \< masterGroup[i].vars.camera[2] or locY \> masterGroup[i].vars.camera[4]) then object.isAwake = false object.isBodyActive = true else object.isAwake = true object.isBodyActive = true --Turns the object on every frame end

If the object is more than 1 location from the screen edge, it is turned off. If the object is less then 1 location from the screen edge, but still off the edge, it is turned on but put to sleep. Otherwise the sprite is onscreen and it is both turned on and set to awake.

thanks Dyson - worked well as a work around to these two items, i.e. (a) isBodyActive = false not working and (b) wide objects turning off when they are still on the screen (i.e. part of them still on the screen). I’m assuming these are really work arounds until you get a chance to resolve?  

I’m hoping this work around only applies to objects not tiles?  i.e. like it’s not now having the impact of turning off culling for all the tiles for my level?  (just double checking).  

PS.  Noted there’s actually two sections in the code like this.  The second section is called “Handle Offscreen Physics (ISO)”, so I’m wondering if I should comment this out too?   Seems I didn’t have to to get it to work, but I’m kind of curious what this section is (with the “ISO” appended to it)?

The workaround only applies to objects. Tiles will continue to cull and render as normal.

The ISO section handles the same function but on isometric maps. You can ignore that unless you’re using an isometric map. Many of the code sections are divided between ISO and non-ISO, because Isometric maps have a few special needs when it comes to positioning and translation between the rectangular map data and isometric output.