Free Camera

From Blue Mars Developer Guidebook

Jump to: navigation, search
There are security restrictions on this article

Contents


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

Back to the Script Center

Problems with this wiki page? Contact us either by: Support Email or Support Ticket System

Blue Mars Guidebook Privacy Policy
Blue Mars Guidebook Community Guidelines

Personal tools