0
\$\begingroup\$

It's a very poorly worded question because I'm not exactly sure how to put it into words that are of appropriate number for a title. Read on for a better explanation. (Using Unity API, C#)

Basically, I have an AI class in a spaceship game. I can assign the AI a target GameObject, and the AI will look in the direction of and chase after it's target. I would like to make the AI be able to strafe in circles around the target. Since the AI always faces its target, I can simply TransformDirection(Vector2.left/right) and it will orbit the target nicely, but if the target is moving it always breaks orbit.

To combat this, I want to add the target's velocity to the strafe velocity of the AI. However, I have different classes for the player's ship and the AI ships whom also might be targeted by another AI. All of my ship classes have a field for the ship's velocity, but since they are different classes, I thought I may access the velocity field by doing a GetComponent() and passing some sort of predicate => T has a Vector2 field named "velocity". Is there some way to achieve this?

\$\endgroup\$
1
\$\begingroup\$

You have 3 options I can think of:

Inheritance, all possible target types inherit from single base classclass TargetBase : MonoBehaviour with velocity property, probably the most efficient solution

target.GetComponenet<TargetBase>().velocity

Introduce interface IHasVelocity, implement the interface in target classes and filter for components that implement it, decent solution especially from code style viewpoint

((IHasVelocity)target.GetComponenets().ToList().Single(c => c is IHasVelocity)).velocity

Using reflection, the most flexible but also more dangerous, possibly also least efficient solution

target.GetComponenets().ToList().Select(c => { 
  Vector2? value;
  c.GetType().GetProperty("velocity").GetValue(value, null)
  return value; }).Single(v => v != null).Value

all solution will also work with fields with only minor changes. Code syntax not tested.

\$\endgroup\$
  • \$\begingroup\$ I use the reflection method to link my UI to other objects, its kinda safe and fast if you cache all the reflection nastiness. Its build around this but with some heavy mods so I can call methods and functions from my UI using commands. blogs.msdn.microsoft.com/shawnhar/2012/04/20/… \$\endgroup\$ – Justin William Stanley Bryant Feb 21 '17 at 15:00
  • \$\begingroup\$ I had used something like the last option in a previous project, but I didn't think to apply reflection here as well. Thanks for the detailed answer. \$\endgroup\$ – Tanner Fix-It Smith Feb 24 '17 at 0:46
0
\$\begingroup\$

Check whether the target has changed its position within the last frame and then add that change to your AI's transform.

//after doing the stuff you need to do, check the changes and add those up
if(lastPos != target.transform.position && currentlyCirclingTheTarget)
{
    transform.position = transform.position + (target.transform.position - lastPos);
    lastPos = target.transform.position
}

I'm not sure if this will work exactly as I think it will but you should be able to incorporate the logic into your own code if it doesn't work perfectly.

(This will only work well if you want the AI to lock on to your target and stay within a certain distance, if you have different maximum speeds for different units, this will mean a slower AI will be faster when it locks on to a faster target.)

\$\endgroup\$
  • \$\begingroup\$ I knew that this was an option, but I would have liked to avoid having to store extra variables. You're right, though, this would work. All I'd need to do is apply the ship's speed factor to the vector before translating which would remedy the issue of slower ships becoming faster. However, this doesn't answer the question I posed within the last paragraph; rather it's a workaround to avoid the issue. \$\endgroup\$ – Tanner Fix-It Smith Feb 21 '17 at 8:35
  • \$\begingroup\$ Why not just have two states for your AI then? In State 1, your AI will follow the target, in State 2 your AI will circle the target. If the target is X units away, switch to State 1 and if not, switch to State 2. Should be relatively easy to wrap your code in that. @TannerFix-ItSmith \$\endgroup\$ – John Hamilton Feb 21 '17 at 8:49
  • \$\begingroup\$ That's exactly what I've done, actually. The problem isn't in implementing a state in which the AI circles the enemy. The problem lies when calculating the angle at which the AI should circle the target in order to maintain a stable orbit, even while the target is moving. I'd like to reach into whatever script is controlling the target and grab it's velocity which I have made sure is stored in a field across all different scripts that can control a ship. \$\endgroup\$ – Tanner Fix-It Smith Feb 21 '17 at 11:00
  • \$\begingroup\$ What do you mean? If your AI is always looking at the target and moving left or right, it will automatically circle the target, unless you're doing the movement in world space. \$\endgroup\$ – John Hamilton Feb 21 '17 at 11:51
  • \$\begingroup\$ The movement is in world space because the AI is a completely separate in-game entity and needs to be able to move independently. \$\endgroup\$ – Tanner Fix-It Smith Feb 24 '17 at 1:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.