AI shadow for racing game

Hi,
Is it possible that someone can give me advice/clue how to write script for shadow car.

I mean that when you’ll finish 1st lap, shadow of your car will appear and ride as you rode on the 1st lap.

I don’t know for where I have to start so I will be gratefull for your advices.

Store a list of positions and rotations every quarter of a second or so. On playback, smoothly lerp between them.

2 Likes

Ok, thank you :slight_smile:

I know how to write code that will save position and rotations but i don’t know conditions of loop. Can someone help me??

What have you tried so far? Knowing nothing about your code means that people can only give generalised answers rather than anything specific about your situation.

Also, just to check, have you done any of these? It will prove very helpful to have covered at least some of these. They will give you a good grounding in using Unity and also coding. :slight_smile:

To save position I did something like this:

private List shadowposition =new List();
private List shadowrotation =new List();
public GameObject car;
public Vector3 pposition;
public Vector3 rrotation;

private float nextActionTime = 0.0f;
public float period = 0.25f;

public void RememberPo()
{
pposition = car.transform.position;
rrotation = car.transform.eulerAngles;
shadowposition.Add (pposition);
shadowrotation.Add (rrotation);
}

void Update()
{

if (Time.time > nextActionTime)
{
nextActionTime += period;
RememberPo ();
}
}

Is it good??

Untested, but something like this:

    public class RaceCarRecorder : MonoBehaviour
    {
        [Serializable]
        public class CarTransform
        {
            [SerializeField] private Vector3 position;
            [SerializeField] private Quaternion rotation;

            public Vector3 Position
            {
                get
                {
                    return position;
                }
            }

            public Quaternion Rotation
            {
                get
                {
                    return rotation;
                }
            }

            public CarTransform(Vector3 position, Quaternion rotation)
            {
                this.position = position;
                this.rotation = rotation;
            }

        }

        [SerializeField] private Transform targetToRecord;
        [SerializeField] private Transform shadowObject;
        [SerializeField, Range(0.001f, 2.5f)] private float timeStep;

        private List<CarTransform> currentRecording = new List<CarTransform>();
        private List<CarTransform> previousRecording = new List<CarTransform>();
       
        public void StartRecording()
        {
            StartCoroutine("RecordingProcess");
        }

        public void FinishRecording()
        {
            StopCoroutine("RecordingProcess");

            if (currentRecording.Count > 0)
            {
                previousRecording = currentRecording;
                currentRecording.Clear();
            }
        }

        public void PlayLastRecording()
        {
            StartCoroutine(PlayRecordingProcess());
        }

        private IEnumerator RecordingProcess()
        {
            WaitForSeconds timer = new WaitForSeconds(timeStep);

            while (true)
            {
                currentRecording.Add(new CarTransform(targetToRecord.position, targetToRecord.rotation));
                yield return timer;
            }
        }

        private IEnumerator PlayRecordingProcess()
        {
            if (previousRecording.Count > 0)
            {
                WaitForSeconds timer = new WaitForSeconds(timeStep);
                for (int i = 0; i < previousRecording.Count; i++)
                {
                    shadowObject.position = currentRecording[i].Position;
                    shadowObject.rotation = currentRecording[i].Rotation;
                    yield return timer;
                }
            }
        }
    }

So this is the recorder itself. Now you just need something to call StartRecording, FinishRecording, and PlayLastRecording (that starts the shadow following the previous lap). Now this isn’t the finished thing, but it’s a good basis. You might want to lerp the recording between the two points so there is no ‘stutter’ and things like that, but the basic idea is here. Let me know if anything’s too confusing in the way I wrote the code here.

Thank you. And how can I trigger playback now?

Well I’d imagine you’d have some sort of collider with ‘isTrigger’ set to true over the finish line, and on OnTriggerEnter you’d call FinishRecording() then StartRecording() and lastly PlayLastRecording(). Something like that.

Yes I’ve got collider. Now I understand thank you

I do like the answer in the link bellow

1 Like

@Nigey Something it’s not working in this code. I have collider with name of tag “FinishLine” on the finish line. And when I across the fnish line Shadow it’s not working. I don’t know why?

Here is the code OnTriggerEnter:

void OnTriggerEnter(Collider other)
{

if (other.tag == “Shadow”)
{
PlayRecording();
StartRecording();
}

Okay, so it’s a matter of digging through the process and seeing at what point it stops working. Like for example, on the first round there won’t be a shadow, as there’s no previous lap yet. At that point are you recording the first lap, and is that working? You will be able to tell by checking the RaceCarRecorder component in the inspector. You will be seeing ‘Current Recording’ having lots of rows added to it. When that doesn’t work, check that you have called ‘StartRecording’ correctly and there’s no errors in your code. Supposing that IS working it means it’s saving positions/rotations okay, just not playing them correctly. So what’s going on?