• 🏆 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!

[Need Info] Ship-like movement for units

Status
Not open for further replies.
Level 2
Joined
Feb 2, 2015
Messages
8
Hi,

I'm trying to make a unit (It's a starship) move like a... well, a ship. That is, it would only be able to move in the direction it is currently facing while slowly turning towards the target point, thus moving in an arc as opposed to a line as starcraft units do. There is an explanation in the attached picture.

I have tried decreasing the turning speed, but that doesn't help, the unit still moves in a direct line. So I tried a bunch of different movers, but without success.

Please help.
 

Attachments

  • ShipMovementExplanation.png
    ShipMovementExplanation.png
    14.4 KB · Views: 118
Level 2
Joined
Feb 2, 2015
Messages
8
Yes, I had the same idea, but it seems horribly inefficient. There could be quite a few of these units on the map so I want to avoid doing it with triggers.

I hope that with all these advanced features of Starcraft 2, this could be done in a simple way.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
It wouldn't be noticeably inefficient. How many units will use this? 10? 100? 1000?

I did a quick test using the following (horribly inefficient) code:
  • Sliding
    • Events
      • Timer - Every 0.03 seconds of Game Time
    • Local Variables
    • Conditions
    • Actions
      • Unit Group - Pick each unit in (Any units in (Entire map) owned by player Any Player matching Excluded: Missile, Dead, Hidden, with at most Any Amount) and do (Actions)
        • Actions
          • Unit - Move (Picked unit) instantly to ((Position of (Picked unit)) offset by 0.1 towards (Facing of (Picked unit)) degrees) (Blend)
With 100+ BCs, there is no lag at all.

Using a "proper" mover would be more elegant maybe, but if you don't find a solution, triggers will work just fine. You just need to add:
- acceleration to make it nicer
- "move" detection, as in only move/accelerate the unit while it is moving using its actual movement
- scale the speed if the unit is slowed, snared, etc
 
Level 2
Joined
Feb 2, 2015
Messages
8
Hmm, I guess about 200.

I have already started on the trigger way of things and it's becoming painfully apparent that I will have to code some kind of primitive movement code for this. The pathing system is confused that the unit is moving with triggers while also trying to move it along the path. It just doesn't work that well.

I have also encountered something strange, if I decrease the unit's speed too much, it won't turn. It's not that big of a problem, I was just surprised at the behaviour. (A behaviour that I will probably abuse to implement this system.)
 

TKF

TKF

Level 19
Joined
Nov 29, 2006
Messages
1,266
Well, this is how its done in Cruiser Command:

A dummy unit for giving orders
The ship itself is triggered, using a movement engine and a triggered turning.

Based on that you control only 1 unit at a time



For example make the unit turn 4 degrees every 0.25 sec, while it is moving straight forward facing using SetUnitX/SetUnitY as it doesn't interrupt the units orders. Using move unit instantly interrupts is and make it not able to acquire its surroundings


You can use the unit itself, but you must stop the order each time you make and order and reorder it from the triggers to move x+/x- value each time and the movement must be triggered. You can use unit order but that will interrupt unit orders and if you are going to skills which requires the ship to move there to use, this gets much more complex.


But with only turn rate which helps making an movement arc, that is if you are using a dummy controller. Making a trigger which reselects the dummy controller each time you select the main unit solves that, although it has some minor delay of about 0.1~0.5 sec for some odd reasons.

  • Turning
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • Set localunit = Battlecruiser Unit 0001 <gen>
      • Set Temp_Point = (Position of CruiserLocator[(Integer A)])
      • Set Temp_Real = (Angle from Temp_Point to CruiserDestination[(Integer A)])
      • For each (Integer A) from 1 to 2, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Temp_Real Less than 0.00
            • Then - Actions
              • Set Temp_Real = (180.00 - (Temp_Real x -1.00))
              • Set Temp_Real = (Temp_Real + 180.00)
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • And - All (Conditions) are true
                    • Conditions
                      • ((Facing of localunit) - Temp_Real) Less than 2.00
                      • ((Facing of localunit) - Temp_Real) Greater than or equal to 0.00
                  • And - All (Conditions) are true
                    • Conditions
                      • (Temp_Real - (Facing of localunit)) Less than 2.00
                      • (Temp_Real - (Facing of localunit)) Greater than or equal to 0.00
            • Then - Actions
              • Set Temp_Integer = (Temp_Integer + 1)
              • Custom script: call RemoveLocation(udg_CruiserDestination[GetForLoopIndexA()])
              • Set CruiserDestination[(Integer A)] = (Temp_Point offset by 1000.00 towards (Facing of localunit) degrees)
              • Set CruiserOnCourse[(Integer A)] = True
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Distance between Temp_Point and CruiserDestination[(Integer A)]) Less than 25.00
                • Then - Actions
                  • Do nothing
                • Else - Actions
                  • Set HomingPoint[0] = (Temp_Point offset by 50.00 towards ((Facing of localunit) + 90.00) degrees)
                  • Set HomingPoint[1] = (Temp_Point offset by 50.00 towards ((Facing of localunit) - 90.00) degrees)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Distance between HomingPoint[0] and CruiserDestination[(Integer A)]) Less than (Distance between HomingPoint[1] and CruiserDestination[(Integer A)])
                    • Then - Actions
                      • Set Temp_Point2 = (Temp_Point offset by 600.00 towards ((Facing of localunit) + 1.00) degrees)
                      • Unit - Order localunit to Move To Temp_Point2
                      • Custom script: call RemoveLocation(udg_Temp_Point2)
                    • Else - Actions
                      • Set Temp_Point2 = (Temp_Point offset by 600.00 towards ((Facing of localunit) - 1.00) degrees)
                      • Unit - Order localunit to Move To Temp_Point2
                      • Custom script: call RemoveLocation(udg_Temp_Point2)
                  • Custom script: call RemoveLocation(udg_Temp_Point)
                  • Custom script: call RemoveLocation(udg_HomingPoint[0])
                  • Custom script: call RemoveLocation(udg_HomingPoint[1])
This example is ordering the unit to move, while slowly turning.

udg_CruiserDestination[X] is set point from a different order trigger


Applying this to 10-20 units is ok, having lots of starships is not ideal with this suggested trigger.
 
Level 2
Joined
Feb 2, 2015
Messages
8
Hmm, I'm not sure how well will that translate to Starcraft 2, but thanks for the ideas.

I'm still hoping that somebody comes with a miraculous data editor version though. :)
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
Well, this is how its done in Cruiser Command:

A dummy unit for giving orders
The ship itself is triggered, using a movement engine and a triggered turning.

Based on that you control only 1 unit at a time



For example make the unit turn 4 degrees every 0.25 sec, while it is moving straight forward facing using SetUnitX/SetUnitY as it doesn't interrupt the units orders. Using move unit instantly interrupts is and make it not able to acquire its surroundings


You can use the unit itself, but you must stop the order each time you make and order and reorder it from the triggers to move x+/x- value each time and the movement must be triggered. You can use unit order but that will interrupt unit orders and if you are going to skills which requires the ship to move there to use, this gets much more complex.


But with only turn rate which helps making an movement arc, that is if you are using a dummy controller. Making a trigger which reselects the dummy controller each time you select the main unit solves that, although it has some minor delay of about 0.1~0.5 sec for some odd reasons.

  • Turning
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • Set localunit = Battlecruiser Unit 0001 <gen>
      • Set Temp_Point = (Position of CruiserLocator[(Integer A)])
      • Set Temp_Real = (Angle from Temp_Point to CruiserDestination[(Integer A)])
      • For each (Integer A) from 1 to 2, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Temp_Real Less than 0.00
            • Then - Actions
              • Set Temp_Real = (180.00 - (Temp_Real x -1.00))
              • Set Temp_Real = (Temp_Real + 180.00)
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • And - All (Conditions) are true
                    • Conditions
                      • ((Facing of localunit) - Temp_Real) Less than 2.00
                      • ((Facing of localunit) - Temp_Real) Greater than or equal to 0.00
                  • And - All (Conditions) are true
                    • Conditions
                      • (Temp_Real - (Facing of localunit)) Less than 2.00
                      • (Temp_Real - (Facing of localunit)) Greater than or equal to 0.00
            • Then - Actions
              • Set Temp_Integer = (Temp_Integer + 1)
              • Custom script: call RemoveLocation(udg_CruiserDestination[GetForLoopIndexA()])
              • Set CruiserDestination[(Integer A)] = (Temp_Point offset by 1000.00 towards (Facing of localunit) degrees)
              • Set CruiserOnCourse[(Integer A)] = True
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Distance between Temp_Point and CruiserDestination[(Integer A)]) Less than 25.00
                • Then - Actions
                  • Do nothing
                • Else - Actions
                  • Set HomingPoint[0] = (Temp_Point offset by 50.00 towards ((Facing of localunit) + 90.00) degrees)
                  • Set HomingPoint[1] = (Temp_Point offset by 50.00 towards ((Facing of localunit) - 90.00) degrees)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Distance between HomingPoint[0] and CruiserDestination[(Integer A)]) Less than (Distance between HomingPoint[1] and CruiserDestination[(Integer A)])
                    • Then - Actions
                      • Set Temp_Point2 = (Temp_Point offset by 600.00 towards ((Facing of localunit) + 1.00) degrees)
                      • Unit - Order localunit to Move To Temp_Point2
                      • Custom script: call RemoveLocation(udg_Temp_Point2)
                    • Else - Actions
                      • Set Temp_Point2 = (Temp_Point offset by 600.00 towards ((Facing of localunit) - 1.00) degrees)
                      • Unit - Order localunit to Move To Temp_Point2
                      • Custom script: call RemoveLocation(udg_Temp_Point2)
                  • Custom script: call RemoveLocation(udg_Temp_Point)
                  • Custom script: call RemoveLocation(udg_HomingPoint[0])
                  • Custom script: call RemoveLocation(udg_HomingPoint[1])
This example is ordering the unit to move, while slowly turning.

udg_CruiserDestination[X] is set point from a different order trigger


Applying this to 10-20 units is ok, having lots of starships is not ideal with this suggested trigger.

It's much easier to just let the unit use its own turn rate and move it towards its facing angle.
 
Level 2
Joined
Feb 2, 2015
Messages
8
It's much easier to just let the unit use its own turn rate and move it towards its facing angle.

Right, about that, I have already implemented a proof of concept for that. The problem there is, that starcraft calculates the path ahead of time and then after a while, the unit stops (and stops turning) because it thinks it has already arrived at its destination. It will not stop at the desired location.

Well, anyway I think I will need a way to control the unit's turn rate too and I haven't been able to find a function for that yet.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
Interesting. The testmap I made did not have this issue, but maybe because it has enough time to turn around and be on the correct course.

I was using a move speed value of 0.1 for the unit, and a turn rate of 50.

A quick and dirty workaround to keep using the game's pathing would be to save the unit's target location and re-order it to move there every few seconds.
 
Level 2
Joined
Feb 2, 2015
Messages
8
Hmm, I guess I'll trigger it then. At least it won't be too hard to do other movement effects that way.

Still, if anyone knows of a different way to do this, don't hesitate to reply. It could be useful in some way.
 
Level 12
Joined
Mar 24, 2011
Messages
1,082
Btw, watch out for the turning speed and step distance.
If the turning speed is too slow or the step is too big and you give a move order somewhere close to it, the unit may end orbiting around the move-to point and never reach it.

//Edit// Oh, that's an old post... didn't notice...
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
I did a quick test using the following (horribly inefficient) code:
Minimum period for StarCraft II is 0.0625. This matches the same period that units naturally move at (graphics are interpolated with separate thread to anywhere from 30 to >200 Hz depending on resources and display device).

However I agree that your solution is the right approach. SC2 movement (like WC3) does not allow arcing naturally so triggers only seem a logical option. You might need to cache move orders as I think moving in this way loses their current order.

On the other hand there might be a solution involving firing the unit as a missile since arcing is supported by missile movers (you can define a turn rate).
 
Status
Not open for further replies.
Top