Forum rules - please read before posting.

3D camera to follow player from side view

2»

Comments

  • Thank you, this is enough. I've recreated the problem.

    It's an issue with Paths that are set to Loop. If you set it to Forward, the Player will be able to move in both directions - only without looping.

    I shall work on a fix for this as part of the next release.

  • Thank you so much, it works for me too. Do you have a schedule for the next release already planned?

  • I have no ETA, no. PM me if you'd like to be involved in testing.

  • Hello, I'm back again with some camera issues. We've been testing the circling camera, which works in certain parts of the game, but we'd need a side scrolling camera, which would keep it's distance and rotation from the main character at all times, which would eliminate the need to switch between navigation cameras. I've been trying to get this thing working with 3D camera set to side-scrolling, but how should I configure the camera, as the player is locked on a lopped path, and the camera should be locked on the side view, following the player from one direction. Basically a 2D camera, but in 3D space.

  • edited July 2021

    Side Scrolling will move the camera in 2D only.

    To have the camera maintain a persistent angle relative to the Player, you need a frame of reference for it to know which way to face. This was the intent behind my original script, where you mentioned the Player circling the scene.

    Why is there a need to switch camera?

    If the actual scene is more of an oval shape, you can try something more complex where - instead of having a "centre point" to spin around, you have a "centre line":

    using UnityEngine;
    
    namespace AC
    {
    
        public class SpinCameraOval : _Camera
        {
    
            public float heightOffset = 1f;
            public Transform centreLineStart;
            public Transform centreLineEnd;
            public float distance = 10f;
    
            public override void _Update ()
            {
                if (Target)
                {
                    float p = (Target.position.x - centreLineStart.position.x) / (centreLineEnd.position.x - centreLineStart.position.x);
                    Vector3 centrePoint = Vector3.Lerp (centreLineStart.position, centreLineEnd.position, p);
    
                    Vector3 direction = (Target.position - centrePoint).normalized;
                    Vector3 ownPosition = centrePoint + (direction * distance) + (Vector3.up * heightOffset);
                    transform.position = ownPosition;
                    transform.LookAt (centrePoint);
                }
            }
    
        }
    
    }
    

    (Replace .x with .z if the oval is along the z axis)

    The other method would be to have the camera somehow align itself to be perpendicular to the Path, which'd be a lot more complicated.

  • So it's not possible to have a single camera to be pointed directly towards the character on a side view where it would maintain the it's distance and side view direction towards the player in all circumstances? I've tried messing around with the game camera settings, but I haven't been able to get it working. I'll try the oval approach, but the ideal situation would be that the shape of the game area would not be affected on how the camera follows the player. So basically I'd like to achieve the functionality of a 2D camera, but on 3D.

  • So it's not possible to have a single camera to be pointed directly towards the character on a side view where it would maintain the it's distance and side view direction towards the player in all circumstances?

    You could have a camera that basically sticks to the Player's right side by just parenting it to the Player. The issue is that even micro-adjustments to the Player's rotation will cause big changes in the camera's position. To do something like this properly, you need the camera to have a better frame of reference.

    Again, one possible avenue may be to have the camera refer to the Player's path - but see how the oval approach goes first.

  • I tried the oval approach, but there's so much height differences in the scene as well as sharp turns (see here: https://drive.google.com/file/d/1tumvCNqHiHcwKYeT5UBliYalBqIISCD1/view?usp=sharing) so I wasn't able to get it working correctly. At the moment what I've done, is have two Spin Cameras on each end of the island and Side Scrolling cameras between them on the long sides of island. It works reasonably well, but controlling the distance of the player is difficult.
    I tried to put a camera as a child of the player character, but - like you said - it didn't work out quite well :)
    I think I can fine tune the current system to work the way we want to, but it would be super awesome & mega cool to have a camera that would maintain it's position on the side view of the player.

  • I tried dabblibg with different camera setups, but having a camera that would align itself on the path the player is moving would probably be the best solution to this. Then it would keep the set distance of the character in all occasions, as it would circle outside the path loop. How could this kind of functionality be achieved?
  • Essentially, it would be a case of working out which Path segment the Player is currently in, calculating that segment's normal, and then placing the camera some distance away from it in that direction.

    I gave this a go myself, but it did become too cumbersome to work well in my testing. The issue really is when it comes to interpolating between the previous and next segments to keep things smooth.

    What might be the better option is to look into a pre-defined set of waypoints for the camera to take, and then have a simple script to sync the camera's position along these waypoints with the Player's position along their own AC Path.

    Cinemachine offers this in the form of its Dolly Cart component

    https://docs.unity3d.com/Packages/com.unity.cinemachine@2.3/manual/CinemachineDollyCart.html

    Though it would mean the dolly path has to be manually built, IMO that would probably give the best results in the end. Give it a try with a more simple scene as a test - if it works for you, I can assist with a script that calculates how far along the AC Path the Player character is, which could then be fed into the above component's Position property.

  • Cinemachine Dolly did the trick! Thanks again for your help, the camera works like a charm now!
  • Hello again!

    I'm reasonably happy with the Cinemachine, but is it possible to configure the dolly track camera with AC so that it would keep a set distance from the player character on the path? This is basically the only issue I'm currently struggling with. I've been fine-tuning the dolly track so this isn't a huge issue, but it would be great if this would be possible :)

  • It would involve custom scripting that's mainly on the Cinemachine side of things - modifying the track's waypoints given the AC Path normals.

    Untested, but could be along the lines of:

    using UnityEngine;
    using Cinemachine;
    
    public class UpdateDollyTrack : MonoBehaviour
    {
    
        public AC.Paths myPath;
        public float distance = 10f;
        public CinemachinePath cmPath;
    
        [ContextMenu ("Update Dolly track")]
        private void Test ()
        {
            for (int i = 0; i < myPath.nodes.Count - 1; i++)
            {
                Vector3 waypointPosition = GetWaypointPosition (i);
                cmPath.m_Waypoints[i].position = waypointPosition;
            }
        }
    
        private Vector3 GetWaypointPosition (int nodeIndex)
        {
            Vector3 nodeDirection = (myPath.nodes[nodeIndex+1] - myPath.nodes[nodeIndex]);
            nodeDirection.y = 0f;
            nodeDirection.Normalize ();
            Vector3 normalDirection = Vector3.Cross (nodeDirection, Vector3.up);
    
            Vector3 nodeAverage = (myPath.nodes[nodeIndex+1] + myPath.nodes[nodeIndex]) / 2f;
    
            Vector3 wayPointPosition = nodeAverage + (normalDirection * distance);
            return wayPointPosition;
        }
    
    }
    

    In practice, it may be more hassle than it's worth - it won't be possible to have the track be entirely consistent 100% of the time, given that the AC Path is linear and the Cinemachine Path uses bezier curves.

  • Okay, I'm once again back with this :smiley:

    Cinemachine's third person camera can be used instead of the dolly track. I have an empty game object as a child of the player, which the camera follows and looks at. This works great except when I turn to the opposite direction. The camera rotates along with the character. I need to flip the child game object when the direction changes, but I can't figure out how to do that.
  • You can attach a script that controls the child object's rotation in LateUpdate.

    To keep it at an angle you can set in the Inspector, for example:

    using UnityEngine;
    
    public class ForceAngle : MonoBehaviour
    {
    
        public float angle = 0f;
    
        private void LateUpdate ()
        {
            transform.eulerAngles = new Vector3 (0f, angle, 0f);
        }
    
    }
    

    You could extend this to set the value of "angle" if needed, but it would be down to what you need to set it to.

  • Thanks for your reply, but this is not exactly what I was looking for

    Here's how the camera should work: https://drive.google.com/file/d/1ptEJePpRnMm89unNAJkavxzEzuTooghz/view?usp=sharing

    So basically the child object should rotate with the player so that the camera can follow it just from one side. The script you provided halts all angular transform, but the gameobject should rotate with the player movement, but it shouldn't flip the camera to the opposite side when the direction changes. This is what it does, when the direction changes: https://drive.google.com/file/d/1Sf-CIgGQYGCb0LftwrKheQlRtFnGXkY0/view?usp=sharing

    So how can I configure the child game object's rotation so that it's transform is the same as in the first image despite the player changes direction? I want to have the camera to stay on one side of the player despite the direction the character is moving to. This is basically the same thing I've achieved with the dolly track, but this way it would be a lot easier to maintain a set distance from the player character.

  • What you're getting is the issue I described earlier with parenting to the Player.

    The script wasn't intended to work straight away - but to demonstrate that you first need to separate its rotation from that of the Player.

    What you need to do is extract which part of the Path the Player is on, calculate it's direction, and then a corresponding angle that you can apply to the child object.

    In case of rotation offsets, you may need to attach this to an interim object that is an immediate parent of your camera target, but you'd be looking for something like this:

    using UnityEngine;
    using AC;
    
    public class ForceAngle : MonoBehaviour
    {
    
        public float lerpSpeed = 10f;
        private float angle = 0f;
    
        private void LateUpdate ()
        {
            Paths path = KickStarter.player.GetPath ();
            if (path == null) return;
    
            int targetNodeIndex = KickStarter.player.GetTargetNode ();
            bool isGoingForwards = path.pathType != AC_PathType.ReverseOnly;
    
            int prevNodeIndex = isGoingForwards ? (targetNodeIndex - 1) : (targetNodeIndex + 1);
    
            if (prevNodeIndex < 0)
            {
                prevNodeIndex = path.nodes.Count - 1;
            }
            else if (prevNodeIndex >= path.nodes.Count)
            {
                prevNodeIndex = 0;
            }
    
            if (!isGoingForwards)
            {
                int temp = prevNodeIndex;
                prevNodeIndex = targetNodeIndex;
                targetNodeIndex = temp;
            }
    
            Vector3 lineDirection = path.nodes[targetNodeIndex] - path.nodes[prevNodeIndex];
            lineDirection.y = 0f;
            lineDirection.Normalize ();
    
            Vector3 lineNormal = Vector3.Cross (Vector3.up, lineDirection);
            float newAngle = Vector3.SignedAngle (Vector3.forward, lineNormal, Vector3.up);
    
            if (newAngle < 0f) newAngle += 360f;
    
            angle = (lerpSpeed > 0f) ? Mathf.Lerp (angle, newAngle, lerpSpeed * Time.deltaTime) : 0f;
            transform.eulerAngles = new Vector3 (0f, angle, 0f);
        }
    
    }
    
  • Wow, I can't thank you enough, this works like charm!
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.