Jump to content
  • entries
    940
  • comments
    5,894
  • views
    863,971

Sample FPS Player Script in New Engine


Josh

1,874 views

 Share

Here is a script for a first-person player. All of this is actually working now. It's very interesting that physics, rendering, culling, and Lua game code are all executing at the same time on different threads. CPU usage in a simple scene and some physics is about 35% on a quad core processor, which is good.

I think the most interesting thing here is that to break the kinematic joint used to control an object the player picks up, you simply set the variable to nil. However, I did run into one problem with the garbage collector. If you do not call collectgarbage() after setting the joint variable to nil, the joint will not get deleted, and it will still affect the entity. This is not good. I got around this by placing a call to collectgarbage() immediately after getting rid of the joint, but I don't think I like that.  I could just make the engine call the Lua garbage collector once before the world update and once before the world render. Originally, I thought Lua would be a big problem for VR applications but since the Lua game code gets its own thread, with a maximum execution time of about 16 milliseconds just for your game code, that is plenty of time to be wasteful with the GC, and I think we will be just fine even with high-performance VR games! Remember, the rendering thread runs at 90 hz but the game logic thread only runs at 60 or even 30 hz, so it's no big deal.

However, I am leaning towards adding a Destroy() function that frees everything it can from an object without actually deleting it.

Also note that window and context are global variables. There is no "current" window or context, so this code expect that these have been created in Lua or C++ and set as global variables.

Script.lookspeed=0.1--float
Script.movespeed=3--float
Script.maxcarrymass=10--float
Script.throwforce=100--float

function Script:Start()

	--Player physics
	if self.mass==0 then self.mass=70 end
	self:EnablePhysics(PHYSICS_PLAYER)
	self.collisiontype=COLLISION_PLAYER
	
	--Set up camera
	self.camera=CreateCamera(self:GetWorld())
	local cx=Round(context:GetWidth()/2)
	local cy=Round(context:GetHeight()/2)
	window:HideMouse()
	window:SetMousePosition(cx,cy)
	self.camerarotation=self:GetRotation(true)

end

function Script:Update()

	--Mouse look
	local cx = Round(context:GetWidth()/2)
	local cy = Round(context:GetHeight()/2)
	local mousepos = window:GetMousePosition()
	window:SetMousePosition(cx,cy)
	local mx = mousepos.x - cx
	local my = mousepos.y - cy
	self.camerarotation.x = self.camerarotation.x + my * self.lookspeed
	self.camerarotation.y = self.camerarotation.y + mx * self.lookspeed
	self.camerarotation.x = Clamp(self.camerarotation.x,-90,90)
	self.camera:SetRotation(self.camerarotation,true)

	--Player movement
	local jump=0
	if window:KeyDown(KEY_SPACE) then
		if self:GetAirborne()==false then jump=6 end
	end
	if self:GetAirborne() then jump = 0 end
	local move=0
	if window:KeyDown(KEY_W) then move=move+1 end
	if window:KeyDown(KEY_S) then move=move-1 end
	local strafe=0
	if window:KeyDown(KEY_D) then strafe=strafe+1 end
	if window:KeyDown(KEY_A) then strafe=strafe-1 end
	self:SetPlayerInput(self.camerarotation.y, move*self.movespeed, strafe*self.movespeed, jump, false,0,0,true,0)
	self.camera:SetPosition(self:GetPosition(true),true)
	self.camera:Translate(0,1.7,0,true)

	--Update carried object
	if self.carryjoint~=nil then
		
		--Update kinematic joint
		local position=TransformPoint(self.carryposition,self.camera,nil)
		local rotation=TransformRotation(self.carryrotation,self.camera,nil)
		self.carryjoint:SetTarget(position,rotation)
		
		--Throw
		if window:MouseHit(MOUSE_LEFT) then
			self.carryjoint.child:AddForce(TransformNormal(0,0,1,self.camera,nil)*self.throwforce)
			self.carryjoint.child:EnableGravity(true)
			self.carryjoint=nil
			collectgarbage()
		end

	end

	--Interact with environment
	if window:KeyHit(KEY_E) then
		if self.carryjoint~=nil then

			--Drop carried object
			self.carryjoint.child:EnableGravity(true)
			self.carryjoint=nil
			collectgarbage()

		else

			--Find new object to interact with
			local pickinfo = PickInfo()
			if self.camera:Pick(0,0,10,pickinfo,0,true,0) then
				local entity=pickinfo.entity
				if entity.Activate~=nil then

					--Activate the object
					entity:Activate(self)

				else

					--Pick it up if its light enough
					if entity.mass>0 and entity.mass<=self.maxcarrymass then

						if self.carryjoint~=nil then

							--Drop carried object
							self.carryjoint=nil
							collectgarbage()

						end

						local p=entity:GetPosition(true)
						entity:EnableGravity(false)
						self.carryjoint=CreateKinematicJoint(p.x,p.y,p.z,entity)
						self.carryposition=TransformPoint(entity:GetPosition(true),nil,self.camera)
						self.carryrotation=TransformRotation(entity:GetQuaternion(true),nil,self.camera)
					end

				end
			end

		end
	end

end

 

 Share

3 Comments


Recommended Comments

Here's what I did:

--Drop carried object
self.carryjoint.child:EnableGravity(true)
self.carryjoint:Destroy()
self.carryjoint=nil

 

Link to comment

I also added getters / setters for "globalposition" and "globalrotation" so you can do this:

self.globalposition=Vec3(1,2,3)

 

Link to comment

I can't wait to write my own scripts. Nice to see physics online. ?

On the note of the Destroy function, I think Free() would be a better name. Destroy sounds like kill/delete. Free is what I name functions that clean out pointers and values with my RaspPi project.

Who knows, I may just be weird. I'd be interested in others take on it.

  • Like 1
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...