Respawning

Our game is almost complete, but there is one situation we have not accounted for. If the player runs off the edge of the world, there is no way for them to get back to the start without restarting the game. We want them to be able to make mistakes and keep going, so let's add a mechanism to deal with this when the player "dies". We will accomplish this by using another trigger script that causes damage to the player.

Create a large box brush underneath your level. Make sure it is big enough the player will always hit it if they fall into space:

With this box still selected, select the Scene tab in the side panel. Select the General tab in the properties editor and set the name of this object to "Kill Trigger". Select the Script tab in the properties editor and press button with a folder icon to open a file open dialog. Select the file "Scripts\Objects\Triggers\TriggerPain.lua". We want this trigger to kill the player immediately, so set the damage value to 100.

If we open the TriggerPain script, we can see how it works. In the Script:Collision() function, this script will check to see if the colliding entity has a script with a TakeDamage() function declared. If the function is present, this script will call it, passing its own damage value in as a function argument. However, our player script does not have a TakeDamage() function, so without further modification this trigger will have no effect.

function Script:Collision(entity, position, normal, speed)
if self.enabled then
if entity.script then
if type(entity.script.TakeDamage)=="function" then
entity.script:TakeDamage(self.damage)
end
end
end
end

Let's open our "MyBallPlayer.lua" script again and make some modifications. First, we want the player to start with 100 health. We also want to get the player's starting position so that we can use it later to reposition them if they die. Add these two lines of code inside the Script:Start() function:

self.health = 100
self.startposition = self.entity:GetPosition()

Now we will add a TakeDamage() function so the pain trigger has something to call. Add this function at the end of the "MyBallPlayer.lua" script:

function Script:TakeDamage(damage)
self.health = self.health - 100
if self.health<=0 then
self.health=100
self.entity:SetPosition(self.startposition)
self.entity:SetRotation(0,0,0)
self.entity:SetVelocity(Vec3(0,0,0))
self.entity:SetOmega(Vec3(0,0,0))
end
end

Our new Script:TakeDamage() function will subtract health from the player when it is called. If the player's health is less than or equal to zero, then the player will respawn at their original starting position with 100 health. We also set their rotation, velocity, and omega (rotational velocity) back to zero so they can start the level over and try again. Go ahead and run the game now. You should be able to roll the ball off into space and respawn at the start of the map.

Here is the finished "MyBallPlayer.lua" script. It looks like a lot of code, but because we went through it all bit by bit, you now have a good understand of how it works and what it does:

function Script:Start()

--Create a camera
self.camera = Camera:Create()

--Update the camera
self:UpdateCamera()

--Load a custom font
self.font = Font:Load("Fonts/Ranchers-Regular.ttf",18)
self.health = 100
self.startposition = self.entity:GetPosition()
end

--This function will be called by the pain trigger
function Script:TakeDamage(damage)
self.health = self.health - 100
if self.health<=0 then
self.health=100
self.entity:SetPosition(self.startposition)
self.entity:SetRotation(0,0,0)
self.entity:SetVelocity(Vec3(0,0,0))
self.entity:SetOmega(Vec3(0,0,0))
end
end

--Adjust the camera orientation relative to the ball
function Script:UpdateCamera()
self.camera:SetRotation(45,0,0)
self.camera:SetPosition(self.entity:GetPosition())
self.camera:Move(0,0,-4)
end

function Script:UpdatePhysics()

--Get the game window
local window = Window:GetCurrent()

--Add force to the player when a key is pressed
if window:KeyDown(Key.W) then self.entity:AddForce(0,0,10,true) end
if window:KeyDown(Key.A) then self.entity:AddForce(-10,0,0,true) end
if window:KeyDown(Key.D) then self.entity:AddForce(10,0,0,true) end
if window:KeyDown(Key.S) then self.entity:AddForce(0,0,-10,true) end
end

function Script:UpdateWorld()
--Update the camera each frame
self:UpdateCamera()
end

function Script:PostRender(context)

--Set the font to a cartoonish style
if self.font~=nil then
context:SetFont(self.font)
end

if TotalCoins~=nil and CoinsCollected~=nil then

--Enable alpha blending
context:SetBlendMode(Blend.Alpha)

--Set drawing color to red
context:SetColor(1,0,0,1)

--Combine our variables into some text
local text = "Coins: "..CoinsCollected.." / "..TotalCoins

--Draw the text in the upper right corner of the screen
context:DrawText(text,context:GetWidth()-context:GetFont():GetTextWidth(text)-4,4)

end

--Restore the default font for drawing
context:SetFont(nil)

end