Jump to content
  • entries
    9
  • comments
    38
  • views
    9,609

Create your own FPS Character Controller in LUA - Part 2


tipforeveryone

4,223 views

 Share

II. Implement advanced actions

Previous tutorial guided you to create your own FPS Character Controller with basic actions: Move, Look.

This tutorial will help you add some advanced actions like Jump, Run, Crouch, and Lean

*Note: Below steps will use code from previous tutorial (CharacterController.lua)

1. Jump / Run / Crouch

Firstly, build obtacle with space under it to test crouching, the space height shoud be at least 120cm (leadwerks editor will show you this height in other viewports) You can not crouch and pass space under 120cm, this was hardcoded

crouchheightest_zpsjy2bkvjg.jpg

crouchheightest2_zpshwme61xh.jpg

Next, modify the code.

Add new variables under --Character movement variables comment. Note that putting script variables at the top of script will allow you to modify character stat easier and faster than finding variables deep inside script's functions

--Character movement variables
Script.playerSpeed = 2 --higer = faster
Script.playerRunSpeedMultipier = 2 --if this variable < 1, you can make slower movement
Script.playerJumpForce = 7 --This defines how high you can jump
Add new funtion to smooth movement of character components
function Script:SmoothPosition(position,entity,rate)
local smoothX = Math:Curve(position.x,entity:GetPosition().x,rate)
local smoothY = Math:Curve(position.y,entity:GetPosition().y,rate)
local smoothZ = Math:Curve(position.z,entity:GetPosition().z,rate)
entity:SetPosition(smoothX,smoothY,smoothZ)
end
Replace code in Character_Movement() function by this code
function Script:Character_Movement()
	local playerSpeed, playerJumpForce, playerCrouch

	--Press Space bar to Jump
	if window:KeyHit(Key.Space) then playerJumpForce = self.playerJumpForce else playerJumpForce = 0 end

	--Hold Ctrl key to Crouch
	if window:KeyDown(Key.ControlKey) then
		playerCrouch = true
	else
		if self.playerHeadBlocked then playerCrouch = true else playerCrouch = false end
	end

	--Hold Shift key + AWSD to Run
	if window:KeyDown(Key.Shift) then
		playerSpeed = self.playerSpeed * self.playerRunSpeedMultipier
	else
		playerSpeed = self.playerSpeed
	end

	local playerMove = ((window:KeyDown(Key.W) and 1 or 0) - (window:KeyDown(Key.S) and 1 or 0)) * playerSpeed
	local playerStrafe = ((window:KeyDown(Key.D)and 1 or 0) - (window:KeyDown(Key.A) and 1 or 0)) * playerSpeed
	--Using local playerSpeed varialbe instead of self.playerSpeed in the old code
	local playerTurn = self.playerNeck:GetRotation(true).y

	self.playerBase:SetInput(playerTurn,playerMove,playerStrafe,playerJumpForce,playerCrouch)
end
Replace code in Bind_Character_Components_Together() function too
function Script:Bind_Character_Components_Together()
	--Must use this reposition process because playerBase is not playerNeck's parent, they are indipendent.

	local basePos = self.playerBase:GetPosition(true)
	local height

	if window:KeyDown(Key.ControlKey) then
		height = basePos.y + (self.playerHeight - self.neckLength) / 2
		--You can adjust this variable to get desired crouch height for playerNeck (and playerEyes too)
	else
		if self.playerHeadBlocked then
			height = basePos.y + (self.playerHeight - self.neckLength) / 2
		else
			height = basePos.y + self.playerHeight - self.neckLength
		end
	end

	self:SmoothPosition(Vec3(basePos.x,height,basePos.z),self.playerNeck,10)
end
Add a new function to script, this will keep player crouching if something block above character when release Ctrl key, prevent from being pushed around by obtacle when standing.
function Script:Check_Head_Block()
	--We can use a raycast to check if something block character head when crouching
	local pickInfo = PickInfo()
	local point1 = self.playerNeck:GetPosition(true)
	local point2 = self.playerBase:GetPosition(true) + Vec3(0,self.playerHeight,0)
	if world:Pick(point1,point2,pickInfo,0.3,true) then
		self.playerHeadBlocked = true
	else
		self.playerHeadBlocked = false
	end
end
Update Script:UpdateWorld() function with new Check_Head_Block() function
function Script:UpdateWorld()
	self:Bind_Character_Components_Together()
	self:Check_Head_Block()
	self:Character_Look()
	self:Character_Movement()
end
Now, you can crouch under obtacle, release Ctrl Key and you are still crouching. Continue moving for auto standing.

2. Leaning

In Character_Movement() function, add this code after Crouching code

--Hold Q/E to lean Left/Right
local leanDistance = 0.025 --leanDistance should be < 0.025 or camera will pass through wall when you get too close
if window:KeyDown(Key.Q) then self.playerEyes:Move(-leanDistance,-0.01,0) end
if window:KeyDown(Key.E) then self.playerEyes:Move(leanDistance,-0.01,0) end
And add this line at the bottom of Bind_Character_Components_Together() function
self:SmoothPosition(Vec3(0,self.neckLength,0),self.playerEyes,10)
You can lean now, so smooth.

Final script file was attached to this entry. You can apply it to a pivot point (PlayerControl).

CharacterController.lua

  • Upvote 9
 Share

5 Comments


Recommended Comments

I have recently come back to this blog to go through the code again to make a character controller and I seem to be getting an issue with the player camera. I have attached my script to a CSG box and when I move the camera rotates but doesn't follow the box, it's as if the camera's position is fixed but I can still rotate it. Not to sure where I have gone wrong as all I have done is copy and paste the code.

Link to comment

If you press the jump button while in the air you can still jump, you can fix this by using raycasts to find if the player is grounded or not.

Link to comment
Guest
Add a comment...

×   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.

×
×
  • Create New...