Lua Boat Script
From Blue Mars Developer Guidebook
Hi folks, I have been working on this script based on Tim's Ride-able turtle script. Please enjoy. No warranty, contact me via PM or email if you need some help installing or customizing. Here is the Lua:
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--This script is based on the rideableturtle script that was:
--Created by Tim Webb
--tim@avatar-reality.com
--Property of Avatar Reality Inc.
--This is a sample of how to create an animated vehicle for BlueMars
--This code is valid and pertinent only to BlueMars City developers
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--Further modified by Corey Evans from Gridrock City on Blue Mars to include physics for impluses and turn.
--I have removed the animated entity sections for simplicity.
--General overview of how to use this script: (It assumes you have some knowledge of Lua entities in Blue Mars,
--if you need help installing it please contact whyroc@in2orbit.net)
--1.You need to create an entity .ent file and rename script references where needed
--2.You will have to add or edit a default action map configuration for the level
--3.A suitable geometry must be made with proxies and shaped in a boat like way
--4.Post any modifications or improvements for all to benefit
--------------------------------------------------------------------------
--------------------------------------------------------------------------
GRC_vehicle = {
Properties = {
bDisableSeeThrough = 1,
},
States = {"Idle","Moving"},--some states so we can go dormant when we are not being ridden
speed = 40, --maximum impulse value
actionCallbackId = nil,--we'll use this to make sure we don't register ourself for more than one action callback
rideroffset = {x=0,y=0,z=0.1},--where the rider will be when they get on the turtle
dismountoffset = {x=2,y=0,z=0},--where the rider will be when they get off the turtle
motorposition = {x=0,y=0,z=0},
rider = nil,
walking = false,--moving
speedfwd = 0,
stopheight = 32,--a cut off should be just above you wave highest level. This will stop the boat from flying into the air off a big wave.
turnforce = 0,
--variables for turning off the default actions maps
actionCallbackID = 0,
bAMapWasEnabled_Player = false,
bAMapWasEnabled_Default = false,
bAMapWasEnabled_Debug = false,
}
--from New_co city example functions to enable / disable action maps
function GRC_vehicle:DisableActionMaps()
if (ActionMapManager.IsActionMapEnabled("player")) then
ActionMapManager.EnableActionMap("player",false);
self.bAMapWasEnabled_Player = true; System.Log("Disabled PLAYER ACTION MAP");
end
if (ActionMapManager.IsActionMapEnabled("default")) then
ActionMapManager.EnableActionMap("default",false);
self.bAMapWasEnabled_Default = true; System.Log("Disabled DEFAULT ACTION MAP");
end
if (ActionMapManager.IsActionMapEnabled("debug")) then
ActionMapManager.EnableActionMap("debug",false);
self.bAMapWasEnabled_Debug = true; System.Log("Disabled DEBUG ACTION MAP");
end
end
function GRC_vehicle:ReenableActionMaps()
if (self.bAMapWasEnabled_Player) then
ActionMapManager.EnableActionMap("player",true);
System.Log("Enabled PLAYER ACTION MAP ")
end
if (self.bAMapWasEnabled_Default) then
ActionMapManager.EnableActionMap("default",true);
System.Log("Enabled DEFAULT ACTION MAP ")
end
if (self.bAMapWasEnabled_Debug) then
ActionMapManager.EnableActionMap("debug",true);
System.Log("Enabled DEBUG ACTION MAP ");
end
end
--OnInit() runs when we are in the client
function GRC_vehicle:OnInit()
--This way we'll call OnReset() when we load in the client so our results should be the same in editor and client.
self:OnReset();
end
--OnReset() runs when we are in the editor
function GRC_vehicle:OnReset()
self:LoadObject(0,"Levels/I2O/Common/Objects/Vehicles/boat6.cgf");--your BOAT MODEL here
self:Physicalize(0,PE_RIGID,{mass=10,density=0});--Set a starting mass
--set physics here, mass should be from 10-30 , experiment with buoancy settings. The shape of your boat (its proxy)
--will have a big effect on the responsiveness.
self:SetPhysicParams( PHYSICPARAM_SIMULATION, {mass= 20, sleep_speed = 0.04,damping = 10,max_logged_collisions = 1,max_time_step = 0.04,min_energy = 0.0016, });
self:SetPhysicParams( PHYSICPARAM_BUOYANCY, {water_density = 8, water_damping = 20, water_resistance = 10 });
--now go to an idle state
self:GotoState("Idle");
end
--OnSelect will allow something to happen when we click on the turtle
function GRC_vehicle:OnSelect( avatarEntity, dist, destPos, destNormal )
--Move player to rideroffset and parent them to the turtle
self.rider = avatarEntity;--let's remember who is on us so we can take them off later
self.rider:SetPos(SumVectors(self:GetPos(),self.rideroffset));--let's move the rider to the riding spot
self:AttachChild(self.rider.id,ATTACHMENT_KEEP_TRANSFORMATION);--and attach the rider to move with us.
--this is where there is a problem in the client, the avatar does not stay stuck as well, at low acceleration is useable.
--problem is known by AR staff.
ActionMapManager.EnableActionMap("seavehicle",true);
System.Log("Enabled seavehicle ACTION MAP ");
self:DisableActionMaps();
self:GotoState("Moving");
end
GRC_vehicle.Idle =
{
OnBeginState = function(self)
--Make sure we are not on the active entities list and not getting Updates.
--This doesn't mean your script will go away, you can still call OnSelect to ride again.
self:Activate(0);
end,
OnUpdate = function(self, time )
end,
OnEndState = function(self)
end,
}
GRC_vehicle.Moving =
{
OnBeginState = function(self)
--since we need to have OnUpdate called for movement
self:Activate(1);
--This next call will make the system let us know when a key has been pressed so we can move the turtle
if(not self.actionCallbackId)then --we don't want to register more than once
self.actionCallbackId = HUD.RegisterActionCallback(self.Moving.OnAction, self);
end
end,
--here are the events, wasd + space bar to dismount
OnAction = function(self, action, activationMode)
if(action ~= "") then
local currentdir = self:GetDirectionVector();
if(action == "v_moveforward") then
if(self.speedfwd <= self.speed) then
self.speedfwd = self.speedfwd + 5;
System.Log(tostring(self.speedfwd));
end
self.walking = true;
end
if(action == "v_brake")then
self:GotoState("Idle");
end
if(action=="v_moveback")then
if(self.speedfwd >= -self.speed) then
self.speedfwd = self.speedfwd - 5;
System.Log(tostring(self.speedfwd));
end
end
if(action == "v_turnleft") then
self.turnforce = self.turnforce - 1;
System.Log(tostring(self.turnforce));
end
if(action == "v_turnright") then
self.turnforce = self.turnforce + 1;
System.Log(tostring(self.turnforce));
end
end
end,
--here are the important bits, we are pushing the boat in its forward direction as well as rolling it and turning it
OnUpdate = function(self, time )
if(self.walking == true)then
local currentdir = self:GetDirectionVector();
local height = self:GetPos();
if (height.z < self.stopheight)then
self:AddImpulse(-1, self.motorposition,currentdir, self.speedfwd,0,{x=0,y=0,z=-1},self.turnforce);--fwd and turn
self:AddImpulse(-1, self.motorposition,currentdir, 0,0,SumVectors(currentdir,{x=0,y=1,z=0}),self.turnforce * 0.1);--roll
else
self.speedfwd = 0;
turnforce = 0;
self.walking = false;
end
end
end,
OnEndState = function(self)
self.walking = false;
self.speedfwd = 0;
self.turnforce = 0;
--Get off the tutrle
--First detach the rider so they don't move with us anymore
self:DetachAll(ATTACHMENT_KEEP_TRANSFORMATION);
--alternatively if you had more than one passenger you could call self.rider:DetachThis(0) on whichever rider you wanted off.
--then move them to a safe spot
self.rider:SetPos(SumVectors(self:GetWorldPos(),self.dismountoffset));
--self.rider:EnableGroundAlignment( 0, true );
self:ReenableActionMaps();
ActionMapManager.EnableActionMap("vehicle",false);
--We don't need to be getting keyboard input right now
--HUD.UnregisterActionCallback(self.actionCallbackId);
self.actionCallbackId = nil;
end,
}
You will need to create a default action map 'defaultprofile.xml' in Blue Mars City Developer Tools\Game\Levels\I2O\Common\Libs\Config, see New co city example for details.
<ActionMaps>
<actionmap name="NEWCOExample" version="21">
<action name="newco_mouseclick" onPress="1">
<key name="mouse1" />
</action>
<action name="newco_arrowup" onPress="1">
<key name="up" />
<key name="np_8" />
</action>
<action name="newco_arrowdown" onPress="1">
<key name="down" />
<key name="np_2" />
</action>
</actionmap>
<actionmap name="seavehicle" version="21">
<action name="v_boost" onPress="1" onRelease="1" onHold="1" retriggerable="1">
<key name="lshift" />
<key name="xi_shoulderl" />
</action>
<action name="v_brake" onPress="1" onRelease="1">
<key name="space" />
<key name="xi_a" />
</action>
<action name="v_moveforward" onPress="1" onRelease="1" retriggerable="1">
<key name="w" />
</action>
<action name="v_moveback" onPress="1" onRelease="1" retriggerable="1">
<key name="s" />
</action>
<action name="v_turnleft" onPress="1" onRelease="1" retriggerable="1" onHold="0">
<key name="a" />
</action>
<action name="v_turnright" onPress="1" onRelease="1" retriggerable="1" onHold="0">
<key name="d" />
</action>
</actionmap>
</ActionMaps>
