I wasn't sure if it were to be done via Data or Triggers, so I'm posting this here.
How do I make a unit drift when it turns, like a race car?
And is there a way to make this toggle-able on a unit?
None.
An artist's depiction of an Extended Unit Death
The easiest way would be to just give the unit a ridiculous turn radius, but that wouldn't give the visual effect you probably want.
There's probably a good way to do it with the Data Editor, but I'm more of a Trigger Editor guy. My general suggestion for the trigger approach would be to reduce the unit's speed and have a micro periodic event (every 0.05 seconds of the game) activated while the unit is moving. Record the facing direction of the unit, and then after a small delay (depending on how long you want the drift to happen, maybe 1 second) move the unit in that direction by a minuscule amount (the fact that this trigger runs so often will create a sliding effect). The only problem is you'll probably get weird results for people who spam different directions, but tuning the times can vary this effect. This would take care of things like trying to suddenly stop, though, and you'll have a neat effect where it takes some time to accelerate to full speed from a stationary position.
The other approach with triggers would be to detect a significant change in direction while the unit is moving. You can detect the event that the unit is issued an order, and then compare the angle from that unit to the new order to the angle of the unit's current facing direction, and if the change is significant enough, make a loop that slides the unit for however long you want the slide to last.
The only slightly annoying thing is figuring out when the unit is currently moving or not. The best you can do (to my knowledge) is to use the "Unit Is Issued Order" and "Unit Becomes Idle" events and keep track with a global variable.
Events
Timer - Every 0.0625 seconds of Game Time
Local Variables
Conditions
Actions
Unit Group - Pick each unit in _13 Racers and do (Actions)
Actions
General - If (Conditions) then do (Actions) else do (Actions)
If
_13 Drifting?[(Owner of (Picked unit))] == False
Then
Variable - Set _13 Drifting?[(Owner of (Picked unit))] = True
General - Wait 1.0 Game Time seconds
Unit - Order (Picked unit) to ( Move targeting ((Position of (Picked unit)) offset by 1.1 towards (Facing of (Picked unit)) degrees)) (Replace Existing Orders)
Variable - Set _13 Drifting?[(Owner of (Picked unit))] = False
Else
This is definitely not working.
The problem is that ordering the unit replaces the order, so it'll get in the way of the gameplay a lot. If the player wants to cast an ability while this thing runs, there is a chance the ability won't be cast. And if I don't set it to "Replace Existing Orders", a player that spams order will never be affected by the drifting effect (and all players, in this context,
will be spamming orders).
As it is, it just makes the movement of my Probe racer unit all clunky.
I also haven't bothered with making an "Is Moving" detection trigger since all the racers will basically be moving all the time (though I would add this safe-proof later on, but for testing, I don't think it was necessary).
None.
An artist's depiction of an Extended Unit Death
As an ode to SC1 I'll remind you that "Move Unit" and "Order Unit" are two completely different actions.
Also, you need to store the facing angle of the picked unit into a variable before you do your wait; otherwise it will just get the direction they've been moving toward.
I don't have time to look through what else may be wrong with the trigger, but I'd work on those two issues first. Also, a distance of 1.1 is probably going to be too large a distance.
I do stuff and thingies... Try widening and reducing the number of small nooks and crannies to correct the problem.
I would move it with blend & calculate a speed and a max facing change of the direction you are pushed into.
As an ode to SC1 I'll remind you that "Move Unit" and "Order Unit" are two completely different actions.
Also, you need to store the facing angle of the picked unit into a variable before you do your wait; otherwise it will just get the direction they've been moving toward.
I don't have time to look through what else may be wrong with the trigger, but I'd work on those two issues first. Also, a distance of 1.1 is probably going to be too large a distance.
Ah! That makes more sense.
calculate a speed and a max facing change of the direction you are pushed into.
Sorry for not following, but I'm not sure I understand what is the purpose of calculating the max facing change.
Current trigger:
Events
Timer - Every 0.0625 seconds of Game Time
Local Variables
Angle = 0.0 <Real>
Position = No Point <Point>
Conditions
Actions
Unit Group - Pick each unit in _13 Racers and do (Actions)
Actions
General - If (Conditions) then do (Actions) else do (Actions)
If
_13 Drifting?[(Owner of (Picked unit))] == False
Then
Variable - Set _13 Drifting?[(Owner of (Picked unit))] = True
Variable - Set Angle = (Facing of (Picked unit))
Variable - Set Position = (Position of (Picked unit))
General - Wait 0.1 Game Time seconds
Unit - Move (Picked unit) instantly to (Position offset by 0.5 towards Angle degrees) (Blend)
Variable - Set _13 Drifting?[(Owner of (Picked unit))] = False
Else
I've tried tweaking the numbers, but I just can't get the effect I want. I see the unit drifting slightly, but it's nothing ever near what I am expecting. I want a big sliding effect with decently high speed unit.
I wasn't sure about adding that "Position" variable, but it seemed to increase the sliding effect as long as certain parameters' values were kept within a certain range.
It seems like the solution could be to increase the Move value, but restrict it to when the players are not moving precisely forward, and thus to increase its value based on the Turn Angle compared to the last Forward Angle?
None.
An artist's depiction of an Extended Unit Death
I quickly wrote up a little something that should be easy to use:
Drift Unit
Options: Action
Return Type: (None)
Parameters
Unit = (Triggering unit) <Unit>
Distance = 1.0 <Real>
Angle <Real>
Time = 1.0 <Real>
TimeType = Game Time <Time Type>
Grammar Text: Drift Unit by a distance of Distance toward Angle over Time TimeType
Hint Text: (None)
Custom Script Code
Local Variables
wait = 0.05 <Real (Constant)>
repeat = (Integer((Time / wait))) <Integer>
step = (Distance / repeat) <Real>
Actions
General - Repeat (Actions) repeat times
Actions
Unit - Move Unit instantly to ((Position of Unit) offset by step towards Angle degrees) (Blend)
General - Wait wait TimeType seconds
And a simpler action definition to call it:
Slide Unit
Options: Action
Return Type: (None)
Parameters
Unit = (Triggering unit) <Unit>
Angle <Real>
Grammar Text: Make Unit slide toward Angle based on its current speed
Hint Text: (None)
Custom Script Code
Local Variables
speed = ((Triggering unit) Movement Speed (Current)) <Real>
time = (speed * 0.175) <Real>
distance = (speed * 0.55) <Real>
Actions
Drift Unit by a distance of distance toward Angle over time Game Time
Here's an example of using these new action definitions:
CheckDrift
Events
Unit - Any Unit is issued an order to Move
Local Variables
faceAngle = (Facing of (Triggering unit)) <Real>
orderAngle = (Angle from (Position of (Triggering unit)) to (Target point for (Triggering order))) <Real>
racers = Racers <Unit Group>
Conditions
((Triggering unit) is in racers) == True
Actions
General - If (Conditions) then do (Actions) else do (Actions)
If
(Abs((((faceAngle + 180.0) mod 320.0) - ((orderAngle + 180.0) mod 320.0)))) >= 40.0
Then
Make (Triggering unit) slide toward faceAngle based on its current speed
Else
That complicated If/Then condition is just me being bad at math - all it's doing is checking to see that the angle change is greater than 40 degrees.
Basically, you can just call Slide Unit and give it the unit and its facing angle and it will automatically drift (distance and duration based on its speed), or if you want to fine tune it more, you can call the Drift Unit action instead and specify a distance over a period of time.
Note that without checking to see if the unit is already drifting, you can get interesting results by spamming different directions in rapid succession. But I'll leave that up to you on how you want to handle that (if at all).
Attached is the test map I made. You can just copy pastarino the Drift/Slide actions into your own map, and then use them like you would any other trigger action.
Attachments:
I ended up using a friend's work:
[NYI] Apply Force
Options: Action, Create Thread
Return Type: (None)
Parameters
Unit = (Triggering unit) <Unit>
Initial Force = 1.0 <Real>
Direction = (Facing of (Triggering unit)) <Real>
Duration = 1.0 <Real>
Grammar Text: Apply Force(Unit, Initial Force, Direction, Duration)
Hint Text: Custom "physics" function for basic pushing or pulling effects.
Custom Script Code
Local Variables
force = Initial Force <Real>
steps = (Duration * 16.0) <Real>
temppoint = No Point <Point[2]>
inta = 0 <Integer>
skidstep = 0.0 <Real>
distance = 0.0 <Real>
forcemultiplier = 1.0 <Real>
Actions
General - If (Conditions) then do (Actions) else do (Actions)
If
Direction < 0.0
Then
Variable - Modify Direction: + 360.0
Else
General - While (Conditions) are true, do (Actions)
Conditions
force > 0.0
Actions
Variable - Set forcemultiplier = 1.0
------- things that might modify force effects go here; change forcemultiplier
Unit - Move Unit instantly to ((Position of Unit) offset by (force * forcemultiplier) towards Direction degrees) (Blend)
Variable - Modify force: - (Initial Force / steps)
General - Wait 0.0625 Game Time seconds
Along with:
_13 Drift
Events
Unit - Any Unit uses Move at Generic1 - Any stage (Ignore shared abilities)
Local Variables
Conditions
Actions
Unit - [NYI] Apply Force((Triggering unit), 0.1, (Facing of (Triggering unit)), 1.25)
Works wonders.
Thanks for you work anyways, though.
None.