I have a real time battle system with a 'follow the leader' type of movement AI. You can turn off the movement AI by pressing a key so that you can position your various party members without them following you. The problem with that is that when the movement AI is inactive, gravity seems to be disabled.

For example, I have an enemy with an ability that knocks you flying back and upward. If the character is not currently being controlled by the player and its Move AI is off, it will not fall from that height unless i re-enable its move AI or take control of it (so that it no longer needs a movement AI).

Using the gravity option in rigid body just makes it go through the floor somehow. Using the gravity option with a capsule collider makes it fall but it then tumbles around as if it is a beachball (also, it doesn't walk around correctly either).
  • edited September 2016
    After looking into it a bit, even if the move AI is enabled, if a move isn't triggered (e.g. combatant gets knocked upward but not far-away enough to trigger the 'follow' move) gravity won't work.

    I think this is related to the whole 'combatants spawning above ground' thing and it seems like the implementation should be that gravity is always active no matter what unless explicitly disabled by some sort of option - rather than only being active when moving is happening.

    Potentially this could be something as simple as putting a
    this.controller.Move((Physics.gravity) * t)
    as an else to the if(doMove) condition in SimpleMove.cs, though I'm not sure if that would cause issues or if it's the right way to do it.

    Incidentally, is it possible to 'override' the DLL scripts with same-name copies of the scripts from the source code, so I can test if these things work without compiling ORK (which I'm not even sure how to do)?
    Post edited by Juryiel on
  • edited September 2016
    I made the following script that I added as a component to a combatant and it seems to fix things, if anyone needs it while a real fix is worked out within ORK:
    using UnityEngine;
    using ORKFramework;


    using System.Collections;

    public class Jury_GravityFix : MonoBehaviour {
    private CharacterController controller;
    private float distanceToGround;
    private float prevDistanceToGround;
    private int fallingFrames = 0;
    private int maxFallingFrames = 10;
    private float moveThreshold = 0.01f;
    private Vector3 prevPosition;


    // Use this for initialization
    void Start () {
    this.controller = this.transform.root.GetComponentInChildren<CharacterController>();
    this.fallingFrames = 0;
    this.prevDistanceToGround = -1;
    this.distanceToGround = -1;
    this.prevPosition = this.transform.position;

    }

    // Update is called once per frame
    void Update () {
    if (Vector3.Distance(this.prevPosition, this.transform.position) < moveThreshold) //If object hasn't moved
    {
    RaycastHit hit = new RaycastHit();
    if (Physics.Raycast(transform.position, -Vector3.up, out hit))
    {
    this.distanceToGround = hit.distance;
    }
    else //If the raycast hits nothing, that means you fell off the world so uh... keep falling
    {
    this.distanceToGround = float.NaN;
    }


    if (this.distanceToGround > 0 && this.fallingFrames < this.maxFallingFrames)
    {
    if (this.distanceToGround == this.prevDistanceToGround)
    {
    this.fallingFrames += 1;
    }

    float t = ORK.Game.DeltaMovementTime;
    this.controller.Move((Physics.gravity) * t);
    this.prevPosition = this.transform.position;
    this.fallingFrames = 0;
    }
    this.prevDistanceToGround = this.distanceToGround;

    }
    else
    { //if outside functions changed the position, we should reset the falling checks.
    this.fallingFrames = 0;
    this.prevPosition = this.transform.position;
    }

    }
    }
    It checks if a combatant has moved, and if he hasn't, it tries to make him fall for 10 frames, after which it stops (so that the combatant isn't perpetually in falling animation). If a combatant has moved, it resets the 10 frames count, and then once again re-checks for 10 frames once the combatant stops moving to within moveThreshold amount. The reason it checks if a combatant has moved is so that it doesn't apply the gravity twice (e.g. a moving combatant is affected by gravity already).

    You may also need to disable it from the player you control since this player will fall just fine even if he's not moving. But you may not, since due to his falling, he is moving, so the script should not activate until he is on the ground.
    Post edited by Juryiel on
  • Well, the simple move available for the move AI is just a very simple script to get you started. You might want to switch to using NavMesh or custom solutions.

    Also, for having gravity and stuff - that's up to whatever style you want for your game. E.g. rigidbody that constraints rotation will prevent the tumbling.
    Please consider rating/reviewing my products on the Asset Store (hopefully positively), as that helps tremendously with getting found.
    If you're enjoying my products, updates and support, please consider supporting me on patreon.com!
  • edited September 2016
    Is it possible to change the SimpleMove script on ally combatants you aren't controlling in a realtime battle system, while still being able to use Move AIs though? I wasn't able to figure out how to do that, which is why I instead used this cloogy method. I agree that this solution with using a custom movement script would be the most ideal but it didn't seem possible.
    Post edited by Juryiel on
  • edited September 2016
    Ah I finally found the setting under the specific Move AI a combatant is using, and then spent a few hours not undersanding why it was doing crazy things because I didn't notice I had to specify the Move() and Stop() functions :P

    Yay it works, thanks for pointing me in the right direction!

    But there is one problem I still can't figure out. I have multiple player combatants who can become the player. The currently controlled combatant has his own move script. But once the MoveAI movement script becomes attached to the combatant, it won't get removed when that combatant becomes player controlled, which then causes interference as the two movement scripts battle it out. Is it possible to unattach or disable the move AI's custom movement script when a combatant is player controlled? Right now I'm doing the following which works but I don't want to have it hard-coded and it would be nice if the Move AI's script would remove itself whenever the player took control of the combatant:
    public void PlayerChanged(Combatant newPlayer, Combatant oldPlayer) {
    if (newPlayer.GameObject != null) {
    ORK_Modified_ButtonPlayerController playerControlScript = newPlayer.GameObject.GetComponent<ORK_Modified_ButtonPlayerController> ();

    //Enable the Player Follow AI's move script for the old player, and disable it for the new player
    newPlayer.GameObject.GetComponent<Jury_SimpleMove>().enabled = false;
    oldPlayer.GameObject.GetComponent<Jury_SimpleMove>().enabled = true;


    }
    }
    Post edited by Juryiel on
  • The move AI isn't used when a combatant is the player, so the move script shouldn't be called any longer.
    Please consider rating/reviewing my products on the Asset Store (hopefully positively), as that helps tremendously with getting found.
    If you're enjoying my products, updates and support, please consider supporting me on patreon.com!
  • edited September 2016
    Yes but the script has stuff in 'Update()' that does stuff like gravity outside of the doMove conditions, and the script is added as a component to the player. It absolutely definitely interferes since I've tested manually turning it on and off (and with my code above). It doesn't interfere with the Move() and Stop() functions as you claim, since those are never called, but the stuff in Update() interferes, and it needs to be there since that script is used to handle gravity.
    Post edited by Juryiel on
  • Naturally, update will interfere with it as it's called each frame by Unity. The simple move script is just a very simple script without any checks there, so you'll have to use NavMesh or custom solutions (where this is handled) for this situation.
    Please consider rating/reviewing my products on the Asset Store (hopefully positively), as that helps tremendously with getting found.
    If you're enjoying my products, updates and support, please consider supporting me on patreon.com!
  • Yes, thinking about it more makes sense that I should only include the functions the move AI uses in its movement script, and everything else should be separately handled via different functionality. I thought initially it would be easy for the move AI to just remove its script when the combatant switches to being player controlled but I can see this would lead to other, different issues.

    Thanks!

  • Hmm I had a chance to play with different implementations of custom controls for non-player ally combatants in my party and nothing seems great for setup the way it's currently done.

    Using Update() is needed to do some things (like jumping, or falling), so that means I either need to have those in separate scripts and then have crazy checks to compute the overall movement, or I need to manually destroy the scripts attached by Move AI whenever the ally combatant becomes the player to prevent interference.

    So maybe disabling the Move AI script is worth while for ORK to do automatically when the combatant is player controlled, or alternatively provide some type of MovementUpdate() function to the AI that does the same thing as Update() but isn't called when the Move AI is disabled.

    Just feedback at this point since I implemented work arounds as described :)
  • Well - usually the falling part would be handled by the rigidbody using gravity. If you need the movement script used by the move AI to handle that as well, you'll have to implement it that way.

    E.g. do the movement stuff in the update function only when a flag (bool) is set to move to a destination (i.e. position function will set the flag to true, stop/reaching the target will set it to false). If the flag is false, only do the gravity stuff.
    Please consider rating/reviewing my products on the Asset Store (hopefully positively), as that helps tremendously with getting found.
    If you're enjoying my products, updates and support, please consider supporting me on patreon.com!
  • Right rigidbody gravity would work and I may go that route.

    That second approach works until the Ally becomes Player controlled by the player. In that case the flag in the AI control script will be false and gravity will happen from that script, which will interfere with the player control script.

    Ideally you'd want two control scripts that act exclusively such that when one is active the other is not - one when the player is controlling a party member, and one when an AI is controlling it. But right now this is only possible through scripting (e.g. if you listen for when the player changes and disable the AI control script).
  • Well, add a check for that as well :)
    Please consider rating/reviewing my products on the Asset Store (hopefully positively), as that helps tremendously with getting found.
    If you're enjoying my products, updates and support, please consider supporting me on patreon.com!
  • Yeap :) it's what I'm doing. As I said at this point it was more feedback that it should probably be an option to have the script disabled when not being controlled by the AI, but yeah not too tough to get around.
Sign In or Register to comment.