Physics, applyImpulse, dt and other things

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Broncheabones
Prole
Posts: 15
Joined: Wed Feb 04, 2009 5:25 am

Physics, applyImpulse, dt and other things

Post by Broncheabones »

I'm new to Love and relatively new to LUA but I've got things down, for the most part. The "Game" I'm trying to make is a sidescroller that involves gravity. Any how, I used applyImpulse for my movement but whenever the key is it it totally resets my current horizontal/vertical speed. On top of that, I can't use dt as a value so when I hit one direction it instantly reaches top speed. hoping you all can help me out, current code is below. (Note: I stole most of this from the love.physics manual page :ehem: )

EDIT: The values seen below are only 100 but for some reason I need 10000+ to see any noticeable movement. Is this normal?

Code: Select all

function keypressed(k) 
   if k == love.key_d then
      body:applyImpulse(100, 0)
   elseif k == love.key_a then
	  body:applyImpulse(-100, 0)
   end 
   
   if k== love.key_w then
	  body:applyImpulse(0, -100)
   end
end 
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Physics, applyImpulse, dt and other things

Post by bartbes »

About dt: that's because there's no dt value in keypressed, you might have noticed that update gets the dt as an argument. You can use love.timer.getDelta() instead.
osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: Physics, applyImpulse, dt and other things

Post by osuf oboys »

To get a smoother turning, you may want to use love.keyboard.isDown in the update instead. Regarding the impulse - yes, you need that much because a 40 by 40 pixels body is huge in box2d.
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.
User avatar
rude
Administrator
Posts: 1052
Joined: Mon Feb 04, 2008 3:58 pm
Location: Oslo, Norway

Re: Physics, applyImpulse, dt and other things

Post by rude »

Broncheabones wrote:10000+
Yes, because of this: http://love2d.org/forum/viewtopic.php?f=3&t=223.
Broncheabones
Prole
Posts: 15
Joined: Wed Feb 04, 2009 5:25 am

Re: Physics, applyImpulse, dt and other things

Post by Broncheabones »

Hey guys, you've been a big help, but over one hill and on to another. I hate to keep asking questions, it makes me feel so dumb but it's better than raging on my keyboard. This is what I've turned my code in to:

Code: Select all

function update(dt)
	if love.keyboard.isDown(love.key_d) then
      body:applyImpulse(200000*dt, 0)
   elseif love.keyboard.isDown(love.key_a) then
	  body:applyImpulse(-200000*dt, 0)
   end 
   
   if love.keyboard.isDown(love.key_w) then
	  body:applyImpulse(0, -100000)
   end

   -- Update the world. 
   world:update(dt) 
end 
I get smooth movement and it works very well but I have 2 more questions. How do I get it to only be able to jump when on the ground? If I hold down W it simply shoots upward with out stopping. My second question is how do I set a "Top Speed" so to speak. I figure it has something to do with getVelocity but whatever I'm doing it's not working. Thanks a lot.
Chris016
Prole
Posts: 22
Joined: Sat Aug 16, 2008 1:58 am

Re: Physics, applyImpulse, dt and other things

Post by Chris016 »

it seems as tho we are doing the same thing. Ive been working with about the same stuff you are lol.

But so you want them to once they jump, they cant jump again until a collision with the ground? Add some condtions.
Heres an example:

Code: Select all

	if space == 0 then
	if k == love.key_space then
		space = 1
		body:applyImpulse(0,-math.random(0,621000))
	end
	end

Here is another for collision

Code: Select all

function collision(a, b, c) 
   space=0

   text = "Collided: " .. a .. " and " .. b 
   
end 
This is from the physics example in the documents, I just modded it. Maybe that helps. Top speed, Not sure, haven't messed with yet.
Broncheabones
Prole
Posts: 15
Joined: Wed Feb 04, 2009 5:25 am

Re: Physics, applyImpulse, dt and other things

Post by Broncheabones »

Hey Chris, I tried what you suggested but it seems my ball just won't jump anymore. Please tell me if I did it right.

Code: Select all

if space == 0 then
   if love.keyboard.isDown(love.key_w) then
   	  space = 1
	  body:applyImpulse(0, -100000)
   end
   end
I also added in

Code: Select all

function collision(a, b, c) 
   space=0

   text = "Collided: " .. a .. " and " .. b 
   
end 
Thanks for the help, I hope I just made some simple mistake is all. I might add the first bit is no longer under function keypressed(k) but is now under update(dt) so that may be my problem.
osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: Physics, applyImpulse, dt and other things

Post by osuf oboys »

Hi, another way to deal with jumping is to check the distance between objects - which gives excellent results. A platformer demo featuring this should appear at the end of this week. I paste parts of the code in case you wish to use it nevertheless. Note that the exact polygon-polygon collision isn't added but I don't have time to fill that in right now, I'm afraid.

shapeDistance(shape1, shape2) returns distance, x1, y1, x2, y2, where (x1, y1) is the nearest point on shape1 and (x2, y2) is the nearest point on shape2. shapeDistanceQuick does the same but is much faster because it only checks the bounding box. It is advisable to first use the quick check and then the full if two shapes are actually nearby.

Good luck!

Code: Select all

function nearRelPointLineSegPoint(lx1, ly1, lx2, ly2, px, py)
	local	r = ((lx2 - lx1) * (px - lx1) + (ly2 - ly1) * (py - ly1)) / ((lx2-lx1)^2 + (ly2-ly1)^2)
	return math.min(math.max(0,r),1)
end

function nearPointLineSegPoint(lx1, ly1, lx2, ly2, px, py)
	local	r = nearRelPointLineSegPoint(lx1, ly1, lx2, ly2, px, py)
	return (1-r)*lx1 + r*lx2, (1-r)*ly1 + r*ly2
end

function distLineSegPoint(lx1, ly1, lx2, ly2, px, py)
	local	r = nearRelPointLineSegPoint(lx1, ly1, lx2, ly2, px, py)
	local ret = (((1-r)*lx1 + r*lx2 - px)^2 + ((1-r)*ly1 + r*ly2 - py)^2)^0.5
	return ret
end

function distLineSegLineSeg(lx1, ly1, lx2, ly2, lx3, ly3, lx4, ly4)
	return math.min(
		distLineSegPoint(lx1, ly1, lx2, ly2, lx3, ly3),
		distLineSegPoint(lx1, ly1, lx2, ly2, lx4, ly4),
		distLineSegPoint(lx3, ly3, lx4, ly4, lx1, ly1),
		distLineSegPoint(lx3, ly3, lx4, ly4, lx2, ly2)
	)
end

--~ function shapeDistanceQuick(shape1, shape2)
--~ 	local	x1,y1,x2,y2,x3,y3,x4,y4 = shape1:getBoundingBox()
--~ 	local	u1,v1,u2,v2,u3,v3,u4,v4 = shape2:getBoundingBox()
--~ 	return (math.max(0,u2 - x4, x2 - u4)^2
--~ 		+ math.max(0,v2 - y4, y2 - v4)^2)^0.5
--~ end

function shapeDistanceQuick(shape1, shape2)
	local	x1,y1,x2,y2,x3,y3,x4,y4 = shape1:getBoundingBox()
	local	u1,v1,u2,v2,u3,v3,u4,v4 = shape2:getBoundingBox()
	local	bx, bu, by, bv
	if u2 > x4 then
		bx = x4; bu = u2
	elseif x2 > u4 then
		bx = x2; bu = u4
	else
		bx = math.min(u4, x4) / 2 + math.max(u2, x2) / 2; bu = bx
	end
	if v2 > y4 then
		by = y4; bv = v2
	elseif y2 > v4 then
		by = y2; bv = v4
	else
		by = math.min(v4, y4) / 2 + math.max(v2, y2) / 2; bv = by
	end
	return ((bx-bu)^2+(by-bv)^2)^0.5, bx, by, bu, bv
end

-- Assumes circles are not offset. If so, please set offsetX and offsetY in data.
function shapeDistance(shape1, shape2)
	if shape1 == shape2 then return nil end
	if shape1:getType() == love.shape_circle then
		if shape2:getType() == love.shape_circle then
			local	data1 = shape1:getData()
			local	data2 = shape2:getData()
			local x1, y1 = data1.body:getData():getPosition()
			if data1.offsetX then x1 = x1 + data1.offsetX; end
			if data1.offsetY then y1 = y1 + data1.offsetY; end
			local x2, y2 = data2.body:getPosition()
			if data2.offsetX then x2 = x2 + data2.offsetX; end
			if data2.offsetY then y2 = y2 + data2.offsetY; end
			local	dx = x2 - x1
			local	dy = y2 - y1
			local d = (dx^2 + dy^2)^0.5
			local	r = shape1:getRadius() + shape2:getRadius()
			if d > 0 then
				x1 = x1 + shape1:getRadius() * dx / math.max(d,r)
				y1 = y1 + shape1:getRadius() * dy / math.max(d,r)
				x2 = x2 - shape2:getRadius()  * dx / math.max(d,r)
				y2 = y2 - shape2:getRadius()  * dy / math.max(d,r)
			end
			return d-r, x1, y1, x2, y2, dx, dy
		elseif shape2:getType() == love.shape_polygon then
			local	data1 = shape1:getData()
			local x1, y1 = data1.body:getPosition()
			if data1.offsetX then x1 = x1 + data1.offsetX; end
			-- Warning: table creation tends to be slow
			local	points = {shape2:getPoints()}
			local	n = #points
			local	mindis = distLineSegPoint(points[n-1], points[n], points[1], points[2], x1, y1)
			local mink = n/2
			local dis
			for k=1,n/2-1 do
				dis = distLineSegPoint(points[2*k-1], points[2*k], points[2*k+1], points[2*k+2], x1, y1)
				if dis < mindis then
					mindis = dis
					mink = k
				end
			end
			local	x2, y2 = nearPointLineSegPoint(points[2*mink-1], points[2*mink],
				points[(2*mink)%n+1], points[(2*mink+1)%n+1], x1, y1)
			local r = shape1:getRadius()
			local	dx = x2 - x1
			local	dy = y2 - y1
			if mindis > 0 then
				x1 = x1 + math.min(r, mindis) * dx / mindis
				y1 = y1 + math.min(r, mindis) * dy / mindis
			end
			return math.max(mindis - r, 0), x1, y1, x2, y2, dx, dy
		end
	elseif shape1:getType() == love.shape_polygon then
		if shape2:getType() == love.shape_circle then
			local	d, x1, y1, x2, y2 = shapeDistance(shape2, shape1)
			return d, x2, y2, x1, y1
		elseif shape2:getType() == love.shape_polygon then
			
		end
	end
end
Usage (replace entities with shapes)

Code: Select all

						-- Having found a nearest entity/shape 'nearent'
						local	dis,bs1,bs2,shp1,shp2,x1,y1,x2,y2,dx,dy = entityDistance(self, nearent)
						if (x2-x1)^2 + (y2-y1)^2 < 0.2^2 then 
							points = {x1,y1,x2,y2}
							local	d = (dx^2+dy^2)^0.5
							if d > 0 then
								angle = math.acos(dx / d)
								if dy < 0 then angle = math.pi - angle; end
							else
								angle = math.pi / 2
							end
							body1 = bs1.body
							body2 = bs2.body
							shape1 = shp1
							shape2 = shp2
						end
					...
					body1:applyImpulse(self.jumpPower * math.cos(angle), self.jumpPower * math.sin(angle))
					body2:applyImpulse(-self.jumpPower * math.cos(angle), -self.jumpPower * math.sin(angle))
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.
Broncheabones
Prole
Posts: 15
Joined: Wed Feb 04, 2009 5:25 am

Re: Physics, applyImpulse, dt and other things

Post by Broncheabones »

Wow, that is a hefty amount of code just to make it so I don't keep jumping. Shouldn't it be something simple like collision detection and not 12 lines?
osuf oboys
Party member
Posts: 215
Joined: Sun Jan 18, 2009 8:03 pm

Re: Physics, applyImpulse, dt and other things

Post by osuf oboys »

Broncheabones wrote:Wow, that is a hefty amount of code just to make it so I don't keep jumping. Shouldn't it be something simple like collision detection and not 12 lines?
Chris016's solution works fine if you don't have platforms that you can fall off of. There will probably/hopefully be a better solution by the next LÖVE version.


If you don't want the normal of the surface, e.g. all jumps should upwards, then you could use (change 0.2 accordingly)

Code: Select all

for k,v in pairs(shapes) do
  if shapeDistanceQuick(k, myshape) < 0.2 and shapeDistance(k, myshape) < 0.2 then
    mybody:applyImpulse(0, -xyz)
    break
  end
end
Or, to jump off of the surface.

Code: Select all

for k,v in pairs(shapes) do
  if shapeDistanceQuick(k, myshape) < 0.2 then
    local dis, x1, y1, x2, y2 = shapeDistance(k, myshape)
    if dis <= 0.2 then
      local angle = 90
      if dis > 0 then
        angle = math.deg(math.cos((x2 - x1) / dis))
      end
      -- Jump with this angle
      break
    end
  end
end
If I haven't written anything else, you may assume that my work is released under the LPC License - the LÖVE Community. See http://love2d.org/wiki/index.php?title=LPC_License.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 206 guests