ESO Lua File v100015

libraries/zo_movementcontroller/zo_movementcontroller.lua

[◄ back to folders ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
ZO_MovementController = ZO_Object:Subclass()
--[[ Public API ]]--
function ZO_MovementController:New(...)
    local movementController = ZO_Object.New(self)
    movementController:Initialize(...)
    return movementController
end
MOVEMENT_CONTROLLER_DIRECTION_VERTICAL = 1
MOVEMENT_CONTROLLER_DIRECTION_HORIZONTAL = 2
local function GetStickMagnitude(direction)
    if direction == MOVEMENT_CONTROLLER_DIRECTION_VERTICAL then
        return DIRECTIONAL_INPUT:GetY(ZO_DI_LEFT_STICK, ZO_DI_DPAD)
    end
    return -DIRECTIONAL_INPUT:GetX(ZO_DI_LEFT_STICK, ZO_DI_DPAD)
end
local NUM_TICKS_TO_START_ACCELERATING = 5
local ACCELERATION_MAGNTITUDE_FACTOR = 3
function ZO_MovementController:Initialize(direction, accumulationPerSecondForChange, magnitudeQueryFunctionOverride)
    self.direction = direction or MOVEMENT_CONTROLLER_DIRECTION_VERTICAL
    self.accumulationPerSecondForChange = accumulationPerSecondForChange or 8
    self.magnitudeQueryFunction = magnitudeQueryFunctionOverride or GetStickMagnitude
    self.totalAccumulation = 0
    self.debt = 0
    self.lastMagnitude = 0
    self.allowAcceleration = true
    self.numTicksToStartAccelerating = NUM_TICKS_TO_START_ACCELERATING
    self.accelerationMagnitudeFactor = ACCELERATION_MAGNTITUDE_FACTOR
end
function ZO_MovementController:SetAllowAcceleration(allowAcceleration)
    self.allowAcceleration = allowAcceleration
end
function ZO_MovementController:SetNumTicksToStartAccelerating(numTicks)
    self.numTicksToStartAccelerating = numTicks
end
function ZO_MovementController:SetAccelerationMagnitudeFactor(accelerationMagnitudeFactor)
    self.accelerationMagnitudeFactor = accelerationMagnitudeFactor
end
MOVEMENT_CONTROLLER_NO_CHANGE = 0
MOVEMENT_CONTROLLER_MOVE_NEXT = 1
MOVEMENT_CONTROLLER_MOVE_PREVIOUS = 2
local function IsChangingDirections(previousMagnitude, newMagnitude)
    return (previousMagnitude > 0 and newMagnitude < 0)
        or (previousMagnitude < 0 and newMagnitude > 0)
end
local ACCUMULATION_DEBT_PERCENT_AFTER_FIRST_SELECT = 1
local MIN_MAGNITUDE_FOR_ACCEL = .8
function ZO_MovementController:CheckMovement()
    local magnitude = self:GetMagnitude()
    if magnitude == 0 then
        self.totalAccumulation = 0
        self.isMovingFromAccumulation = false
        self.lastMagnitude = 0
    else
        if IsChangingDirections(self.lastMagnitude, magnitude) then
            -- reset moving state when changing a direction
            self.isMovingFromAccumulation = false
            self.lastMagnitude = magnitude
            -- consume this input, some devices will "flip back" when the stick is tapped in a direction
            -- this will help, but not eliminate that effect
            return MOVEMENT_CONTROLLER_NO_CHANGE
        end
        if zo_abs(magnitude) < MIN_MAGNITUDE_FOR_ACCEL then
            self.numAccumulationTicks = 0
        end
        if self.isMovingFromAccumulation then
            local normalizedMagnitude = magnitude * GetFrameDeltaNormalizedForTargetFramerate()
            if self.debt > 0 then
                local absNormalizedMagnitude = zo_abs(normalizedMagnitude)
                -- Consume it all, nothing to do here
                if self.debt >= absNormalizedMagnitude then
                    self.debt = self.debt - absNormalizedMagnitude
                    return MOVEMENT_CONTROLLER_NO_CHANGE
                end
                normalizedMagnitude = normalizedMagnitude - self.debt * zo_sign(normalizedMagnitude)
                self.debt = 0
            end
            
            self.totalAccumulation = self.totalAccumulation + normalizedMagnitude * self:CalculateAccelerationFactor()
        else
            self.isMovingFromAccumulation = true
            self.numAccumulationTicks = 0
            self.totalAccumulation = magnitude > 0 and self.accumulationPerSecondForChange or -self.accumulationPerSecondForChange
            self.debt = zo_abs(self.totalAccumulation * ACCUMULATION_DEBT_PERCENT_AFTER_FIRST_SELECT)
        end
        self.lastMagnitude = magnitude
        if self.totalAccumulation >= self.accumulationPerSecondForChange then
            self.totalAccumulation = self.totalAccumulation - self.accumulationPerSecondForChange
            self.numAccumulationTicks = self.numAccumulationTicks + 1
            return MOVEMENT_CONTROLLER_MOVE_PREVIOUS
        elseif self.totalAccumulation <= -self.accumulationPerSecondForChange then
            self.totalAccumulation = self.totalAccumulation + self.accumulationPerSecondForChange
            self.numAccumulationTicks = self.numAccumulationTicks + 1
            return MOVEMENT_CONTROLLER_MOVE_NEXT
        end
    end
    return MOVEMENT_CONTROLLER_NO_CHANGE
end
--[[ Private API ]]--
function ZO_MovementController:GetMagnitude()
    return self.magnitudeQueryFunction(self.direction)
end
do
    local MAX_TICKS_TO_ACCEL_ACROSS = 30
    function ZO_MovementController:CalculateAccelerationFactor()
        if self.allowAcceleration then
            return 1.0 + ZO_EaseOutQuartic(zo_clampedPercentBetween(self.numTicksToStartAccelerating, MAX_TICKS_TO_ACCEL_ACROSS, self.numAccumulationTicks)) * self.accelerationMagnitudeFactor
        end
        return 1.0
    end
end