Articles

UnitySteer: Experimental vehicle and radar changes

15

Lots of UnitySteer changes this last week. Mikko Mononen was kind enough to comment on a neighbor avoidance approach I was trying out, and suggested something based on his own DetourCrowd. I promptly implemented it, only to run into an oscillation problem. After a quick review, it turns out that the oscillation wasn’t being caused directly by the RVO implementation, but instead by some leftover details from OpenSteer.

You see, previously UnitySteer’s Vehicles kept track of their speed, and calculated their velocity by projecting the speed along the vehicle’s forward vector. This is the way OpenSteer does it, since it seems mostly focused on vehicles that act that way, but it has the effect of assuming that the vehicle can only move forward and backwards – which causes a problem when I aimed to create vehicles which could side-step (necessary for move natural agent behavior). One could apply a sideways force – and several behaviors were doing just that – but all the vehicle calculations assumed that the recorded speed was being projected along the Vehicle’s forward. This messed up future vehicle position predictions when the agent was moving slightly sideways but not enough to turn, since the agent’s future position did not lay along its forward vector.

Needless to say, this is not a behavior that you want if you’re implementing cars, but for my bipedal agents it is perfect.

While I was at it, I’ve also changed the way that Radars are used. We previously kept track separately of a layer for obstacles and one for vehicles, which was just silly. Right now we just have a property for the layers checked, and any gameObject with a DetectableObject component which is not a vehicle will be considered an obstacle.

These are not the only changes, however. The latest modifications are:

  • Steering behaviors are no longer ticked independently. Autonomous vehicles will now add to the priority queues a method that is ticked for calculating and setting the Vehicle’s Velocity, which will then be applied on every FixedUpdate.
  • Steering behaviors no longer cache the force value, and will calculate it every time that the Force property is queried.
  • The vehicle’s Velocity is no longer estimated based on speed and the forward vector. Instead I am recording the actual velocity applied to the vehicle.
  • The vehicle’s Speed is now no longer a property you can set, and is instead calculated based on the vehicle’s velocity.
  • Removed Radar.ObstacleLayer. Any DetectableObject that is not a vehicle will be considered as an obstacle.
  • Removed Radar.ObstacleFactory. DetectableObjects should know how to create their own obstacles if they’re not spherical.
  • Updated other steering behaviors to work with DetectableObjects.
  • Added methods to Radar to create a list of DetectableObjects to be ignored.

Finally, I’ve begun using more Linq during this process, because I really like its expressiveness and it has served us very well on the game. Unity however has issues with Linq on iOS, since it seems to be ignored by their AOT compilation – your game will build just fine, but you’ll get runtime exceptions once you deploy. This means that this branch is not suitable for iOS use until Unity improves their AOT compilation support for generics (which by their own admission is quite limited).

As before, this is an experimental branch, so here be dragons. Like I mentioned on a commit log, this is looking more and more like UnitySteer 3 instead of a point release, but I’m happier now about the general state of things.

  1. John
    John03-23-2011

    Hi Ricardo,

    I have been seeing an issue that I can’t figure out and wanted to make sure it isn’t a problem in UnitySteer. I have a path going all over a terrain and one part of it goes around a block. The issue is sometimes, not always, the vehicle will seem to take a shortcut after the 2nd or 3rd run; it’s not always consistent but of all the testing that seems to be the most consistent.
    My path is an array of gameobjects that I assign to a script and in the script I create the path for SteerForPathSimplified by taking the transform.position for each point and creating the Vector3. Hopefully this is enough information for you. If there are any other questions about my logic please let me know.

    Thank you,
    -John

    • Ricardo J. Méndez
      Ricardo J. Méndez03-24-2011

      Hi John,

      SteerForPathSimplified predicts the future position along the path on the prediction time you’ve set, and aims for that spot. That *could* end up causing it to take shortcuts around bends if either speed is large or the prediction time is too far ahead. Try lowering the prediction time and check how it acts.

      This implementation is rather trivial, so it has those “peculiarities”. AngryAnt mentioned he was going to do one that stuck to a path tunnel, but I’m not sure what the progress is on it.

      • John
        John03-24-2011

        OK I’ll try lowering, if that doesn’t work I was thinking about “locking” it from looking too far ahead, AKA only using the next path point. Is this possible with the class structure (private, public)?

        • Ricardo J. Méndez
          Ricardo J. Méndez03-24-2011

          Not sure if I explained myself. The behavior does not calculate things in terms of number of waypoints, but in world distance units along the path. Say your speed is 2 and your prediction time is 1.5. This means that on an update, the behavior will calculate which point in the path is 3 world units (2 * 1.5) ahead of it, measured along the path and not in as straight line on the world, and it will then aim for that point. Therefore, if the agent is at a point where there is a bend that measures less than 3 units, it’ll appear like it’s taking a shortcut.

          Does that clarify things?

          To answer your question: you *could* rewrite it to act in term of waypoints, as opposed to distance, but I don’t think it’ll be very useful.

          • John
            John03-24-2011

            OK thank you, that helps and yes it clarified things.

  2. John
    John04-13-2011

    Hi, it’s me again. UnitySteer’s been working great for a while now but I’ve ran into another problem I wanted to check with you with for direction before going in the wrong route.

    I have a vehicle with four wheel colliders. I have SteerForPathSimplified attached to the vehicle and it drives great, however when it collides with another vehicle it will slow down and in some cases roll back and never stop. I did some debugging and it looks like the wheel colliders RPM values are high in the backwards direction and never getting updated so the vehicle just continues going in the opposite direction or not going forward fast. It almost looks like the force from UnitySteer and the rpm applied to the wheel colliders are fighting with each other.

    Is there something in UnitySteer that takes into account wheel colliders or would I need to write something to do this?

    Thank you,
    -John Flaherty

    • John
      John04-13-2011

      One thing I noticed is if I apply infinity brake torque to the wheel collider it doesn’t have this problem since the wheels will never rotate, thus not countering the force applied by UnitySteer. Does this sound like a viable fix?

    • Ricardo J. Méndez
      Ricardo J. Méndez04-14-2011

      Hi John,

      I’ve never combined them, so there’s no off-the-shelf code that does it. The fix you mention might help, but I cannot tell off the top of my head if it has any implications. Please keep me posted on if that solved your problem permanently.

      • John
        John04-14-2011

        Well I did about 2 hours of testing and it seems to work really well. It looks how a vehicle with a larger mass driving into another vehicle would look so I’m going to keep it. I just made a script that attaches to the root that finds all wheel colliders and sets their braketorque to Infinity on Start().

  3. Tom
    Tom04-14-2011

    Hi Ricardo
    “Right now we just have a property for the layers checked, and any gameObject with a DetectableObject component which is not a vehicle will be considered an obstacle.”

    Where is DetectableObject component defined? I’m new to UnitySteer using 2.1. Do you have any docs that can help me ? Also if I want to be able try UnitySteer under iOS should I rollback to some older version of UnitySteer? Thanks.

    I posted in UnityAnswers under tag UnitySteer-2.1 fyi. I didn’t see a local forum here.

    Great Work BTW !!!!

Leave a Reply