In Leadwerks FPS game, if you want to do something like Leaning, HeadBobbing, ThirdPersonView, modifing default FPSCharacterController to fit these needs is a painful task. But it is much easier when you make your own Character Controller (CC) then alter it.
This tutorial series will guide you to:
- Create a CC which can: Move, Look around from scratch.
- Implement advanced actions: Lean, Jump, Run, Crouch
I. Create a basic CC
Step 1: Understand CC's components
- PlayerBase (Blue): Control Player Movement (Forward, Backward, Strafe Left/Right and Jump)
- PlayerNeck (Yellow): Control Player Mouse Look function.
- PlayerEyes (White): Yes, it is just a camera, will be controlled by PlayerNeck (its parent)
- CameraLead (Pink): Where the camera is pointed at (this is useful for Leaning process in later part of this series)
For your curiousity
- What is PlayerNeck for ? Why don't just apply MouseLook on Camera ?
In reallife, when you look up / down, your neck will be static, only head moves around and your eyes are attached to your head so that they move too. This will help you to see your feet model if need.
- Why CameraLead ?
In reallife, you can keep your head straight and move your eyes to look around, right? CameraLead solve that. This is useful for Leaning and HeadBobbing process too.
Step 2: Setup CC's components
- In Leadwerks Editor, create a large platform by using Primitive Box > Rename to "Ground"
- Create another box(es) for obtacle test.
- Create a new Pivot > rename to "CharacterController", put it above "Ground"
- Create new script > rename to "CharacterControl.lua > Apply it to "CharacterController" Pivot
Here is the code
--Character components variables Script.playerWeight = 10 --Adjustable, not really important, this variable affects how player interact to other physical objects Script.playerHeight = 1.7 Script.neckLength = 0.2 Script.leadDistance = 10 --Character movement variables Script.playerSpeed = 2 --higer = faster --Character look variables Script.camerarotation = Vec3() Script.playerFOV = 70 --Default player field of view Script.lookUpLimit = -70 Script.lookDownLimit = 80 --Adjust lookUpLimit and lookDownLimit for your experiment function Script:Setup_Character_Components() --Create Player Base self.playerBase = self.entity self.playerBase:SetMass(1) self.playerBase:SetCollisionType(Collision.Character) self.playerBase:SetPhysicsMode(Entity.CharacterPhysics) --Create Player Neck self.playerNeck = Pivot:Create() --Do not make playerBase become playerNeck's parent, it will be a infinitive loop for Mouse Look self.playerNeck:SetPosition(--default position for playerNeck self.playerBase:GetPosition(true).x, self.playerBase:GetPosition(true).y + self.playerHeight - self.neckLength, self.playerBase:GetPosition(true).z) --Create Player Camera self.playerEyes = Camera:Create() self.playerEyes:SetParent(self.playerNeck) self.playerEyes:SetFOV(self.playerFOV) self.playerEyes:SetPosition(Vec3(0,self.neckLength,0)) --Create Camera Lead, remember, this is good for Leaning action self.cameraLead = Pivot:Create() self.cameraLead:SetParent(self.playerNeck) self.cameraLead:SetPosition(0,0,self.leadDistance) end function Script:Character_Look() local sx = Math:Round(context:GetWidth()/2) local sy = Math:Round(context:GetHeight()/2) local mouseposition = window:GetMousePosition() local dx = mouseposition.x - sx local dy = mouseposition.y - sy --Limit Look up / Look down angle, the fact is you can not look up 90 degrees most of time.. ehehe just kidding self.camerarotation.x = Math:Clamp(self.camerarotation.x + dy,self.lookUpLimit,self.lookDownLimit) self.camerarotation.y = self.camerarotation.y + dx --Smooth camera rotation local neckRot = self.playerNeck:GetRotation() self.camerarotation.x = Math:Curve(self.camerarotation.x,neckRot.x,10) self.camerarotation.y = Math:Curve(self.camerarotation.y,neckRot.y,10) self.playerNeck:SetRotation(self.camerarotation) window:SetMousePosition(sx,sy,0) end function Script:Character_Movement() local playerMove = ((window:KeyDown(Key.W) and 1 or 0) - (window:KeyDown(Key.S) and 1 or 0)) * self.playerSpeed local playerStrafe = ((window:KeyDown(Key.D)and 1 or 0) - (window:KeyDown(Key.A) and 1 or 0)) * self.playerSpeed local playerTurn = self.playerNeck:GetRotation(true).y self.playerBase:SetInput(playerTurn,playerMove,playerStrafe,0,false) end function Script:Bind_Character_Components_Together() local basePos = self.playerBase:GetPosition(true) --Must use this reposition process because playerBase is not playerNeck's parent, they are indipendent. self.playerNeck:SetPosition(basePos.x,basePos.y + self.playerHeight - self.neckLength,basePos.z) end function Script:Start() self:Setup_Character_Components() end function Script:UpdateWorld() self:Bind_Character_Components_Together() self:Character_Look() self:Character_Movement() end
Press F6 to start. Now you can move around by using AWSD, look around by using mouse and movement is blocked by an obtacle. So basic, so pure
Next tutorial about Lean, Jump, Run, Crouch coming soon!