Vehicles/VehicleScripts/MovingParts.lua

MovingParts implements an option to have some translation or rotation parts that can be moved using an Input axis (either by key, by mouse or by joystick). The script is used for smooth movement of the snowcat's snow blade. You may find the script useful for any axis that should be fine-controllable.

Contrary to AnimatedParts, moving parts do not have to be in one of two fixed positions (open/closed or similar) but rather anywhere between those positions.

  27  
  28  MovingParts                         = MovingParts or {};

MovingParts:load(dataTable)

Load the configuration data for each moving part axis.

  32  function MovingParts:load(dataTable)
  33      self.setMovingPartPosition      = VehicleManager:newFunction("setMovingPartPosition");
  34  
  35      self.movingParts                = {};
  36      self.movingPartsByInputAxis     = {};
  37      self.movingPartsButtonDown      = 0;
  38  
  39      if dataTable.movingParts ~= nil then
  40          for k, v in ipairs(dataTable.movingParts) do
  41              local id                = getChild(self.id, v.index or "");
  42  
  43              if id ~= 0 then
  44                  local mp            = {};
  45                  mp.id               = id;
  46                  mp.mouseButton      = v.mouseButton or 0;
  47                  mp.mouseAxis        = v.mouseAxis   or 0;
  48  
  49                  if v.rotAxis ~= nil then
  50                      mp.rotAxis      = v.rotAxis or 1;
  51                      mp.rotMin       = v.rotMin or 0;
  52                      mp.rotMax       = v.rotMax or 0;
  53                      if v.noRotChild ~= nil then
  54                          mp.noRotChild   = getChild(self.id, v.noRotChild);
  55                      end;
  56  
  57                  elseif v.transAxis ~= nil then
  58                      mp.transAxis    = v.transAxis or 1;
  59                      mp.transMin     = v.transMin or 0;
  60                      mp.transMax     = v.transMax or 0;
  61                  end;
  62  
  63                  mp.moveSpeed        = 0.001 * (v.moveSpeed or 20);
  64                  mp.position         = v.position or 0.5;
  65  
  66                  if v.inputAxis ~= nil then
  67                      mp.inputAxis    = InputMapper[v.inputAxis];
  68                      mp.axisSpeed    = v.axisSpeed;
  69                      table.insert(self.movingPartsByInputAxis, mp);
  70                  end;
  71  
  72                  table.insert(self.movingParts, mp);
  73  
  74                  self:setMovingPartPosition(#self.movingParts, mp.position, true);
  75              end;
  76          end;
  77      end;
  78  end;

MovingParts:saveToTable(tbl)

Stores the position of each moving part in the savegame.

  82  function MovingParts:saveToTable(tbl)
  83      if tbl == nil then return end;
  84  
  85      tbl.movingParts                 = {};
  86  
  87      for k, mp in pairs(self.movingParts) do
  88          tbl.movingParts[k]          = mp.position;
  89      end;
  90  end;

MovingParts:loadFromTable(tbl)

Restores moving part positions.

  94  function MovingParts:loadFromTable(tbl)
  95      if tbl == nil then return end;
  96      if tbl.movingParts == nil then return end;
  97  
  98      for k, mp in pairs(self.movingParts) do
  99          local position              = tbl.movingParts[k];
 100          if position ~= nil then
 101              self:setMovingPartPosition(k, position);
 102          end;
 103      end;
 104  end;

MovingParts:setMovingPartPosition(key, pos, noEvent)

Sets the position of the moving part number key (int, starting with 1) to pos (float, range 0 to 1), and directly applies it to the object.noEvent (bool) specifies whether the multiplayer event shall be suppressed.

The corresponding network event is EventSetMovingPartPosition.

 110  function MovingParts:setMovingPartPosition(key, pos, noEvent)
 111      local mp                        = self.movingParts[key or 0];
 112  
 113      if mp == nil then return end;
 114  
 115      mp.position                     = clamp01(pos or 0);
 116  
 117      if mp.rotAxis ~= nil then
 118          local rotValue              = lerp(mp.rotMin, mp.rotMax, mp.position);
 119          
 120          if mp.rotAxis == 1 then
 121              setRotationX(mp.id, rotValue);
 122  
 123              if mp.noRotChild ~= nil then
 124                  setRotationX(mp.noRotChild, -rotValue);
 125              end;
 126          elseif mp.rotAxis == 2 then
 127              setRotationY(mp.id, rotValue);
 128  
 129              if mp.noRotChild ~= nil then
 130                  setRotationY(mp.noRotChild, -rotValue);
 131              end;
 132          else
 133              setRotationZ(mp.id, rotValue);
 134  
 135              if mp.noRotChild ~= nil then
 136                  setRotationY(mp.noRotChild, -rotValue);
 137              end;
 138          end;
 139      end;
 140      if mp.transAxis ~= nil then
 141          local transValue            = lerp(mp.transMin, mp.transMax, mp.position);
 142  
 143          if mp.transAxis == 1 then
 144              setPositionX(mp.id, transValue);
 145          elseif mp.transAxis == 2 then
 146              setPositionY(mp.id, transValue);
 147          else
 148              setPositionZ(mp.id, transValue);
 149          end;
 150      end;
 151  
 152      if not noEvent then
 153          EventSetMovingPartPosition:send(self, key, mp.position);
 154      end;
 155  end;

MovingParts:update(dt)

Update player input. First check each axis' inputAxis (to allow for joystick control), afterwards check whether the player wants to move it using the mouse.

 159  function MovingParts:update(dt)
 160      if not self:getIsInputActive() then
 161          return;
 162      end;
 163  
 164      -- move the blade by input axis
 165      for key, mp in pairs(self.movingPartsByInputAxis) do
 166          local inputValue            = InputMapper:getAxis(mp.inputAxis) * (mp.axisSpeed or 1);
 167  
 168          if inputValue ~= 0 then
 169              self:setMovingPartPosition(key, mp.position + inputValue * GameplaySettings.joystickSensitivity * dt);
 170          end;
 171      end;
 172  
 173      -- input is active - let's update our moving parts
 174      local lmb                       = Input.getMouseButton(0);
 175      local rmb                       = Input.getMouseButton(1);
 176      local activeMouseButton         = (lmb and rmb and 3) or (lmb and 1) or (rmb and 2) or 0;
 177  
 178      if activeMouseButton == 0 and self.movingPartsButtonDown ~= 0 then
 179          self.movingPartsButtonDown  = 0;
 180  
 181          if VehicleCamera.activeCamera ~= nil then
 182              VehicleCamera.activeCamera:setBlockInput(false);
 183          end;
 184          return;
 185      end;
 186      self.movingPartsButtonDown      = self.movingPartsButtonDown + dt;
 187  
 188      -- freeze camera after 200 ms
 189      if self.movingPartsButtonDown > 0.2 and VehicleCamera.activeCamera ~= nil then
 190          VehicleCamera.activeCamera:setBlockInput(true);
 191      end;
 192  
 193      -- there's a mouse button active
 194      for key, mp in pairs(self.movingParts) do
 195          if activeMouseButton == mp.mouseButton then
 196              -- this one is moving
 197              local mouseMovement     = 0;
 198              if mp.mouseAxis == 1 then
 199                  mouseMovement       = Input.getAxis("Mouse X");
 200              else
 201                  mouseMovement       = Input.getAxis("Mouse Y");
 202              end;
 203  
 204              self:setMovingPartPosition(key, mp.position + mouseMovement * mp.moveSpeed);
 205          end;
 206      end;
 207  end;

MovingParts:writeResync()

Resynchronizes all variables when a new player joins the game. The data sent by writeResync will be received by readResync.

 211  function MovingParts:writeResync()
 212      for k, mp in ipairs(self.movingParts) do
 213          streamWriteFloat(mp.position);
 214      end;
 215  end;

MovingParts:readResync()

Resynchronizes all variables when a new player joins the game. The data sent by writeResync will be received by readResync.

 218  function MovingParts:readResync()
 219      for k, mp in ipairs(self.movingParts) do
 220          self:setMovingPartPosition(k, streamReadFloat(), true);
 221      end;
 222  end;
 223  

All contents of this page may be used for modding use for Winter Resort Simulator - Season 2 only. Any use exceeding this regulation is not permitted.

Copyright (C) HR Innoways, 2021. All Rights Reserved.