I am making a game where you have a set of scales, and must put the same weight on both sides.
This is my update code:
local function worldUpdate( event )
world:step(1/60, 8, 3);
updatePhysicsObject(barSpr);
updatePhysicsObject(supportSpr);
updatePhysicsObject(leftScaleSpr);
updatePhysicsObject(rightScaleSpr);
for ix, el in pairs(fruits) do
updatePhysicsObject(el);
end
local rotation = math.deg(barSpr.body:getAngle());
if rotation < 0 then rotation = -rotation end;
barSpr.body:setAngularDamping(25 - rotation*0.5);
if wait > 0 then
wait = wait - 1;
return;
end
if rotation < 2 then
print("getting angular velocity", debug.getinfo(1).currentline);
local angularVelocity = barSpr.body:getAngularVelocity();
if angularVelocity < 0 then angularVelocity = -angularVelocity end
if angularVelocity < 0.15 then
levelNumber = levelNumber + 1;
if levelNumber > maxLevelNumber then
return;
end
print("calling delete all fruits", debug.getinfo(1).currentline);
deleteAllFruits();
loadNewLevel();
wait = 100;
end
end
end
updatePysicsOBject purpose only is set the sprite to the body.
loadNewLevel is too long and complex to paste here, but basically it spawn stuff.
now, the curious part is the deleteAllFruits code:
local function deleteAllFruits()
world:clearForces();
local counter=0;
for ix, el in pairs(fruits) do
if not el.body then
print("for some reason a fruit is missing its body", ix);
end
world:destroyBody(el.body);
el:removeFromParent();
el = nil;
fruits[ix] = nil;
counter = counter + 1;
end
print("destroyed " .. counter .. " fruits")
end
Originally the "clearForces()" was not present.
When I comment out the "destroyBody()" the game works as intended, except leaves behind the physics of the last level...
If I leave the "destroyBody()" working, the game crashes when you win twice. (the first win works fine).
Later I experimented adding the "clearForces()" now it crashes when you win 5 or 6 times (don't remember exactly).
I am not sure of what to do now, and by "crash" I mean "crash", Gideros Player gets killed by Windows, no error message.
Note this game was made before in Corona SDK, and worked fine there, the code on Gideros is mostly a copy and paste with the changes needed on different API parts. (in fact if you wish, you can play the Corona SDK version, it is on Google Play, it is a minigame on the second map of this game:
https://play.google.com/store/apps/details?id=com.kidoteca.nonoamazonia.beta )
Comments
Here is my example with indexed table and it seems to work great for me, can you try it (click to add bodies, clear balls to remove them)?
local function deleteAllFruits()
local counter=0;
for ix=#fruits, 1, -1 do
local el = fruits[ix];
if not el.body then
print("for some reason a fruit is missing its body", ix);
end
world:destroyBody(el.body);
el:removeFromParent();
el = nil;
fruits[ix] = nil;
counter = counter + 1;
end
print("destroyed " .. counter .. " fruits")
end
Now it crashes every time I win the second level. (and with the clear it crashes at random times).
So, the way that I am looping is not at fault.
There is no way to know why Gideros crashed? Ie: what it was attempting to do? Can Atilim give me a special debug version or something? (remembering that my account is the most expensive one... if that makes a difference in this case)
world:destroyBody(body)
body=nil
Otherwise you might later do body.getAngle() which is a disaster as "body" is no longer valid to Box2D.
Also you must not destroy bodies during BEGIN/END_CONTACT listeners.
https://github.com/gideros/gideros
https://www.youtube.com/c/JohnBlackburn1975
Also I am making the body nil indirectly (ie: I am making all references to the body parent nil).
Also I call this after step(), I don't even added any contact listeners yet.
Also I saw this: http://www.box2d.org/forum/viewtopic.php?f=8&t=1147 it might be related (the symptom is the same at least)
print(pcall(deleteAllFruits))
First level it worked
Second level crashed before pcall returning anything.
I am guessing the crash IS NOT at the deletion, the deletion is deleting something it should not, and it is crashing later for other reasons.
what do you do inside loadNewLevel() ?
The only remaing part is the function that spawns a fruit (That is called a couple times when a level is created).
local function spawnFruit(fruitType, side)
local radius = fruitRadius[fruitType];
local fruit = Bitmap.new(fruitTx[fruitType]);
fruit:setAnchorPoint(0.5, 0.5);
if side == 1 then
fruit:setPosition(SpriteUtils.CENTER_X+130+math.random(20), -48-radius);
--add touch listener
else
fruit:setPosition(SpriteUtils.CENTER_X-130+math.random(20), -48-radius-math.random(50));
end
local fruitShape = b2.CircleShape.new(0, 0, radius);
local fruitBody = world:createBody({type = b2.DYNAMIC_BODY, position = {x=fruit:getX(), y=fruit:getY()}});
fruitBody:createFixture( { density=2, friction=0.6, restitution=0.05, shape=fruitShape});
fruit.body = fruitBody;
fruitLayer:addChild(fruit);
fruits[#fruits + 1] = fruit;
end
local function loadNewLevel()
spawnFruit(1);
spawnFruit(2);
spawnFruit(3);
spawnFruit(4);
return;
end
https://github.com/gideros/gideros
https://www.youtube.com/c/JohnBlackburn1975
you are also not deleting bodies on the locked world, so for now I'm clueless.
Does it also crash on on other palftorms/devices?
Will you be able to send me or @atilim a test project?
Also I will see if I can test tomorrow on OSX (today I am on Windows)
@john26 My code only add, delete, and run step, there is no force, no position change, no collision listeners.
https://github.com/gideros/gideros
https://www.youtube.com/c/JohnBlackburn1975
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 liblua.1.dylib 0x00000000002065f5 0x1f2000 + 83445
1 liblua.1.dylib 0x00000000001f693e luaH_get + 206
2 liblua.1.dylib 0x00000000001f6835 lua_rawget + 69
3 libgideros.1.dylib 0x000000000023c7eb luaL_rawgetptr + 107
4 com.yourcompany.Gideros Player 0x000000010008701e getb2(lua_State*) + 62
5 com.yourcompany.Gideros Player 0x0000000100085b56 getb2(lua_State*, void*) + 38
6 com.yourcompany.Gideros Player 0x000000010008b0ad DestructionListener::SayGoodbye(b2Fixture*) + 77
7 com.yourcompany.Gideros Player 0x000000010001c83b b2World::DestroyBody(b2Body*) + 395
8 com.yourcompany.Gideros Player 0x0000000100074d61 Box2DBinder2::b2World_DestroyBody(lua_State*) + 369
9 liblua.1.dylib 0x00000000001fdace luaD_precall + 1006
10 liblua.1.dylib 0x00000000001fffe0 luaV_execute + 7616
11 liblua.1.dylib 0x00000000001f79b2 luaD_call + 178
12 liblua.1.dylib 0x00000000001f78be lua_call + 78
13 com.yourcompany.Gideros Player 0x000000010008ef8e eventClosure(lua_State*) + 206
14 liblua.1.dylib 0x00000000001fdace luaD_precall + 1006
15 liblua.1.dylib 0x00000000001f7999 luaD_call + 153
16 liblua.1.dylib 0x00000000001f78be lua_call + 78
17 com.yourcompany.Gideros Player 0x00000001000957e9 PushEventVisitor::visit(EnterFrameEvent*) + 921
18 com.yourcompany.Gideros Player 0x00000001000dd95e EnterFrameEvent::apply(EventVisitor*) + 30
19 com.yourcompany.Gideros Player 0x000000010008e9d7 CppLuaBridge::luaEvent(LuaEvent*) + 359
20 com.yourcompany.Gideros Player 0x0000000100091868 Slot::call(Event*) + 120
21 com.yourcompany.Gideros Player 0x000000010006ec8f EventDispatcher::dispatchEvent(Event*) + 271
22 com.yourcompany.Gideros Player 0x000000010011b784 Stage::enterFrame(int) + 932
23 com.yourcompany.Gideros Player 0x00000001000c9cd3 Application::enterFrame() + 227
24 com.yourcompany.Gideros Player 0x000000010009b169 enterFrame(lua_State*) + 425
25 liblua.1.dylib 0x00000000001fdace luaD_precall + 1006
26 liblua.1.dylib 0x00000000001f7999 luaD_call + 153
27 liblua.1.dylib 0x00000000001f7c4f 0x1f2000 + 23631
28 liblua.1.dylib 0x00000000001fd0f9 luaD_rawrunprotected + 105
29 liblua.1.dylib 0x00000000001f7b6a luaD_pcall + 122
30 liblua.1.dylib 0x00000000001f7a9e lua_pcall + 174
31 libgideros.1.dylib 0x000000000023c768 lua_pcall_traceback + 200
32 com.yourcompany.Gideros Player 0x000000010009a7c5 LuaApplication::enterFrame(GStatus*) + 133
33 com.yourcompany.Gideros Player 0x0000000100058e85 GLCanvas::paintGL() + 53
34 QtOpenGL 0x000000000038f629 QGLWidget::glDraw() + 121
(skipped lines up to 60+, because they are mostly calls to OpenGL, main(), etc...)
And using world:clear make the crash happen much later...
I am guessing it is a bug similar to the links I pasted earlier, the bodies are dangling in the collision structures.
This thing was supposed to be working tomorrow (since we are just copying and pasting from Corona, we felt no need in having a big deadline)
Surely you position sprites on top of physics bodies?
https://github.com/gideros/gideros
https://www.youtube.com/c/JohnBlackburn1975
if it would be simply leaving references in collisions, then my example would also crash, and as it does not, it means there is some specific situation triggered in your code.
You can email @atilim project to atilim.cetin at gmail.com or me to
ar2rsawseen at gmail.com
from the stack
getb2 probably get the b2 reference from the lua. so it seems this is where it crashes
:-/
Probably what I have different from your example, I have a non-dynamic object, and I have some joints, those compose the scales where my fruits rest.
Maybe it is those are needed to break it.
it seems coroutines are interfering with box2d, if everything is run on single thread its working as expected, emailing you a modified project to try
I will see what I can do for now.
But please fix it!
If you have other scenes that are loaded on other coroutines, most probably it'll be good enough to create a new world there
BTW whats up with so many coroutines?
I actually never used them in my own projects, they make the code really unreadable/untrackable
One I could imagine is to preload assets and make a loader for it, but in the mini game case I did not get the purpose
Actually, it is exactly for that, all coroutines I used are preloaders, I am writing a memory manager (that for now is incomplete) to also help.
The previous version of this game had some serious memory and loading issues, one issue is that it frequently crashed on some devices after eating up all the ram, the reason for that is that adventure-game animations on a retina screen can easily gobble up several 2048x2048 files.
The other problem is that on some devices (like my personal phone), the game frequently was killed while still loading because of not responding to the OS, and when I solved that, then users ended killing it because the loading time was too long, what I did this time was use all those coroutines, to allow the game to keep pre-loading stuff while you are already playing...
The "system.start()" function is not supposed to load anything ever, only to display them on the screen, or call the memory manager if it detects something is not loaded yet. But parts of that are not done yet (ie: the game currently has no "loading" screen for stuff that you tried to use that were not loaded, it just runs the coroutine fast as it can and freezes until it finishes)
will be eager to see how end result will work
https://github.com/gideros/gideros
https://www.youtube.com/c/JohnBlackburn1975