• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • ✅ The POLL for Hive's Texturing Contest #33 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!

Fixed Camera Lock (Isometric RPG)

There seem to be a whole bunch of camera systems on hive, but no system for isometric view that addresses an inherent issue with those camera systems.

The SetCameraTargetController native behaves incredibly awful around steep terrain and often sinks into the ground for no reason or lets the anchored unit escape to the edge of the screen. This simple system fixes that by adjusting the camera z-offset dynamically.

Instead of doing SetCameraTargetController(whichUnit, ...), you do FCL_Lock(whichUnit, whichPlayer).

As a GUI user, you do:
  • Custom script: call FCL_Lock(udg_myUnit, udg_myPlayer)
That's all! Not much else to say... enjoy!

Lua:
if Debug then Debug.beginFile "FixedCameraLock" end
do
    --[[
    =============================================================================================================================================================
                                                                     Fixed Camera Lock
                                                                        by Antares

                                    Locks the camera to a unit while dynamically adjusting the z-offset to disable awfulness.

                                Requires:
                                TotalInitialization			    https://www.hiveworkshop.com/threads/total-initialization.317099/
                                PrecomputedHeightMap (optional) https://www.hiveworkshop.com/threads/precomputed-synchronized-height-map.353477/
                            
    =============================================================================================================================================================
                                                                          A P I
    =============================================================================================================================================================

    FCL_Lock(whichUnit, whichPlayer)            Locks the camera of the specified player to the specified unit or the camera of the owning player of that unit,
                                                if player is not specified.
    FCL_Release(whichPlayer)                    Releases the camera of the specified player or for all players if no player is specified.

    =============================================================================================================================================================
                                                                        C O N F I G
    =============================================================================================================================================================
    ]]

    local ADJUSTMENT_INTERVAL           = 0.1           ---@constant number

    --The adjustment strength when the camera target is below the unit. This type of camera shift is always awful and I recommend a value of 1.
    local ADJUSTMENT_STRENGTH_UP        = 1.0           ---@constant number

    --The adjustment strength when the camera target is above the unit. This camera shift is sometimes actually useful, so you can disable it if you want to.
    local ADJUSTMENT_STRENGTH_DOWN      = 1.0           ---@constant number

    --===========================================================================================================================================================

    local MASTER_TIMER                          ---@type timer
    local anchor                                ---@type unit
    local lockEnabled           = false         ---@type boolean
    local moveableLoc                           ---@type location
    local GetLocZ                               ---@type function

    ---@param whichUnit unit
    ---@param whichPlayer? player
    function FCL_Lock(whichUnit, whichPlayer)
        if GetLocalPlayer() == (whichPlayer or GetOwningPlayer(whichUnit)) then
            SetCameraTargetController(whichUnit, 0, 0, false)
            lockEnabled = true
            anchor = whichUnit
        end
    end

    ---@param whichPlayer? player
    function FCL_Release(whichPlayer)
        if whichPlayer == nil or GetLocalPlayer() == whichPlayer then
            ResetToGameCamera(0)
            lockEnabled = false
        end
    end

    local function AdjustCameraHeight()
        if lockEnabled then
            local dz = GetLocZ(GetUnitX(anchor), GetUnitY(anchor)) - (GetCameraTargetPositionZ() - GetCameraField(CAMERA_FIELD_ZOFFSET))
            if dz > 0 then
                SetCameraField(CAMERA_FIELD_ZOFFSET, ADJUSTMENT_STRENGTH_UP*dz, ADJUSTMENT_INTERVAL)
            else
                SetCameraField(CAMERA_FIELD_ZOFFSET, ADJUSTMENT_STRENGTH_DOWN*dz, ADJUSTMENT_INTERVAL)
            end
        end
    end

    OnInit.final("FixedCameraLock", function()
        local precomputedHeightMap = Require.optionally "PrecomputedHeightMap"

        if precomputedHeightMap then
            GetLocZ = _G.GetLocZ
        else
            moveableLoc = Location(0, 0)
            GetLocZ = function(x, y)
                MoveLocation(moveableLoc, x, y)
                return GetLocationZ(moveableLoc)
            end
        end

        MASTER_TIMER = CreateTimer()
        TimerStart(MASTER_TIMER, ADJUSTMENT_INTERVAL, true, AdjustCameraHeight)
    end)
end
if Debug then Debug.endFile() end

JASS:
library FixedCameraLock initializer Init
    /*
    =============================================================================================================================================================
                                                                     Fixed Camera Lock
                                                                        by Antares

                                    Locks the camera to a unit while dynamically adjusting the z-offset to disable awfulness.
                            
    =============================================================================================================================================================
                                                                          A P I
    =============================================================================================================================================================

    FCL_Lock(whichUnit, whichPlayer)            Locks the camera of the specified player to the specified unit.
    FCL_Release(whichPlayer)                    Releases the camera of the specified player.

    =============================================================================================================================================================
                                                                        C O N F I G
    =============================================================================================================================================================
    */

    globals
        private real ADJUSTMENT_INTERVAL           = 0.1
        private real ADJUSTMENT_STRENGTH_UP        = 1.0
        //The adjustment strength when the camera target is below the unit. This type of camera shift is always awful and I recommend a value of 1.
        private real ADJUSTMENT_STRENGTH_DOWN      = 1.0
        //The adjustment strength when the camera target is above the unit. This type of camera shift is actually useful, so you can disable it if you want to.

        //=======================================================================================================================================================

        private timer MASTER_TIMER = CreateTimer()
        private unit anchor
        private boolean lockEnabled = false
        private location moveableLoc = Location(0, 0)
    endglobals

    private function GetLocZ takes real x, real y returns real
        call MoveLocation(moveableLoc, x, y)
        return GetLocationZ(moveableLoc)
    endfunction

    function FCL_Lock takes unit whichUnit, player whichPlayer returns nothing
        if GetLocalPlayer() == whichPlayer then
            call SetCameraTargetController(whichUnit, 0, 0, false)
            set lockEnabled = true
            set anchor = whichUnit
        endif
    endfunction

    function FCL_Release takes player whichPlayer returns nothing
        if GetLocalPlayer() == whichPlayer then
            call ResetToGameCamera(0)
            set lockEnabled = false
        endif
    endfunction

    private function AdjustCameraHeight takes nothing returns nothing
        local real dz
        if lockEnabled then
            set dz = GetLocZ(GetUnitX(anchor), GetUnitY(anchor)) - (GetCameraTargetPositionZ() - GetCameraField(CAMERA_FIELD_ZOFFSET))
            if dz > 0 then
                call SetCameraField(CAMERA_FIELD_ZOFFSET, ADJUSTMENT_STRENGTH_UP*dz, ADJUSTMENT_INTERVAL)
            else
                call SetCameraField(CAMERA_FIELD_ZOFFSET, ADJUSTMENT_STRENGTH_DOWN*dz, ADJUSTMENT_INTERVAL)
            endif
        endif
    endfunction

    private function Init takes nothing returns nothing
        call TimerStart(MASTER_TIMER, ADJUSTMENT_INTERVAL, true, function AdjustCameraHeight)
    endfunction
endlibrary
Contents

FixedCameraLock (Map)

FixedCameraLock (Lua) (Binary)

FixedCameraLock (vJASS) (Binary)

FixedCameraLock vJASS (Map)

Reviews
Wrda
When I saw the fixed camera lock, it was clear how horrible the normal the camera is, splendid. Approved
Top