LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

GuiTopDownCamera

Description
Top-down camera used for UI. Provides a birds-eye view for players when they need to interact with the world from the UI (e.g. placing objects, modifying terrain).
Functions

activate

Description
Activate the camera and change the game's viewpoint to it.
Definition
activate()
Code
189function GuiTopDownCamera:activate()
190 self.inputManager:setShowMouseCursor(true)
191 self:onInputModeChanged({self.inputManager:getLastInputMode()})
192
193 self:updatePosition()
194
195 self.previousCamera = getCamera()
196 setCamera(self.camera)
197
198 -- Leave the player so it is not visible and use player position as initial focus.
199 if self.controlledPlayer ~= nil then
200 local x, y, z = getTranslation(self.controlledPlayer.rootNode)
201 self.lastPlayerPos[1], self.lastPlayerPos[2], self.lastPlayerPos[3] = x, y, z
202 self.lastPlayerTerrainHeight = getTerrainHeightAtWorldPos(self.terrainRootNode, x, 0, z)
203
204 -- self.controlledPlayer:onLeave()
205 self.controlledPlayer:setVisibility(true)
206 end
207
208 self:resetToPlayer()
209
210 self:registerActionEvents()
211 self.messageCenter:subscribe(MessageType.INPUT_MODE_CHANGED, self.onInputModeChanged, self)
212
213 self.isActive = true
214end

applyMovement

Description
Apply a movement to the camera (and view).
Definition
applyMovement()
Code
352function GuiTopDownCamera:applyMovement(dt)
353 -- Smooth updates of camera
354 -- This lerps towards the target. Due to a constant alpha it will automatically
355 -- change faster if target is further away.
356
357 local xChange = (self.targetCameraX - self.cameraX) / dt * 5
358 if xChange < 0.0001 and xChange > -0.0001 then
359 self.cameraX = self.targetCameraX
360 else
361 self.cameraX = self.cameraX + xChange
362 end
363
364 local zChange = (self.targetCameraZ - self.cameraZ) / dt * 5
365 if zChange < 0.0001 and zChange > -0.0001 then
366 self.cameraZ = self.targetCameraZ
367 else
368 self.cameraZ = self.cameraZ + zChange
369 end
370
371 local zoomChange = (self.targetZoomFactor - self.zoomFactor) / dt * 2
372 if zoomChange < 0.0001 and zoomChange > -0.0001 then
373 self.zoomFactor = self.targetZoomFactor
374 else
375 self.zoomFactor = MathUtil.clamp(self.zoomFactor + zoomChange, 0, 1)
376 end
377
378
379 local tiltChange = (self.targetTiltFactor - self.tiltFactor) / dt * 5
380 if tiltChange < 0.0001 and tiltChange > -0.0001 then
381 self.tiltFactor = self.targetTiltFactor
382 else
383 self.tiltFactor = MathUtil.clamp(self.tiltFactor + tiltChange, 0, 1)
384 end
385
386 local rotateChange = (self.targetRotation - self.cameraRotY) / dt * 5
387 if rotateChange < 0.0001 and rotateChange > -0.0001 then
388 self.cameraRotY = self.targetRotation
389 else
390 self.cameraRotY = self.cameraRotY + rotateChange
391 end
392end

createCameraNodes

Description
Create scene graph camera nodes.
Definition
createCameraNodes()
Return Values
intCameranode ID (view point, child of camera base node)
intCamerabase node ID (view target, parent of camera node)
Code
117function GuiTopDownCamera:createCameraNodes()
118 local camera = createCamera("TopDownCamera", math.rad(60), 1, 4000) -- camera view point node
119 local cameraBaseNode = createTransformGroup("topDownCameraBaseNode")-- camera base node, look-at target
120
121 link(cameraBaseNode, camera)
122 setRotation(camera, 0, math.rad(180) , 0)
123 setTranslation(camera, 0, 0, -5)
124 setRotation(cameraBaseNode, 0, 0 , 0)
125 setTranslation(cameraBaseNode, 0, 110, 0)
126 setFastShadowUpdate(camera, true)
127
128 return camera, cameraBaseNode
129end

deactivate

Description
Disable this camera.
Definition
deactivate()
Code
218function GuiTopDownCamera:deactivate()
219 self.isActive = false
220
221 self.messageCenter:unsubscribeAll(self)
222 self:removeActionEvents()
223
224 -- local showCursor = self.controlledPlayer == nil and self.controlledVehicle == nil
225 self.inputManager:setShowMouseCursor(false)
226
227 -- restore player position and previous camera
228 if self.controlledPlayer ~= nil then
229 local x,y,z = unpack(self.lastPlayerPos)
230 local currentPlayerTerrainHeight = getTerrainHeightAtWorldPos(self.terrainRootNode, x,0,z)
231 local deltaTerrainHeight = currentPlayerTerrainHeight - self.lastPlayerTerrainHeight
232 if deltaTerrainHeight > 0 then
233 y = y + deltaTerrainHeight
234 end
235
236 self.controlledPlayer:moveRootNodeToAbsolute(x, y, z)
237 -- self.controlledPlayer:onEnter(true)
238 self.controlledPlayer:setVisibility(false)
239 end
240
241 if self.previousCamera ~= nil then
242 setCamera(self.previousCamera)
243 self.previousCamera = nil
244 end
245end

delete

Description
Definition
delete()
Code
133function GuiTopDownCamera:delete()
134 if self.isActive then
135 self:deactivate()
136 end
137
138 delete(self.cameraBaseNode) -- base node holds the camera as a child, this call deletes both
139 self.camera, self.cameraBaseNode = nil, nil
140 self:reset()
141end

determineMapPosition

Description
Determine the current camera position and orientation.
Definition
determineMapPosition()
Return Values
CameraXworld space position

Warning: Undefined array key "className" in /usr/www/users/giantw/gdn.giants-software.com/documentation_scripting_fs22.php on line 210
CameraZworld space position
CameraYrotation in radians
Code
284function GuiTopDownCamera:determineMapPosition()
285 return self.cameraX, 0, self.cameraZ, self.cameraRotY - math.rad(180), 0
286end

getIsActive

Description
Check if this camera is active.
Definition
getIsActive()
Code
249function GuiTopDownCamera:getIsActive()
250 return self.isActive
251end

getMouseEdgeScrollingMovement

Description
Get camera movement for mouse edge scrolling.
Definition
getMouseEdgeScrollingMovement()
Return Values
Xdirectionmovement [-1, 1]
Zdirectionmovement [-1, 1]
Code
404function GuiTopDownCamera:getMouseEdgeScrollingMovement()
405 local moveMarginStartX = 0.015 + 0.005
406 local moveMarginEndX = 0.015
407 local moveMarginStartY = 0.015 + 0.005
408 local moveMarginEndY = 0.015
409
410 local moveX, moveZ = 0, 0
411
412 if self.mousePosX >= 1 - moveMarginStartX then
413 moveX = math.min((moveMarginStartX - (1 - self.mousePosX)) / (moveMarginStartX - moveMarginEndX), 1)
414 elseif self.mousePosX <= moveMarginStartX then
415 moveX = -math.min((moveMarginStartX - self.mousePosX) / (moveMarginStartX - moveMarginEndX), 1)
416 end
417
418 if self.mousePosY >= 1 - moveMarginStartY then
419 moveZ = math.min((moveMarginStartY - (1 - self.mousePosY)) / (moveMarginStartY - moveMarginEndY), 1)
420 elseif self.mousePosY <= moveMarginStartY then
421 moveZ = -math.min((moveMarginStartY - self.mousePosY) / (moveMarginStartY - moveMarginEndY), 1)
422 end
423
424 return moveX, moveZ
425end

getPickRay

Description
Get a picking ray for the current camera orientation and cursor position.
Definition
getPickRay()
Code
290function GuiTopDownCamera:getPickRay()
291 if self.isCatchingCursor then
292 return nil
293 end
294
295 return RaycastUtil.getCameraPickingRay(self.mousePosX, self.mousePosY, self.camera)
296end

mouseEvent

Description
Handle mouse moves that are not caught by actions.
Definition
mouseEvent()
Code
486function GuiTopDownCamera:mouseEvent(posX, posY, isDown, isUp, button)
487 if self.lastActionFrame >= g_time or self.cursorLocked then
488 return
489 end
490
491 -- Mouse move only happens when other actions did not
492 if self.isCatchingCursor then
493 self.isCatchingCursor = false
494 self.inputManager:setShowMouseCursor(true)
495
496 -- force warp to get rid of invisible position
497 wrapMousePosition(0.5, 0.5)
498
499 self.mousePosX = 0.5
500 self.mousePosY = 0.5
501 else
502 if self.isMouseMode then
503 self.mousePosX = posX
504 self.mousePosY = posY
505 end
506 end
507end

onInputModeChanged

Description
Called when the mouse input mode changes.
Definition
onInputModeChanged()
Code
633function GuiTopDownCamera:onInputModeChanged(inputMode)
634 self.isMouseMode = inputMode[1] == GS_INPUT_HELP_MODE_KEYBOARD
635
636 -- Reset to center of screen
637 if not self.isMouseMode then
638 self.mousePosX = 0.5
639 self.mousePosY = 0.5
640 end
641end

onMoveForward

Description
Definition
onMoveForward()
Code
575function GuiTopDownCamera:onMoveForward(_, inputValue)
576 self.inputMoveForward = inputValue * GuiTopDownCamera.INPUT_MOVE_FACTOR / g_currentDt
577end

onMoveSide

Description
Definition
onMoveSide()
Code
569function GuiTopDownCamera:onMoveSide(_, inputValue)
570 self.inputMoveSide = inputValue * GuiTopDownCamera.INPUT_MOVE_FACTOR / g_currentDt
571end

onRotate

Description
Definition
onRotate()
Code
581function GuiTopDownCamera:onRotate(_, inputValue, _, isAnalog, isMouse)
582 if isMouse and self.mouseDisabled then
583 return
584 end
585
586 -- Do not show cursor and clip to center of screen so that cursor does not
587 -- overlap with edge scrolling
588 if isMouse and inputValue ~= 0 then
589 self.lastActionFrame = g_time
590
591 if not self.isCatchingCursor then
592 self.inputManager:setShowMouseCursor(false)
593 self.isCatchingCursor = true
594 end
595 end
596
597 -- Analog has very small steps
598 if isMouse and isAnalog then
599 inputValue = inputValue * 3
600 end
601
602 self.inputRotate = -inputValue * 3 / g_currentDt * 16
603end

onTilt

Description
Definition
onTilt()
Code
607function GuiTopDownCamera:onTilt(_, inputValue, _, isAnalog, isMouse)
608 if isMouse and self.mouseDisabled then
609 return
610 end
611
612 -- Do not show cursor and clip to center of screen so that cursor does not
613 -- overlap with edge scrolling
614 if isMouse and inputValue ~= 0 then
615 self.lastActionFrame = g_time
616
617 if not self.isCatchingCursor then
618 self.inputManager:setShowMouseCursor(false)
619 self.isCatchingCursor = true
620 end
621 end
622
623 -- Analog has very small steps
624 if isMouse and isAnalog then
625 inputValue = inputValue * 3
626 end
627
628 self.inputTilt = inputValue * 3
629end

onZoom

Description
Definition
onZoom()
Code
552function GuiTopDownCamera:onZoom(_, inputValue, _, isAnalog, isMouse)
553 if isMouse and self.mouseDisabled then
554 return
555 end
556
557 local change = 0.2 * inputValue
558 if isAnalog then
559 change = change * 0.5
560 elseif isMouse then -- UI mouse wheel zoom
561 change = change * InputBinding.MOUSE_WHEEL_INPUT_FACTOR
562 end
563
564 self.inputZoom = change
565end

registerActionEvents

Description
Register required action events for the camera.
Definition
registerActionEvents()
Code
521function GuiTopDownCamera:registerActionEvents()
522 local _, eventId = self.inputManager:registerActionEvent(InputAction.AXIS_MOVE_SIDE_PLAYER, self, self.onMoveSide, false, false, true, true)
523 self.inputManager:setActionEventTextPriority(eventId, GS_PRIO_VERY_LOW)
524 self.inputManager:setActionEventTextVisibility(eventId, false)
525 self.eventMoveSide = eventId
526
527 _, eventId = self.inputManager:registerActionEvent(InputAction.AXIS_MOVE_FORWARD_PLAYER, self, self.onMoveForward, false, false, true, true)
528 self.inputManager:setActionEventTextPriority(eventId, GS_PRIO_VERY_LOW)
529 self.inputManager:setActionEventTextVisibility(eventId, false)
530 self.eventMoveForward = eventId
531
532 _, eventId = self.inputManager:registerActionEvent(InputAction.AXIS_CONSTRUCTION_CAMERA_ZOOM, self, self.onZoom, false, false, true, true)
533 self.inputManager:setActionEventTextPriority(eventId, GS_PRIO_LOW)
534 _, eventId = self.inputManager:registerActionEvent(InputAction.AXIS_CONSTRUCTION_CAMERA_ROTATE, self, self.onRotate, false, false, true, true)
535 self.inputManager:setActionEventTextPriority(eventId, GS_PRIO_LOW)
536 _, eventId = self.inputManager:registerActionEvent(InputAction.AXIS_CONSTRUCTION_CAMERA_TILT, self, self.onTilt, false, false, true, true)
537 self.inputManager:setActionEventTextPriority(eventId, GS_PRIO_LOW)
538end

removeActionEvents

Description
Remove action events registered on this screen.
Definition
removeActionEvents()
Code
542function GuiTopDownCamera:removeActionEvents()
543 self.inputManager:removeActionEventsByTarget(self)
544end

reset

Description
Definition
reset()
Code
145function GuiTopDownCamera:reset()
146 self.cameraTransformInitialized = false
147 self.controlledPlayer = nil
148 self.controlledVehicle = nil
149 self.terrainRootNode = nil
150 self.waterLevelHeight = 0
151 self.terrainSize = 0
152 self.previousCamera = nil
153 self.isCatchingCursor = false
154end

resetInputState

Description
Reset event input state.
Definition
resetInputState()
Code
511function GuiTopDownCamera:resetInputState()
512 self.inputZoom = 0
513 self.inputMoveSide = 0
514 self.inputMoveForward = 0
515 self.inputTilt = 0
516 self.inputRotate = 0
517end

resetToPlayer

Description
Reset the camera target position to the player's location.
Definition
resetToPlayer()
Code
265function GuiTopDownCamera:resetToPlayer()
266 local playerX, playerZ = 0, 0
267
268 if self.controlledPlayer ~= nil then
269 playerX, playerZ = self.lastPlayerPos[1], self.lastPlayerPos[3]
270 elseif self.controlledVehicle ~= nil then
271 local _
272 playerX, _, playerZ = getTranslation(self.controlledVehicle.rootNode)
273 end
274
275 self:setMapPosition(playerX, playerZ)
276end

setControlledPlayer

Description
Set the reference to the currently controlled Player instance. Clears the controlled vehicle reference if any has been set.
Definition
setControlledPlayer()
Code
172function GuiTopDownCamera:setControlledPlayer(player)
173 self.controlledPlayer = player
174 self.controlledVehicle = nil
175end

setControlledVehicle

Description
Set the reference to the currently controlled Vehicle instance. Clears the controlled player reference if any has been set.
Definition
setControlledVehicle()
Code
180function GuiTopDownCamera:setControlledVehicle(vehicle)
181 if vehicle ~= nil then
182 self.controlledVehicle = vehicle
183 self.controlledPlayer = nil
184 end
185end

setMapPosition

Description
Set the camera target position on the map.
Definition
setMapPosition(float mapX, float mapZ)
Arguments
floatmapXMap X position
floatmapZMap Z position
Code
257function GuiTopDownCamera:setMapPosition(mapX, mapZ)
258 self.cameraX, self.cameraZ = mapX, mapZ
259 self.targetCameraX, self.targetCameraZ = mapX, mapZ
260 self:updatePosition()
261end

setMouseEdgeScrollingActive

Description
Enable or disable the mouse edge scrolling.
Definition
setMouseEdgeScrollingActive()
Code
396function GuiTopDownCamera:setMouseEdgeScrollingActive(isActive)
397 self.isMouseEdgeScrollingActive = isActive
398end

setTerrainRootNode

Description
Set the current game's terrain's root node reference for terrain state queries and raycasts.
Definition
setTerrainRootNode()
Code
158function GuiTopDownCamera:setTerrainRootNode(terrainRootNode)
159 self.terrainRootNode = terrainRootNode
160 self.terrainSize = getTerrainSize(self.terrainRootNode)
161end

setWaterLevelHeight

Description
Set the water level height as defined in the current map's environment.
Definition
setWaterLevelHeight()
Code
165function GuiTopDownCamera:setWaterLevelHeight(waterLevelHeight)
166 self.waterLevelHeight = waterLevelHeight
167end

update

Description
Update camera state.
Definition
update()
Code
433function GuiTopDownCamera:update(dt)
434 if self.isActive then
435 if self.isMouseMode or not self.movementDisabledForGamepad then
436 self:updateMovement(dt)
437 self:resetInputState()
438 end
439 end
440end

updateMovement

Description
Update camera position and orientation based on player input.
Definition
updateMovement(dt Delta, movementMultiplier Speed)
Arguments
dtDeltatime in milliseconds
movementMultiplierSpeedfactor for movement
Code
446function GuiTopDownCamera:updateMovement(dt)
447 self.targetZoomFactor = MathUtil.clamp(self.targetZoomFactor - self.inputZoom * 0.2, 0, 1)
448 self.targetRotation = self.targetRotation + dt * self.inputRotate * GuiTopDownCamera.ROTATION_SPEED
449 self.targetTiltFactor = MathUtil.clamp(self.targetTiltFactor + self.inputTilt * dt * GuiTopDownCamera.ROTATION_SPEED, 0, 1)
450
451 local moveX = self.inputMoveSide * dt
452 local moveZ = -self.inputMoveForward * dt -- inverted to make it consistent
453
454 -- When touching the edge with mouse cursor, move
455 if moveX == 0 and moveZ == 0 and self.isMouseEdgeScrollingActive then
456 moveX, moveZ = self:getMouseEdgeScrollingMovement()
457 end
458
459 -- make movement faster when zoomed out
460 local zoomMovementSpeedFactor = GuiTopDownCamera.MOVE_SPEED_FACTOR_NEAR + self.zoomFactor * (GuiTopDownCamera.MOVE_SPEED_FACTOR_FAR - GuiTopDownCamera.MOVE_SPEED_FACTOR_NEAR)
461 moveX = moveX * zoomMovementSpeedFactor
462 moveZ = moveZ * zoomMovementSpeedFactor
463
464 -- note: we use the actual current camera rotation to define the direction, instead of the target location
465 local dirX = math.sin(self.cameraRotY) * moveZ + math.cos(self.cameraRotY) * -moveX
466 local dirZ = math.cos(self.cameraRotY) * moveZ - math.sin(self.cameraRotY) * -moveX
467
468 local limit = self.terrainSize * 0.5 - GuiTopDownCamera.TERRAIN_BORDER
469 local moveFactor = dt * GuiTopDownCamera.MOVE_SPEED
470 self.targetCameraX = MathUtil.clamp(self.targetCameraX + dirX * moveFactor, -limit, limit)
471 self.targetCameraZ = MathUtil.clamp(self.targetCameraZ + dirZ * moveFactor, -limit, limit)
472
473 self:applyMovement(dt)
474 self:updatePosition()
475end

updatePosition

Description
Update the camera position and orientation based on terrain and zoom state.
Definition
updatePosition()
Code
300function GuiTopDownCamera:updatePosition()
301 local samplingGridStep = 2 -- terrain sampling step distance in meters
302 local cameraTargetHeight = self.waterLevelHeight
303
304 -- sample the terrain height around the camera
305 for x = -samplingGridStep, samplingGridStep, samplingGridStep do
306 for z = -samplingGridStep, samplingGridStep, samplingGridStep do
307 local sampleTerrainHeight = getTerrainHeightAtWorldPos(self.terrainRootNode, self.cameraX + x, 0, self.cameraZ + z)
308 cameraTargetHeight = math.max(cameraTargetHeight, sampleTerrainHeight)
309 end
310 end
311
312 cameraTargetHeight = cameraTargetHeight + GuiTopDownCamera.CAMERA_TERRAIN_OFFSET
313
314 -- Tilt factor decides position between min and max. Min and max depend on zoom level
315 local rotMin = math.rad(GuiTopDownCamera.ROTATION_MIN_X_NEAR + (GuiTopDownCamera.ROTATION_MIN_X_FAR - GuiTopDownCamera.ROTATION_MIN_X_NEAR) * self.zoomFactor)
316 local rotMax = math.rad(GuiTopDownCamera.ROTATION_MAX_X_NEAR + (GuiTopDownCamera.ROTATION_MAX_X_FAR - GuiTopDownCamera.ROTATION_MAX_X_NEAR) * self.zoomFactor)
317 local rotationX = rotMin + (rotMax - rotMin) * self.tiltFactor
318
319 -- Distance to target depends fully on zoom level
320 local cameraZ = GuiTopDownCamera.DISTANCE_MIN_Z + self.zoomFactor * GuiTopDownCamera.DISTANCE_RANGE_Z
321
322 setTranslation(self.camera, 0, 0, cameraZ)
323 setRotation(self.cameraBaseNode, rotationX, self.cameraRotY, 0)
324 setTranslation(self.cameraBaseNode, self.cameraX, cameraTargetHeight, self.cameraZ)
325
326 -- check if new camera position is close to or even under terrain and lift it if needed
327 local cameraX, cameraY
328 cameraX, cameraY, cameraZ = getWorldTranslation(self.camera)
329 local terrainHeight = self.waterLevelHeight
330 for x = -samplingGridStep, samplingGridStep, samplingGridStep do
331 for z = -samplingGridStep, samplingGridStep, samplingGridStep do
332 local y = getTerrainHeightAtWorldPos(self.terrainRootNode, cameraX + x, 0, cameraZ + z)
333
334 local hit, _, hitY, _ = RaycastUtil.raycastClosest(cameraX + x, y + 100, cameraZ + z, 0, -1, 0, 100, CollisionMask.ALL - CollisionMask.TRIGGERS)
335 if hit then
336 y = hitY
337 end
338
339 terrainHeight = math.max(terrainHeight, y)
340 end
341 end
342
343 -- TODO instead we should tilt the camera up to clear the terrain...
344 if cameraY < terrainHeight + GuiTopDownCamera.GROUND_DISTANCE_MIN_Y then
345 cameraTargetHeight = cameraTargetHeight + (terrainHeight - cameraY + GuiTopDownCamera.GROUND_DISTANCE_MIN_Y)
346 setTranslation(self.cameraBaseNode, self.cameraX, cameraTargetHeight, self.cameraZ)
347 end
348end