Trig question: How to get x,y of "apply_force" from angle (SOLVED)

I need to apply a force to an dynamic object (x,y) to send it flying at an initial angle supplied by a trajectory indicator (which I already have rotating around my player game object). My trig was never that great, and while I found a website for calculating force vectors that explains it pretty well, I don’t really grasp (yet) how to get the two force values when all I really have is an angle.

Will one of the force values always be arbitrary?

I’m sure this is basic game math. Can someone help enlighten me?

Thanks!

1 Like

Okay so you’ll need two values: The angle and the magnitude of your force value (the hypotenuse of the triangle). This will either be a magic number you supply or a random number from a range with the min and max being some magic number that you supply (assuming you give the player control of the force of the thing that will be flying).

To get the X value: cos (angle) * magnitude

To get the Y value: sin (angle) * magnitude

2 Likes

Thanks for posting this.

I’m currently applying a “magic number” force and it these seem to function somewhat… but I can’t seem to get it to produce the right behavior yet.

When the game first loads and I try launching the object at a 45 degree angle… it works as planned. But then if I adjust the angle or move the player about the level, it all gets out of whack and nothing behaves as expected.

Here’s what I’m doing in my player object:

if message_id == hash("animation_done") then
      if (message.id == anim_fall_throw) or (message.id == anim_stand_throw) then
	        -- if message table anim id is a throwing anim then create stone
					local pos = go.get_position("player")

					if self.holding_stone then
						print('Anim complete, now throwing stone')
						msg.post("#holding_stone", "disable")
						msg.post("trajectory", "disable")

						-- Calc throw
						local x_force = math.cos(self.traj_angle) * throw_force
						local y_force = math.sin(self.traj_angle) * throw_force
						print(x_force .. ' ' .. y_force)

		                                local stone = factory.create("#stone_factory", vmath.vector3(pos.x + 20, pos.y + 64, .9), nil, { direction = self.direction }, 1)
						msg.post(stone, "apply_force", { force = vmath.vector3(x_force, y_force, 0), position = go.get_world_position("#player") })
						--msg.post(":level/stone_controller#script", "throw_stone", { player = 1, id = stone })
						self.holding_stone = false
					end

				-- resume prev animation after throw
        	msg.post("#sprite", "play_animation", {id = self.anim})
        end
    end

Here’s an example of the behavior.


Anything you can see that is obviously wrong here?

1 Like

Honestly I haven’t done any physics work in defold and I just woke up but here are my thoughts:

I don’t remember if 0,0 is in the upper left or bottom left. That being said, it seems like you just need to invert the Y value of the force being applied (multiply it by -1).

Alternatively, taking a second look, you might not be moving whatever acts as the origin point of the angle with the person (which should be wherever you’re spawning the stone from, imo) and it is calculating it from the point you start from. Posting the code for how you’re computing the traj_angle would be useful.

  • David

Ah, yeah, I didn’t post that because there’s not too much going on there.

I’m starting with the degrees and then just adjust it when you press up or down:

Note: I’m aware this code allows for 91 and -1 degree angles due to the value change by 2, I just haven’t fixed that yet…

...
    elseif action_id == input_up then
    	-- up adjust traj
			if self.direction > 0 and self.traj_angle < 90 then
	    	self.traj_angle = self.traj_angle + 2
			elseif self.direction < 0 and self.traj_angle < 90 then
	    	self.traj_angle = self.traj_angle + 2
			end
    elseif action_id == input_down then
    	-- do down adjust traj
			if self.direction > 0 and self.traj_angle > 0 then
	    	self.traj_angle = self.traj_angle - 2
			elseif self.direction < 0 and self.traj_angle > 0 then
	    	self.traj_angle = self.traj_angle - 2
			end
    end
...

I’m sure it has something to do with my self.direction not being applied properly and also negative angles not being handled properly.

EDIT: I just realized I am not applying the left-facing offset to the self.traj_angle to account for changing directions left… Probably not the whole problem, but I need to resolve that.

Okay. Can you verify that math.sin and math.cos takes the angle in degrees? If it takes it in radians, then you’ll have to convert it to radians (divide by 180 and multiply by pi)

1 Like

Oh, you may be on to something there…

From the lua manual

math.cos (x)

Returns the cosine of x (assumed to be in radians).

Let me try to fix that…

I should be able to use

math.rad (x)

Returns the angle x (given in degrees) in radians.

Right?

Yeah that should work. What do you set traj_angle to at startup?

1 Like

Works great! Didn’t need to adjust my self.traj_angle code to account for direction (1 or -1) since I could just multiply that by my x_force when i’m applying it. :smiley:

Woohoo. Thanks for the help. Gotta love it when you misuse the built in language functions. :stuck_out_tongue:

8 Likes