Getting stuck in the wall

Hey all,

I’m playing around with the physics engine, but I came upon an issue I cannot seem to resolve; I spawn a bunch of circles (15), add a dynamic body to it, and give them a random velocity : (simplified code)

globe = display.newCircle( 
	math.random(30, FIELD.WIDTH-30),
	math.random(30, FIELD.HEIGHT-30), 
	5 )
physics.addBody( globe, "dynamic", { radius=5, bounce=0.99 } )
globe.setLinearVelocity(Xv, Yv)

I have my “playfield” bordered by rectangles that are “static” body;

bot = rect(0, FIELD.HEIGHT, FIELD.WIDTH, 15, green)
right = rect(FIELD.WIDTH-5, 0,  15, FIELD.HEIGHT, purple)

top = rect(0, 0, FIELD.WIDTH, 15, green)
left = rect(0, 0, 5, FIELD.HEIGHT, red)

physics.addBody( top, "static" )
physics.addBody( bot, "static" )
physics.addBody( left, "static" )
physics.addBody( right, "static" )

function rect(x, y, w, h, color)
	local new_x = x+(w/2)
	local new_y = y+(h/2)
	local r = display.newRect(new_x, new_y, w, h)
	r.fill = color
	return r
end

After running the simulation for a few seconds, some globes get stuck to the wall; I’m not exactly sure what happens, but I observe that Xv or Yv drops to 0 in this state, my attempt to fix this was to run check regularly for this case and reset Xv or Yv to the initial state (which I store); while this sometimes fixes it, mostly it does not; (simplified)

if (vx == 0 or vy == 0) then 
	new_vx = vx
	new_vy = vy

	if (vx == 0) then
		new_vx = globe[id].init_Xv
	end
	if (vy == 0) then
		new_vy = globe[id].init_Yv
	end

	globe[id]:setLinearVelocity(new_vx, new_vy)
end

I also attempted to make the border not straight by adding, but again no luck;

r.path.x4 = -1
r.path.x3 = -2
r.path.x2 = -3
r.path.x1 = -4

I then tried to round the x and y position because I believe it might be related to floating calculations; so I round the numbers and reset Xv and Yv; (depending on what is 0) Sadly this does not resolve it either; The last thing I tried is to teleport them away from the wall while resetting :

globe[id].x = round(globe[id].x) + (math.random(20,30)/10)
globe[id].y = round(globe[id].y) + (math.random(20,30)/10)
globe[id]:setLinearVelocity(new_vx, new_vy)

While this helps somewhat, its clearly visible, and not a full solution; Does anyone have an idea how to resolve this ?

This is what I want to recreate : https://upload.wikimedia.org/wikipedia/commons/6/6d/Translational_motion.gif

Thanks for the help / idea’s !

Very hard to understand how your code works from these fragments. I would expect your globes to just drop down thanks to gravity since they are dynamic bodies.

Have you configured any collision detection for the globes and walls?

Hey Markus,

I set physics.setGravity( 0, 0 ) ; and globes are dynamic, walls are static;

The marked globe will only move horizontally against (/in) the wall;

This is the code (warning : its not clean :wink: )

-----------------------------------------------------------------------------------------
--
-- main.lua
--
-----------------------------------------------------------------------------------------

local physics = require( "physics" )
physics.start()
physics.setGravity( 0, 0 )
physics.setDrawMode( "hybrid" )

-- Hide status bar
display.setStatusBar( display.HiddenStatusBar )
 
-- Seed the random number generator
-- math.randomseed( os.time() )
math.randomseed(os.clock()*1000) -- os.time() is to easy

-- game constants
local FIELD = {WIDTH = 320, HEIGHT = 480}
local LEVEL = {START = 1, VERIFY = 2, REQUIREMENT = {}, ATOMS = {}, ENTROPY = {}, TEXT = {}}

local background

-- color definitions
local white 	= {1}
local black 	= {0}

local yellow 	= {255, 255, 0}
local red 		= {255, 0, 0 , 0.6}
local green 	= {0, 255, 0}
local blue 		= {0, 0, 255}

local pink 		= {255, 204, 204}
local orange	= {255, 128, 0}
local seablue	= {0, 255, 255}
local purple	= {255, 0, 255}

-- vars
local atoms = {} 
local atom_count = 35

function create_borders()
	bot = rect(0, FIELD.HEIGHT, FIELD.WIDTH, 15, green)
	right = rect(FIELD.WIDTH-5, 0,  15, FIELD.HEIGHT, purple)
	
	top = rect(0, 0, FIELD.WIDTH, 15, green)
	left = rect(0, 0, 5, FIELD.HEIGHT, red)
	-- playfield = rect(0, 0, FIELD.WIDTH, FIELD.HEIGHT, red)
	
	-- physics.addBody( playfield, "static" )
	physics.addBody( top, "static" )
	physics.addBody( bot, "static" )
	physics.addBody( left, "static" )
	physics.addBody( right, "static" )
end

function create_atom(n)
	
	-- we need a 1 or a -1
	local function random_direction()

		local result = math.random(0,1)
		if result == 0 then
			result = -1
		end
		return result
	end
	
	-- for n atoms
	local count = 0
	local atom_id = #atoms
	while count < (n+1) do
		
		-- determ type
		local selected_atom = math.random(0,1)
		-- local atom
		if selected_atom == 0 then
			atoms[atom_id] = display.newCircle( 
								math.random(30, FIELD.WIDTH-30),
								math.random(30, FIELD.HEIGHT-30), 
								3 )
			atoms[atom_id].fill = orange
			physics.addBody( atoms[atom_id], "dynamic", { radius=5, bounce=0.99 } )
		else			
			atoms[atom_id] = display.newCircle( 
								math.random(30, FIELD.WIDTH-30),
								math.random(30, FIELD.HEIGHT-30), 
								5 )
			atoms[atom_id].fill = purple
			physics.addBody( atoms[atom_id], "dynamic", { radius=7, bounce=0.99 } )
		end
		
		local Xv = math.random( 40,120 ) * random_direction()
		local Yv = math.random( 20,60 ) * random_direction()
		atoms[atom_id]:setLinearVelocity(Xv, Yv)
		atoms[atom_id].init_Xv = Xv
		atoms[atom_id].init_Yv = Yv
		
		atom_id = atom_id + 1 
		count = count + 1 
	end
end

-- changed from newRect that start with centered x,y
function rect(x, y, w, h, color)
	local new_x = x+(w/2)
	local new_y = y+(h/2)
	local r = display.newRect(new_x, new_y, w, h)
	r.fill = color
	r.path.x4 = -1
	r.path.x3 = -2
	r.path.x2 = -3
	r.path.x1 = -4
	return r
end

function printatoms()
	
local atom_id = 0
local n = #atoms
	while atom_id < (n+1) do

	local vx, vy = atoms[atom_id]:getLinearVelocity()
	
	local function round(number)
  return number - (number % 1)
end

	-- print ("vx:" .. round(vx) .. " vy:" .. round(vy))
	
		if (vx == 0 or vy == 0) then 
			new_vx = vx
			new_vy = vy
			
			if (vx == 0) then
				new_vx = atoms[atom_id].init_Xv
			end
			if (vy == 0) then
				new_vy = atoms[atom_id].init_Yv
			end
			
			-- atoms[atom_id].fill = red
			
			print ("x" .. atoms[atom_id].x .. " y:" .. atoms[atom_id].y)
			print ("vx ori : " .. atoms[atom_id].init_Xv .. " vy ori: " .. atoms[atom_id].init_Yv)
			print ("vx:" .. vx .. " vy:" .. vy .. " to vx:" .. new_vx .. " vy:" .. new_vy)
			atoms[atom_id].x = round(atoms[atom_id].x) + (math.random(20,30)/10)
			atoms[atom_id].y = round(atoms[atom_id].y) + (math.random(20,30)/10)
			atoms[atom_id]:setLinearVelocity(new_vx, new_vy)
		end
		atom_id = atom_id + 1 
	end
end
 
function add_atoms()
	atom_count = atom_count + 5;
	create_atom(5)
	print (#atoms)
	-- draw_debug()
end

-- main function
function main()
	
	create_borders()
	-- generate atoms
	create_atom(atom_count)
	updateLoopTimer = timer.performWithDelay( 400, printatoms, 0 )
end


-- run the code
main()

-- return to menu
-- state = MENU.MENU

I ran your code and now I see what you mean. Strange behavior indeed, and I wasn’t able to solve it either.

Did some googling and it seems to be a “feature” of the Box2D engine. Maybe this can help you:

And this:

I tried physics.setMKS("velocityThreshold", 0) but it didn’t seem to have any effect as the balls still got stuck around the edges when colliding with too small velocity.

1 Like

Hey Markus,

Thanks for having a look! It’s weird nobody seemed to have faced this issue before; I can kinda work around it by the reseting velocity; but its far from ideal.

We also meet this issue and fixed, and we have submitted a pull request to submodule-box2d.

2 Likes

How did you solve this problem?

The problem has not been fixed for over a year. How can I fix this bug myself?

did you try to apply force instead of setting velocity

Hey Kakula,

I never found a solution; (This topic is from 'sept 2020). I don’t have the code or setup anymore to test a fix, but I don’t think that would make a difference, since the code is just setting a velocity based on the calculated weight.

I think the proposed fix by pickerel can be found here :

but it hasn’t been approved yet.

Thanks all for the help :slight_smile:

We have fixed several issues related to box2d and as the official has not been merging our pull request, we had to compile Solar2d ourselves.

1 Like

Apologies I though the date was days ago :grin:

However no physics engine is perfect, but sometimes certain settings can enhance the current engine, meaning that if objects were too small or too large or too heavy, it might affect the engine behavior

So if we had your old code, the first thing I would have done is to increase the size of the objects, this alone might have solved it without fixing the physics engine