library Camera
//##############################################################################################
globals
//**********************************************************************************************
// Configuration Constants
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Default constant values used for initializing each static camera instance.
//
public constant real DEFAULT_PAN_DURATION = 0.55
//
// The following configuration constants are preferred defaults. The camera is set
// to perform best under these circumstances, though adjustments *can* be made if it
// is necessary.
//
public constant real DEFAULT_TARGET_DISTANCE = 1000
public constant real DEFAULT_ZOFFSET = 30
public constant real DEFAULT_ANGLE_OF_ATTACK = 340
//
//
//**********************************************************************************************
endglobals
globals
//**********************************************************************************************
// Dynamic Storage Utility
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// These are private storage variables that allow easy-access of utilities, such as
// the GetLocationZ function which allows terrain-detection.
private constant location core__tempLoc = Location(0, 0)
private real core__tempLocZ
//
//
//**********************************************************************************************
endglobals
//##############################################################################################
private struct cameradata
public real targetDistance
public real angleOfAttack
public real zOffset
static method create takes nothing returns thistype
local thistype data=allocate()
set data.targetDistance=DEFAULT_TARGET_DISTANCE
set data.angleOfAttack=DEFAULT_ANGLE_OF_ATTACK
set data.zOffset=DEFAULT_ZOFFSET
return data
endmethod
endstruct
//##############################################################################################
struct camera extends array
private unit cam__controller
private cameradata cam__specData
readonly player controllerPlayer
private boolean cam__enabled
public boolean inheritRotation
public real panDuration
readonly boolean isLocal
readonly static thistype localCamera
private static timer core__looptmr = CreateTimer()
private static constant real core__looptmrRef = 0.04
method operator controller takes nothing returns unit
return cam__controller
endmethod
method operator controller= takes unit u returns nothing
set cam__controller=u
if(isLocal) then
call SetCameraTargetController(cam__controller, 0, 0, true)
endif
endmethod
method start takes boolean rotation returns boolean
set inheritRotation = rotation
//If there is an available camera-target then .start() will return true. If no target is
//available at all then "inheritRotation" will be queued for when .controller= is used
return cam__controller != null
endmethod
method stop takes nothing returns nothing
set inheritRotation = false
if (isLocal) then
call StopCamera()
endif
endmethod
static if(DEBUG_MODE) then
//The following code will only be implemented if DEBUG_MODE is enabled.
private static method debug takes nothing returns nothing
endmethod
endif
private static method loopFunc takes nothing returns nothing
local real r0=SquareRoot(Pow(GetCameraEyePositionX(), 2)+Pow(GetCameraEyePositionY(), 2))
local real r1=SquareRoot(Pow(GetCameraTargetPositionX(), 2)+Pow(GetCameraTargetPositionY(), 2))
local real d =GetCameraTargetPositionZ()-GetCameraEyePositionZ()
set d=SquareRoot((r1-r0)*(r1-r0)+(d*d))
call MoveLocation(core__tempLoc, GetUnitX(localCamera.controller), GetUnitY(localCamera.controller))
set core__tempLocZ=GetLocationZ(core__tempLoc)
if(localCamera.isLocal) then
if(localCamera.inheritRotation) then
call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(localCamera.controller),/*
*/localCamera.panDuration)
endif
//In order to counter-weight the smoothing that the camera uses we must find out the
//offset and correct it using ZOFFSET. On flat-ground, diffz will be 0.00.
call SetCameraField(CAMERA_FIELD_ZOFFSET, core__tempLocZ-GetCameraTargetPositionZ()/*
*/+localCamera.cam__specData.zOffset+(GetCameraEyePositionZ()/*
*/-core__tempLocZ)/5, localCamera.panDuration)
//Now we must adjust the target-distance depending on how much the result has varied from it's original
set core__tempLocZ=localCamera.cam__specData.targetDistance-d
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE,/*
*/localCamera.cam__specData.targetDistance+(core__tempLocZ/3),/*
*/localCamera.panDuration)
call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK,/*
*/localCamera.cam__specData.angleOfAttack-(GetCameraField(CAMERA_FIELD_ZOFFSET)/6),/*
*/localCamera.panDuration)
endif
debug call debug()
endmethod
//==========================================================================================
private static method onInit takes nothing returns nothing
local integer i = 0
loop
exitwhen(i == 12)
//Initialize camera components:
set camera[i].controllerPlayer =Player(i)
set camera[i].cam__controller =null
set camera[i].cam__specData =cameradata.create()
set camera[i].panDuration =DEFAULT_PAN_DURATION
//Setup local camera data:
set camera[i].isLocal =false
set i = i + 1
endloop
//Finalize local data:
set localCamera = camera[GetPlayerId(GetLocalPlayer())]
set localCamera.isLocal = true
//Initialize update/refresh loop timer:
call TimerStart(core__looptmr, core__looptmrRef, true, function thistype.loopFunc)
endmethod
endstruct
endlibrary