Free Camera
From Blue Mars Developer Guidebook
|
|
|
Free Camera script
When this entity is placed in a level, it will listen for the action to activate (F3); in free cam mode, the view is detached from the avatar and controlled with WASD or the arrow keys (to move fwd, back, left, right), space bar/left-ctrl or home/end (move up/down) and F4 to exit and return to the previous view, usually the default camera. This entity will be included in the next release, but here is the script if you want to try it out or tweak your own version (remember to update the paths to load your new action map, and register the entity).
ARFreeCam =
{
Properties = {
bSetAvatarAtFinalPos = 1, --option to transport avatar to camera position upon exiting free cam mode
bTurnOffWorldHUD = 1, --option to hide world HUD while active - use default to avoid problems such as space bar & chat in the client
fSpeedMultiplier = 1,
},
States = {
"Idle",
"Active",
},
Editor=
{
Icon="AR_Camera.bmp",
},
view = nil,
origView = nil,
pitch = 0,
yaw = 0,
inputMap = { --ar_forward, etc, are action names defined in ARFreeCamProfile action map
ar_forward = "moveForward", -- w or up arrow
ar_back = "moveBack", -- s or down arrow
ar_left = "moveLeft", -- a or left arrow
ar_right = "moveRight", -- d or right arrow
ar_zUp = "moveUp", -- space or home
ar_zDown = "moveDown", -- lctrl or end
},
inputMode = {
moveForward = {pressed = false},
moveLeft = {pressed = false},
moveBack = {pressed = false},
moveRight = {pressed = false},
moveUp = {pressed = false},
moveDown = {pressed = false},
},
bAMapWasEnabled_Player = false,
bAMapWasEnabled_Default = false,
bAMapWasEnabled_Debug = false,
}
function ARFreeCam:OnSpawn()
self.view = Game.CreateView();
Game.LinkViewTo(self.view,self.id);
end
function ARFreeCam:OnInit()
self:GotoState("Idle");
if (not System.IsEditor()) then
MMO:RegisterStartCallback( function() self:Initialize(); end );
else
self:Initialize();
end
end
function ARFreeCam:OnDestroy()
Game.DeleteView(self.view);
HUD.UnregisterActionCallback(self.actionCallbackID);
self.actionCallbackID = nil;
end
function ARFreeCam:OnReset()
self:OnInit();
end
function ARFreeCam:Initialize()
if (not ActionMapManager.IsActionMapLoaded("ARFreeCam")) then
ActionMapManager.LoadFromXML("libs/config/ar/arfreecamprofile.xml");
end
if (not ActionMapManager.IsActionMapEnabled("ARFreeCam")) then
ActionMapManager.EnableActionMap("ARFreeCam", true);
end
self.actionCallbackID = HUD.RegisterActionCallback(self.OnAction, self);
end
function ARFreeCam:GetAvatar()
if (System.IsEditor()) then
if (not System.IsPreviewMode()) then --Note: System.IsPreviewMode not available in Dec 09 release
return System.GetEntityByName("Dude"); --for Ctrl-G in City Editor
end
end
return MMO:GetLocalAvatarEntity(); -- for Blue Mars client, or Preview Mode in City Editor
end
function ARFreeCam:DisableActionMaps()
if (ActionMapManager.IsActionMapEnabled("player")) then
ActionMapManager.EnableActionMap("player",false);
self.bAMapWasEnabled_Player = true;
end
if (ActionMapManager.IsActionMapEnabled("debug")) then
ActionMapManager.EnableActionMap("debug",false);
self.bAMapWasEnabled_Debug = true;
end
if (ActionMapManager.IsActionMapEnabled("default")) then
ActionMapManager.EnableActionMap("default",false);
self.bAMapWasEnabled_Default = true;
end
end
function ARFreeCam:ReenableActionMaps()
if (self.bAMapWasEnabled_Player) then
ActionMapManager.EnableActionMap("player",true);
end
if (self.bAMapWasEnabled_Default) then
ActionMapManager.EnableActionMap("default",true);
end
if (self.bAMapWasEnabled_Debug) then
ActionMapManager.EnableActionMap("debug",true);
end
end
function ARFreeCam:UpdateMouse()
local cx = math.floor(0.5*HUD.GetWidth());
local cy = math.floor(0.5*HUD.GetHeight());
local wx,wy = System.GetWindowMouse();
System.SetWindowMouse(cx, cy);
local dx = wx - cx;
local dy = wy - cy;
local dx = clamp(dx, -cx, cx);
local dy = clamp(dy, -cy, cy);
return dx, dy;
end
-- Key events -----------------------------------------------------------
function ARFreeCam:OnAction(action, activationMode)
--System.Log("ARFreeCam:OnAction ".. action .." mode: ".. activationMode);
if (action ~= "ar_f3") and (self:GetState() ~= "Active") then
return;
end
if (activationMode == 1) then
self:OnKeyPressed(action);
elseif (activationMode == 2) then
self:OnKeyReleased(action);
end
end
function ARFreeCam:OnKeyPressed(keyName)
if (keyName == "ar_f3") then
self:GotoState("Active");
elseif (keyName == "ar_f4") then
self:GotoState("Idle");
end
local input = self.inputMap[keyName];
if (input) then
self.inputMode[input].pressed = true;
end
end
function ARFreeCam:OnKeyReleased(keyName)
local input = self.inputMap[keyName];
if (input) then
self.inputMode[input].pressed = false;
end
end
function ARFreeCam:IsPressed(input)
return self.inputMode[input].pressed;
end
function ARFreeCam:ResetAllInput()
for i,state in pairs(self.inputMode) do
state.pressed = false;
end
end
--------------------------------------------------------------------------
ARFreeCam.Active =
{
OnBeginState = function(self)
ARDebugMessage("Free Camera mode!");
self:DisableActionMaps();
self.origView = Game.GetActiveView();
Game.SetActiveView(self.view);
self:Activate(1);
if (not System.IsEditor() and self.Properties.bTurnOffWorldHUD == 1) then
ARVirtualWorld.Instance:HideHUD();
end
self:UpdateMouse();
self:ResetAllInput();
-- move the freecam to the avatar (plus 2m z)
local avatar = self:GetAvatar();
if (avatar) then
self:SetWorldPos(SumVectors(avatar:GetWorldPos(), ScaleVector(g_Vectors.up,2)));
self:SetWorldAngles(avatar:GetWorldAngles());
self.pitch = 0;
self.yaw = avatar:GetWorldAngles().z + g_Pi2;
end
end,
OnUpdate = function(self,time)
if (System.HasFocus()) then --stop cursor set upon switching to another window. Note: System.HasFocus not available in Dec 09 release
-- handle input
local dx, dy = self:UpdateMouse();
self.yaw = self.yaw - dx*0.25*g_Deg2Rad;
self.pitch = self.pitch - dy*0.25*g_Deg2Rad;
self.pitch = clamp(self.pitch, -80*g_Deg2Rad, 80*g_Deg2Rad);
local move = g_Vectors.temp_v1;
CopyVector(g_Vectors.temp_v1, g_Vectors.v000);
if (self:IsPressed("moveLeft")) then move.x = move.x - 10*self.Properties.fSpeedMultiplier; end
if (self:IsPressed("moveRight")) then move.x = move.x + 10*self.Properties.fSpeedMultiplier; end
if (self:IsPressed("moveBack")) then move.y = move.y - 10*self.Properties.fSpeedMultiplier; end
if (self:IsPressed("moveForward")) then move.y = move.y + 10*self.Properties.fSpeedMultiplier; end
if (self:IsPressed("moveUp")) then move.z = move.z + 10*self.Properties.fSpeedMultiplier; end
if (self:IsPressed("moveDown")) then move.z = move.z - 10*self.Properties.fSpeedMultiplier; end
-- update camera
local dir = g_Vectors.temp_v2;
dir.x = math.cos(self.pitch)*math.cos(self.yaw);
dir.y = math.cos(self.pitch)*math.sin(self.yaw);
dir.z = math.sin(self.pitch);
self:SetWorldVDir(dir);
local pos = g_Vectors.temp_v3;
CopyVector(pos, self:GetWorldPos());
FastSumVectors(pos, pos, ScaleVector(self:GetDirectionVector(0), move.x*time));
FastSumVectors(pos, pos, ScaleVector(self:GetDirectionVector(1), move.y*time));
FastSumVectors(pos, pos, ScaleVector(g_Vectors.up, move.z*time));
self:SetWorldPos(pos);
end
-- print HUD
HUD.Draw2DLabel(10, 10, 2, "F4 to exit Free Camera mode");
end,
OnEndState = function(self)
Game.SetActiveView(self.origView);
self:Activate(0);
if (not System.IsEditor() and self.Properties.bTurnOffWorldHUD) then
ARVirtualWorld.Instance:ShowHUD();
end
if (self.Properties.bSetAvatarAtFinalPos == 1) then
--move the avatar to the freecam
local avatar = self:GetAvatar();
if (avatar) then
avatar:SetWorldPos(self:GetWorldPos());
avatar:SetDirectionVector(self:GetDirectionVector(), g_Vectors.v001);
--fixme: preview mode walking toward previous location
if (not System.IsEditor()) then
avatar.ARAvatarAction:StartIdle();
end
end
end
end,
}
ARFreeCam.Idle =
{
OnBeginState = function(self)
self:ReenableActionMaps();
end,
}
Action Map
The Action Map, ARFreeCamProfile.xml. If you are creating your own, the action map and action names should be changed, the file should be placed in your Libs/Config directory and referenced by the ActionMapManager.LoadFromXML file path (starting from "levels/...") in the free cam script.
<?xml version="1.0" encoding="utf-8"?>
<ActionMaps>
<actionmap name="ARFreeCam" version="21">
<action name="ar_f3" onPress="1">
<key name="f3" />
</action>
<action name="ar_f4" onPress="1">
<key name="f4" />
</action>
<action name="ar_forward" onPress="1" onRelease="1">
<key name="up" />
<key name="w" />
</action>
<action name="ar_back" onPress="1" onRelease="1">
<key name="down" />
<key name="s" />
</action>
<action name="ar_left" onPress="1" onRelease="1">
<key name="left" />
<key name="a" />
</action>
<action name="ar_right" onPress="1" onRelease="1">
<key name="right" />
<key name="d" />
</action>
<action name="ar_zUp" onPress="1" onRelease="1">
<key name="space" />
<key name="home" />
</action>
<action name="ar_zDown" onPress="1" onRelease="1">
<key name="lctrl" />
<key name="end" />
</action>
</actionmap>
</ActionMaps>
Author: tweaked & updated by Magnolia @ AR, based on VSE's free cam

