• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Slide Physics

Status
Not open for further replies.

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Here is an advanced sliding physics I made, for my new map RO2. Not very optimized atm.

Download here

Code (from the attached map above):
JASS:
library SlidePhysics uses TimerUtils, UnitZ
    
    globals
    
        constant real SLOPE_ACCURACY = 0.1
        constant real FULL_GRAVITY = 1.5
        constant real SLIDER_MASS = 1.0
        constant real TAU = bj_PI*2
        constant real HP  = bj_PI/2
        
    endglobals
    
    function IsInBound takes real x, real y returns boolean
        return x < WorldBounds.maxX and x > WorldBounds.minX and y < WorldBounds.maxY and y > WorldBounds.minY
    endfunction

    struct SlideTerrain extends array
        
        private static TableArray data
        
        static method getFriction takes real x, real y returns real
            
            local integer id = GetTerrainType(x, y)
            
            if thistype.data[0].boolean[id] then
                return thistype.data[1].real[id]
            endif
            
            return 0.0
        endmethod
        
        static method newTerrain takes integer id, real friction returns nothing
        
            if not thistype.data[0].boolean[id] then
                
                set thistype.data[0].boolean[id] = true
                set thistype.data[1].real[id]    = friction
            
            endif
            
        endmethod
        
        private static method onInit takes nothing returns nothing
            set thistype.data = TableArray[2]
        endmethod
        
    endstruct
    
    private struct Ground extends array
        static real x = 0
        static real y = 0
    endstruct
    
    struct SlideUnit extends array
        
        readonly unit slider
        
        readonly real x
        readonly real y
        readonly real z
        
        readonly real zVel
        readonly boolean isFlying
        
        real angle
        real speed
        
        private static Ground ground
        
        implement Alloc
        
        private static method getSlope takes real x1, real y1, real x2, real y2 returns real
            return 1.571*((GetTerrainZ(x1, y1)-GetTerrainZ(x2, y2))/SLOPE_ACCURACY)
        endmethod
    
        private static method circularDifference takes real a, real b returns real
        
            local real diff = RAbsBJ(a-b)
            
            if diff*2 <= TAU then
                return diff
            else
                return TAU - diff
            endif
            
        endmethod
        
        private static method normalize takes real a returns real
        
            loop
                
                if a < 0 then
                    set a = a + TAU
                elseif a > TAU then
                    set a = a - TAU
                else
                    exitwhen true
                endif
                
            endloop
            
            return a
        endmethod
        
        private static method onPeriodic takes nothing returns nothing
            
            local real slope
            local real slope2
            local unit u
            
            local real px
            local real py
            
            local real d1
            local real d2
            local real d3
            
            local real sx
            local real sy
            local timer t = GetExpiredTimer()
            local thistype this = GetTimerData(t)
            
            if not .isFlying then
                call .getLowestGr()
                set slope = getSlope(.x, .y, ground.x, ground.y)
                if slope != 0 then
                    call slip(FULL_GRAVITY*slope, 25, Atan2(ground.y-.y, ground.x-.x), 2*bj_DEGTORAD)
                endif
            endif
            
            if .speed > 0 then
                
                if not .isFlying then
                    set .speed = .speed - SlideTerrain.getFriction(.x, .y)
                endif
                
                if .speed > 0 then
                    
                    if IsInBound(.x, .y) then
                        if IsTerrainWalkable(.x, .y) then
                        
                            set px = .x
                            set py = .y
                            
                            set sx = .x + SLOPE_ACCURACY * Cos(.angle)
                            set sy = .y + SLOPE_ACCURACY * Sin(.angle)
                            
                            set slope = getSlope(sx, sy, .x, .y)
                            
                            set .x = .x + .speed * Cos(.angle)
                            set .y = .y + .speed * Sin(.angle)
                            
                            call SetUnitX(.slider, .x)
                            call SetUnitY(.slider, .y)
                            
                            if .isFlying then
                            
                                set .z = .z + .zVel
                                set .zVel = .zVel - (FULL_GRAVITY+SLIDER_MASS)
                                
                                call SetUnitZ(.slider, .z)
                                
                                if .z <= GetTerrainZ(.x, .y) + 0.01 then
                                
                                    set .isFlying = false
                                    
                                    set d1 = Atan(RAbsBJ(.zVel)/.speed)
                                    set d2 = Atan((GetTerrainZ(.x, .y)-GetTerrainZ(px, py))/.speed)
                                    set d3 = bj_PI-d1-d2
                                    
                                    set .speed = .speed * (d3/HP-1)
                                    
                                endif
                                
                            else
                            
                                set sx = .x - SLOPE_ACCURACY * Cos(.angle)
                                set sy = .y - SLOPE_ACCURACY * Sin(.angle)
                                set slope2 = getSlope(.x, .y, sx, sy)
                                
                                if slope > slope2 and slope - slope2 > bj_DEGTORAD*5 then
                                
                                    set .zVel = .speed * Sin(slope)
                                    
                                    if .zVel > (FULL_GRAVITY+SLIDER_MASS+(GetTerrainZ(.x, .y)-GetTerrainZ(sx, sy))) then
                                        set .isFlying = true
                                        set .z = GetUnitZ(.slider)
                                    endif
                                
                                endif
                                
                            endif
                            
                        else//if .speed > stun speed then
                            // stun
                        endif
                    endif
                else
                    set .speed = 0
                endif
                
            endif
            
            set t = null
            
        endmethod
        
        private method getLowestGr takes nothing returns nothing
            
            local real x
            local real y
            local real z
            local real angle = 0
            local real lowest = GetTerrainZ(.x, .y)
            
            set ground.x = .x
            set ground.y = .y
            
            loop
                exitwhen angle >= TAU
                
                set x = .x + SLOPE_ACCURACY*Cos(angle)
                set y = .y + SLOPE_ACCURACY*Sin(angle)
                set z = GetTerrainZ(x, y)
                
                if z < lowest then
                
                    set lowest = z
                    set ground.x = x
                    set ground.y = y
                    
                endif
                
                set angle = angle + bj_DEGTORAD
            endloop
            
        endmethod
        
        method turn takes real targetAngle, real turnRate returns nothing
            
            if Cos(.angle - targetAngle) < Cos(turnRate) then
                if Sin(targetAngle - .angle) >= 0 then
                    set .angle = normalize(.angle + turnRate)
                else
                    set .angle = normalize(.angle - turnRate)
                endif
            else
                set .angle = normalize(targetAngle)
            endif
            
        endmethod
        
        method accelerate takes real speed, real maxspeed, real angle, real rate returns nothing
            
            local real diff
            local real turnPow
            local real spdPow
            
            set angle = normalize(angle)
            
            if .speed <= 0 then
                set .angle = angle
                if .speed < maxspeed then
                    set .speed = speed
                endif
            else
                
                set diff = circularDifference(angle, .angle)
                
                set turnPow = RAbsBJ(circularDifference(diff, HP))
                set turnPow = 1-turnPow/HP
                call .turn(angle, rate*turnPow)
                
                set spdPow = 1-diff*(2/bj_PI)
                if spdPow < 0 or .speed < maxspeed then
                
                    set .speed = .speed + speed*spdPow
                    
                    if .speed > maxspeed and spdPow >= 0 then
                        set .speed = maxspeed
                    endif
                    
                    if .speed < 0 then
                        set .angle = angle
                        set .speed = -.speed
                    endif
                    
                endif
                
            endif
            
        endmethod
        
        method slip takes real speed, real maxspeed, real angle, real rate returns nothing
            
            local real diff
            local real turnPow
            local real spdPow
            
            set angle = normalize(angle)
            set diff = circularDifference(angle, .angle)
            
            set turnPow = RAbsBJ(circularDifference(diff, HP))
            set turnPow = 1-turnPow/HP
            call .turn(angle, rate*turnPow)
        
            set spdPow = 1-diff*(2/bj_PI)
            if spdPow < 0 or .speed < maxspeed then
            
                set .speed = .speed + speed*spdPow
                
                if spdPow >= 0 and .speed > maxspeed then
                    set .speed = maxspeed
                endif
                
                if .speed < 0 then
                    set .angle = angle
                    set .speed = .speed+speed
                endif
                
            endif
            
        endmethod
        
        static method newSlider takes unit whichUnit returns thistype
            
            local thistype this = allocate()
            
            set .slider = whichUnit
            set .isFlying = false
            
            set .speed  = 0
            set .angle  = GetUnitFacing(whichUnit)*bj_DEGTORAD
            
            set .x = GetUnitX(whichUnit)
            set .y = GetUnitY(whichUnit)
            set .z = 0
            
            call SetUnitTimeScale(whichUnit, 0.75)
            call TimerStart(NewTimerEx(this), 0.0312500, true, function thistype.onPeriodic)
            
            return this
        endmethod
        
    endstruct
    
endlibrary
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Here:
JASS:
library SlidePhysics uses TimerUtils
    
    globals
        real SLOPE_ACCURACY = 16.0
        real FULL_GRAVITY = 1.5//0.803
    endglobals
    
    function IsInBound takes real x, real y returns boolean
        return x < WorldBounds.maxX and x > WorldBounds.minX and y < WorldBounds.maxY and y > WorldBounds.minY
    endfunction

    struct SlideTerrain extends array
        
        private static TableArray data
        
        static method getFriction takes real x, real y returns real
            
            local integer id = GetTerrainType(x, y)
            
            if thistype.data[0].boolean[id] then
                return thistype.data[1].real[id]
            endif
            
            return 0.0
        endmethod
        
        static method newTerrain takes integer id, real friction returns nothing
        
            if not thistype.data[0].boolean[id] then
                
                set thistype.data[0].boolean[id] = true
                set thistype.data[1].real[id]    = friction
            
            endif
            
        endmethod
        
        private static method onInit takes nothing returns nothing
            set thistype.data = TableArray[2]
        endmethod
        
    endstruct
    
    private struct Ground extends array
        static real x = 0
        static real y = 0
    endstruct
    
    struct SlideUnit extends array
        
        readonly unit slider
        
        readonly real x
        readonly real y
        readonly real z
        
        readonly real angle
        readonly real speed
        private  integer anime
        
        private static Ground ground
        private static constant real TAU = bj_PI*2
        private static constant real HP  = bj_PI/2
        
        implement Alloc
        
        private static method getSlope takes real x1, real y1, real x2, real y2 returns real
            local real z1 = GetTerrainZ(x1, y1)
            local real z2 = GetTerrainZ(x2, y2)
            local real diff = (z1-z2)/SLOPE_ACCURACY
            return 1.571*diff
        endmethod
    
        private static method circularDifference takes real a, real b returns real
        
            local real diff = RAbsBJ(a-b)
            
            if diff*2 <= TAU then
                return diff
            else
                return TAU - diff
            endif
            
        endmethod
        
        private static method normalize takes real a returns real
        
            loop
                
                if a < 0 then
                    set a = a + TAU
                elseif a > TAU then
                    set a = a - TAU
                else
                    exitwhen true
                endif
                
            endloop
            
            return a
        endmethod
        
        private static method onPeriodic takes nothing returns nothing
            
            local real slope
            local timer t = GetExpiredTimer()
            local thistype this = GetTimerData(t)
                
            call .getLowestGr()
            set slope = getSlope(.x, .y, ground.x, ground.y)
                
            if slope != 0 then
                call slip(FULL_GRAVITY*slope, 20, Atan2(ground.y-.y, ground.x-.x), 2*bj_DEGTORAD)
            endif
            
            if .speed > 0 then
                
                //if slope == 0 then
                    set .speed = .speed - SlideTerrain.getFriction(.x, .y)
                //endif
                
                if .speed > 0 then
                    
                    if IsInBound(.x, .y) then
                        if IsTerrainWalkable(.x, .y) then
                    
                            set .x = .x + .speed * Cos(.angle)
                            set .y = .y + .speed * Sin(.angle)
                            
                            call SetUnitX(.slider, .x)
                            call SetUnitY(.slider, .y)
                            
                        else//if .speed > stun speed then
                            // stun
                        endif
                    endif
                else
                    set .speed = 0
                endif
                
            endif
            
            set t = null
            
        endmethod
        
        private method getLowestGr takes nothing returns nothing
            
            local real x
            local real y
            local real z
            local real angle = 0
            local real lowest = GetTerrainZ(.x, .y)
            
            set ground.x = .x
            set ground.y = .y
            
            loop
                exitwhen angle >= TAU
                
                set x = .x + SLOPE_ACCURACY*Cos(angle)
                set y = .y + SLOPE_ACCURACY*Sin(angle)
                set z = GetTerrainZ(x, y)
                
                if z < lowest then
                
                    set lowest = z
                    set ground.x = x
                    set ground.y = y
                    
                endif
                
                set angle = angle + bj_DEGTORAD
            endloop
            
        endmethod
        
        method turn takes real targetAngle, real turnRate returns boolean
            
            if Cos(.angle - targetAngle) < Cos(turnRate) then
                if Sin(targetAngle - .angle) >= 0 then
                    set .angle = normalize(.angle + turnRate)
                else
                    set .angle = normalize(.angle - turnRate)
                endif
                
                return false
            else
                set .angle = normalize(targetAngle)
                
                return true
            endif
            
        endmethod
        
        method accelerate takes real speed, real maxspeed, real angle, real rate returns nothing
            
            local real diff
            local real turnPow
            local real spdPow
            
            set angle = normalize(angle)
            
            if .speed == 0 then
                set .angle = angle
                if .speed < maxspeed then
                
                    set .speed = .speed+speed
                    
                    if .speed > maxspeed then
                        set .speed = maxspeed
                    elseif .speed < 0 then
                        set .speed = 0
                    endif
                endif
            else
                
                set diff = circularDifference(angle, .angle)
                
                set turnPow = RAbsBJ(circularDifference(diff, HP))
                set turnPow = 1-turnPow/HP
                call .turn(angle, rate*turnPow)
                
                if .speed < maxspeed then
                
                    set spdPow = 1-diff*(2/bj_PI)
                    set .speed = .speed + speed*spdPow
                    
                    if .speed > maxspeed then
                        set .speed = maxspeed
                    elseif .speed < 0 then
                        set .speed = 0
                    endif
                endif
                
            endif
            
                
            call SetUnitAnimationByIndex(.slider, .anime)
            call QueueUnitAnimation(.slider, "stand")
            
        endmethod
        
        method slip takes real speed, real maxspeed, real angle, real rate returns nothing
            
            local real diff
            local real turnPow
            local real spdPow
            
            set angle = normalize(angle)
            set diff = circularDifference(angle, .angle)
            
            set turnPow = RAbsBJ(circularDifference(diff, HP))
            set turnPow = 1-turnPow/HP
            call .turn(angle, rate*turnPow)
        
            if .speed < maxspeed then
                set spdPow = 1-diff*(2/bj_PI)
                set .speed = .speed + speed*spdPow
                
                if .speed > maxspeed then
                    set .speed = maxspeed
                elseif .speed < 0 then
                    set .angle = angle
                    set .speed = -.speed+speed
                endif
            endif
            
        endmethod
        
        static method newSlider takes unit whichUnit, integer walkAnim returns thistype
            
            local thistype this = allocate()
            
            set .slider = whichUnit
            
            set .speed  = 0
            set .anime  = walkAnim
            set .angle  = GetUnitFacing(whichUnit)*bj_DEGTORAD
            
            set .x = GetUnitX(whichUnit)
            set .y = GetUnitY(whichUnit)
            set .z = 0
            
            call SetUnitTimeScale(whichUnit, 0.75)
            call TimerStart(NewTimerEx(this), 0.0312500, true, function thistype.onPeriodic)
            
            return this
        endmethod
        
    endstruct
    
endlibrary
JASS:
library ControlSlider uses SlidePhysics
    
    globals
        SlideUnit array Slider
        unit array Controller
    endglobals

    struct ControlSlider
        
        private static method onPeriodic takes nothing returns nothing
        
            local integer i = 0
            local integer data
            
            loop
                exitwhen i > 5
                
                set data = GetUnitUserData(Controller[i])
                if GetUnitCurrentOrder(Controller[i]) != OrderId("stop") then
                    call IssueImmediateOrder(Controller[i], "stop")
                endif
                call SetUnitX(Controller[i], Slider[data].x)
                call SetUnitY(Controller[i], Slider[data].y)
                
                set i = i + 1
            endloop
            
        endmethod
        
        private static method onOrder takes nothing returns boolean
            
            local unit u = GetTriggerUnit()
            local integer data = GetUnitUserData(u)
            local real angle = Atan2(GetOrderPointY()-Slider[data].y, GetOrderPointX()-Slider[data].x)
            
            call Slider[data].accelerate(5.5, 15, angle, 35*bj_DEGTORAD)
            call SetUnitFacing(Slider[data].slider, angle*bj_RADTODEG)
            
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            
            local trigger t = CreateTrigger()
            local player p
            local integer i = 0
            
            call SlideTerrain.newTerrain('Idki', 0.2)
            call SlideTerrain.newTerrain('Isnw', 0.4)
            
            call EnableSelect(true, false)
            call EnableDragSelect(false, false)
            call EnablePreSelect(false, false)
            call FogEnable(false)
            call FogMaskEnable(false)
            
            loop
                exitwhen i > 0
                set p = Player(i)
                set Controller[i] = CreateUnit(p, 'h000', 100, 100, 90)
                set Slider[GetUnitUserData(Controller[i])] = SlideUnit.newSlider(CreateUnit(p, 'h001', 0, 0, 90), 0)
                
                if GetLocalPlayer() == p then
                    call SelectUnit(Controller[i], true)
                    call SetCameraTargetController(Controller[i], 0, 0, false)
                endif
                
                set i = i + 1
            endloop
            
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
            call TriggerAddCondition(t, Condition(function thistype.onOrder))
            call TimerStart(NewTimer(), 0.0312500, true, function thistype.onPeriodic)
            set t = null
            
        endmethod
    endstruct
    
endlibrary
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Why use order string instead of entering thr exact id?

Sure, I will update those later.

Anyway, here is an update: with correct speed reduction calculation on landing.

However, I'm still struggling to find the correct condition for the "take off" phase. Logically, this should be enough: slope > slope2 Where slope is slider's-location-before-being-moved's slope, while slope2 is slider's-location-after-being-moved's slope. If the source slope is greater than target's slope or in other word, the source ground is more sloppy more than the target ground, that should indicate that the slider should enter take off phase (jump). But seems like it's failed to detect in some cases. Still trying to do some researches about this matter. But using this condition: .speed > 20 the take off phase looks realistic enough, but it's still hardcoded.
 

Attachments

  • slide.w3x
    173.5 KB · Views: 67
Level 25
Joined
Jul 10, 2006
Messages
3,315
Depends on how you're handling the pitch/fly angle.

If you're using a simple delta-z and gravity, do:
pos1 = position of slider
pos2 = pos1 + speed
pos3 = pos2 + speed (basically just a second tick)
heightd1 = difference between height at pos1 and pos2
heightd2 = difference between height at pos2 and pos3

If heightd2 > heightd1, your unit has launched. Set the initial flying speed to the difference between heightd1 and heightd2

I could draw a image to explain this better if my description hasn't been adequate.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Depends on how you're handling the pitch/fly angle.

If you're using a simple delta-z and gravity, do:
pos1 = position of slider
pos2 = pos1 + speed
pos3 = pos2 + speed (basically just a second tick)
heightd1 = difference between height at pos1 and pos2
heightd2 = difference between height at pos2 and pos3

If heightd2 > heightd1, your unit has launched. Set the initial flying speed to the difference between heightd1 and heightd2

I could draw a image to explain this better if my description hasn't been adequate.

If at pos2 the slider hasn't reached the end of the ramp, then it wont be accurate if we use pos3 (the next tick). The slider would enter take off before he has left the ramp.

It can be more simple by comparing the slope of those two locations: where unit before being moved and after being moved. If there is slope difference and the second slope is lower, that should indicate the take off phase perfectly. Using this, it will automatically detect whether the unit has left/passed the ramp or not yet. But maybe I missed something. Thanks for your suggestion though, I will consider it.

I could draw a image to explain this better if my description hasn't been adequate.
I have drew your scenario myself in a paper :p

EDIT:
Problem solved. I realized that the slope difference could be super small such as 0.0001.... . The solution is to determining the minimum difference to indicate the take off phase, but I'm still not sure about that value.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Here is again an update. It has been on it's prime condition, it seems flawless so far. Just need some improvements and it's ready to be released, but maybe that wont happen soon.

Since I have finished all of the feature, this is going to be the latest version that will be shared here. But I'm still accepting suggestions and bug reports. Thanks for any support. :)
 

Attachments

  • slide.w3x
    173.8 KB · Views: 177
Sliding is very cool, and it's nice that you tried to make it as realistic as possible.

Cool acceleration, turning behaviour, friction, ...

I personaly dislike you have to keep that much clicking, but you actually proved with your map in map section that you can make good gameplay with it.^^

What I'm not sure about... I haven't scanned code in detail, but it seems you don't distinguish between different terrain types.
If it's the case, I suggest to change it. People might want have some not slideable terrain, where slide physics won't have any effect. (like friction, etc...)

Edit:

I suggest keeping the main post up to date with code/attachments. Spreading it over the whole thread is probably a bad idea.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Or better yet, use BoundSentinel. That way you don't need to put any bounds checks in your code.

Instead of coding "IsInBounds", use Adiktuz' MapBounds instead. It is WorldBounds with functionality

I will surely settle this issue when this is going to be released, but not now. Thanks for your suggestions.

Sliding is very cool, and it's nice that you tried to make it as realistic as possible.

Cool acceleration, turning behaviour, friction, ...

I personaly dislike you have to keep that much clicking, but you actually proved with your map in map section that you can make good gameplay with it.^^

What I'm not sure about... I haven't scanned code in detail, but it seems you don't distinguish between different terrain types.
If it's the case, I suggest to change it. People might want have some not slideable terrain, where slide physics won't have any effect. (like friction, etc...)

Edit:

I suggest keeping the main post up to date with code/attachments. Spreading it over the whole thread is probably a bad idea.

Updated.

The control (how you accelerate) is up to you. Sadly, in wc3 mouse is still the best option. The game style is originally made to be played using Joystick. But I'm not sure it can be used here.

What I'm not sure about... I haven't scanned code in detail, but it seems you don't distinguish between different terrain types.
If it's the case, I suggest to change it. People might want have some not slideable terrain, where slide physics won't have any effect. (like friction, etc...)
Will add this later.

Thanks for suggestions guys.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
The control (how you accelerate) is up to you. Sadly, in wc3 mouse is still the best option.

For my (very similar) ice race map which has a constant acceleration (with hotkeys for stop/start/hold), I was planning to do flow control by setting a target speed based on the distance between your unit and the target move point.
e.g. if you click right in front of your unit, target speed is set to ~10% of your max
if you click >800 range away from your unit, target speed is set to 100%
The unit would accelerate by a small amount a few times a second (10-30 is fine too for a nice resolution), and not accelerate any further once the target speed has been reached.

I suggest this because the spam-click system doesn't appeal to some of us. You don't need to pick one over the other, you could easily add an option to switch between them. Implementing a looping acceleration would be very easy.

I don't know if your code accounts for this or not, but with the click-to-accelerate system there is potential for abuse using an auto clicker.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
For my (very similar) ice race map which has a constant acceleration (with hotkeys for stop/start/hold), I was planning to do flow control by setting a target speed based on the distance between your unit and the target move point.
e.g. if you click right in front of your unit, target speed is set to ~10% of your max
if you click >800 range away from your unit, target speed is set to 100%
The unit would accelerate by a small amount a few times a second (10-30 is fine too for a nice resolution), and not accelerate any further once the target speed has been reached.

I suggest this because the spam-click system doesn't appeal to some of us. You don't need to pick one over the other, you could easily add an option to switch between them. Implementing a looping acceleration would be very easy.

I don't know if your code accounts for this or not, but with the click-to-accelerate system there is potential for abuse using an auto clicker.

I have several game modes in the game: race, ring out, and brawl arena. For race mode, yes sure I will use keyboard, arrow keys, for control. But for ring out mode, it's just impossible to fully use keyboard without mouse, player is supposed to able to shoot, accelerate, and rotate at the same time. There is no other choice.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
I'm not sure if I explained it correctly in my previous post, this is what I meant:
- Every tick (0.03 sec), the slider is accelerated forward by a small amount, but only if current speed is less than target speed.
- Target speed is set when you order your slider to move somewhere. If the target point is close to the slider, it's low. If the target point is far away, it's high.

The only difference between this control system and your current control system is that you only need to click once instead of many times, and only need to click more when you want to adjust your direction or speed.

Regarding arrow keys, I had those in my map as well but they were utterly useless. When you're moving at 1000+ speed and you need to hit a ramp that's only 150 distance wide, you need the best precision possible.
 
Status
Not open for further replies.
Top