Jump to content

Shortest rotation path


Rick
 Share

Recommended Posts

Just testing something. Imagine you had a top down camera view and you moved the character controller with WASD. No rotation just forward/backward strafe left/right. However, the player avatar isn't the controller. It's separate but it's position is set to the controllers. However if you rotate the model to face the direction the controller is going then if the controller is strafing left the model rotates left, if going forward the model faces forward, etc (includes diagonals).

So I have a check on the move and strafe variables that get passed to SetInput() that determines what the angle is to rotate the model. Values 0 - 315 increasing by 45 degrees. They are hardcoded though. If press 'S' then the angle is 0, if 'W' then the angle is 180, if 'A' then the angle is 90 and if 'D' then the angle is 270. If the current angle is > 180 and you press 'S' key to move it back to 0, it will take the long way around to get back to 0 (I use Math:Curve to smooth the current/target values). So the question is how can I get this rotation so it doesn't take the long way around.

function Script:Start()
	self.window = Window:GetCurrent()
	self.model = Model:Load("Models/Knight/Knight Arthur Mecanim.mdl")
	self.model:SetScale(Vec3(0.01, 0.01, 0.01))

	self.model:SetPosition(self.entity:GetPosition(true), true)

	self.damping = 5
	self.rot = 0
	self.targetRot = 0
	self.pos = self.entity:GetPosition(true)
end

function Script:CalcShortestRot(current, target)
	local dist = target - current + 180
	dist = dist - math.floor(dist / 2 / 180) * 2 * 180 - 180

	if dist < 0 then
		return current - dist
	elseif dist > 0 then
		return current + dist
	else
		return target
	end
end

function Script:UpdateWorld()
	local move = ((window:KeyDown(Key.W) and 1 or 0) - (window:KeyDown(Key.S) and 1 or 0))*4
	local strafe = ((window:KeyDown(Key.D)and 1 or 0) - (window:KeyDown(Key.A) and 1 or 0))*4
	local jump = (window:KeyHit(Key.Space) and 1 or 0)*8

	self.entity:SetInput(0,move,strafe,jump,false)

	-- position the model at the character controllers position
	local pos = self.entity:GetPosition(true)
	self.pos.x = Math:Curve(pos.x, self.pos.x, self.damping)
	self.pos.y = Math:Curve(pos.y, self.pos.y, self.damping)
	self.pos.z = Math:Curve(pos.z, self.pos.z, self.damping)

	self.model:SetPosition(self.pos)

	-- determine the model rotation based on direction we are going
	if move > 0 then
		if strafe > 0 then
			self.targetRot = self:CalcShortestRot(self.targetRot, 225)
			--self.targetRot = 225
		elseif strafe < 0 then
			--self.targetRot = 135
			self.targetRot = self:CalcShortestRot(self.targetRot, 135)
		else
			--self.targetRot = 180
			self.targetRot = self:CalcShortestRot(self.targetRot, 180)
		end
	elseif move < 0 then
		if strafe > 0 then
			--self.targetRot = 315
			self.targetRot = self:CalcShortestRot(self.targetRot, 315)
		elseif strafe < 0 then
			--self.targetRot = 45
			self.targetRot = self:CalcShortestRot(self.targetRot, 45)
		else
			--self.targetRot = 360
			self.targetRot = self:CalcShortestRot(self.targetRot, 360)
		end
	elseif strafe > 0 then
		--self.targetRot = 270
		self.targetRot = self:CalcShortestRot(self.targetRot, 270)
	elseif strafe < 0 then
		--self.targetRot = 90
		self.targetRot = self:CalcShortestRot(self.targetRot, 90)
	end

	self.rot = Math:Curve(self.targetRot, self.rot, self.damping)

	self.model:SetRotation(Vec3(0, self.rot, 0), true)
end

 

Link to comment
Share on other sites

Refer to the LE2 math.lua script which had useful functions to address this.

 

math.lua

 

Granted looking over the wiki, LE4 may already have this code incorporated into Math:DeltaAngle()Math:CurveAngle(), and Math:IncAngle(). It appears you are trying to re-invent what Josh has already provided to you.

  • Upvote 1

Win7 64bit / Intel i7-2600 CPU @ 3.9 GHz / 16 GB DDR3 / NVIDIA GeForce GTX 590

LE / 3DWS / BMX / Hexagon

macklebee's channel

Link to comment
Share on other sites

Adding the value Math:DeltaAngle() returned did the trick thanks. For future reference and others who may wish to know:

    -- determine the model rotation based on direction we are going
	if move > 0 then
		if strafe > 0 then
			self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 225)
		elseif strafe < 0 then
			self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 135)
		else
			self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 180)
		end
	elseif move < 0 then
		if strafe > 0 then
			self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 315)
		elseif strafe < 0 then
			self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 45)
		else
			self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 0)
		end
	elseif strafe > 0 then
		self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 270)
	elseif strafe < 0 then
		self.targetRot = self.targetRot + Math:DeltaAngle(self.targetRot, 90)
	end

    self.rot = Math:Curve(self.targetRot, self.rot, self.damping)

	self.model:SetRotation(Vec3(0, self.rot, 0), true)

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...