Hello guys, so I’m making a sonic fangame and I’m trying to implement a mechanic known as light dash, in which the character follows trails of collectible rings (like coins in the sonic universe) after a single player input.
This is the script that’s supposed to translate the character from its current position to the next ring’s position, and stop the action of no rings in the vincinity are available.
Right now only the “OnEnable” section seems to be working. My character stops all velocity and the direction/movement script “Dir” and different attack mechanics script “HomingAttack” (actually includes all other mechanics. it also enables this “lightDash” script on player input and selects the first ring) are properly disabled. Gravity is properly disabled as well.
My character just stops and stays there, motionless. I don’t know what I’m doing wrong though
I just tested your code and it works fine with just a couple of small changes. On line 28 you’ve got a typo, it should be “nextRing == null” instead of just “= null”. Your line 49 transform.LookAt is another problem. You’re assigning it the same ring repeatedly in FixedUpdate so your character will go toward that rings position, then once it gets there it will turn around and go back toward it, and do that endlessly. If the ring has been picked up it no longer has anything to go toward. You need to keep updating it to the next ring in the series during the FixedUpdate so it will always look and move toward the position of the next ring.
isn’t line 38 supposed to call StopLightDash() (which in turns deactivates this script and reactivates the others) once the variable nextRing is no more? isn’t it already updating what the next ring is in lines 30 to 36?
Edit: correction, you do set the nextRing in the loop, but it’s never removed from the array, so you will probably get a message about the game object being destroyed (assuming they’re destroyed when collected*).
However, I think you want to finish the foreach loop without the ‘else’ statement. If at the end of it, nextRing is still null, then you want to stop. Otherwise, if just the first one doesn’t match, you’d stop. That would only work if they were already sorted by closest to the player.
You could also break from the loop when you find a valid ring.
I’ve got this, but it isn’t working. I don’t understand why it’s not calling StopLightDash() even though nextRing == null condition is met… The character looks at the ring, and then collects it, but afterwards he just doesn’t move and I get this:
MissingReferenceException: The object of type ‘GameObject’ has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.
```csharp
private void FixedUpdate()
{
if (nextRing == null)
{
foreach (var ring in rings)
{
if ((this.transform.position - ring.transform.position).magnitude < lightDashDistance)
{
nextRing = ring;
Ya, because the one that was collected is still in the array after it was destroyed.
Make sure you remove the entry from the collection (you might prefer to use a list for this).
Oh my apologies you’re right. When I typed my reply I got focused on looking at the “is not null” section and completely overlooked what was going on in the null section. When I tested your code I wasn’t destroying the rings so I didn’t encounter the issue of them remaining in the array after the player hitting them.
Well, as the message says, you could check for null in the loop and skip/remove them.
However, currently you’re sometimes checking entries that are null, and that is the issue.
Ok so I got this working BUT even though in the editor the other two scripts “HomingAttack” and “Dir” appear disabled, they’re still working…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lightDash : MonoBehaviour
{
public Rigidbody sonic;
public List<GameObject> rings;
public GameObject nextRing;
public float lightDashDistance;
public float lightDashSpeed;
private void OnEnable()
{
rings.AddRange(GameObject.FindGameObjectsWithTag("ring"));
GetComponent<Dir>().enabled = false;
GetComponent<HomingAttack>().enabled = false;
sonic.velocity = Vector3.zero;
sonic.useGravity = false;
}
private void FixedUpdate()
{
if (nextRing == null)
{
rings.Remove(nextRing);
foreach (var ring in rings)
{
if (ring != null && (this.transform.position - ring.transform.position).magnitude < lightDashDistance)
{
nextRing = ring;
}
else
{
StopLightDash();
}
}
}
if (nextRing != null)
{
this.transform.LookAt(nextRing.transform);
sonic.AddForce(transform.forward * lightDashSpeed * Time.deltaTime, ForceMode.VelocityChange);
}
}
private void StopLightDash()
{
GetComponent<Dir>().enabled = true;
GetComponent<HomingAttack>().enabled = true;
GetComponent<HomingAttack>().chargeState = 3f;
sonic.useGravity = true;
sonic.velocity = Vector3.zero;
this.enabled = false;
}
}
EDIT: I just saw this script “lightDash” is flickering between enabled and disabled extremely fast. how come? once it is disabled it shouldn’t be able to reenable itself right?
So turns out the lightDash script actually gets disabled since the first ring, but the variable in which I store my player input for the light dash, inside the character mechanics script “Homing Attack” is still “true” so it reactivates the “lightDash” script again.
How come lightDash is disabling itself despite the fact there are still rings in range?
EDIT: I moved the “else {StopLightDash()}” to the end of the script, as follows. Seems to be working now!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class lightDash : MonoBehaviour
{
public Rigidbody sonic;
public List<GameObject> rings;
public GameObject nextRing;
public float lightDashDistance;
public float lightDashSpeed;
private void OnEnable()
{
rings.AddRange(GameObject.FindGameObjectsWithTag("ring"));
GetComponent<Dir>().enabled = false;
GetComponent<HomingAttack>().enabled = false;
sonic.velocity = Vector3.zero;
sonic.useGravity = false;
}
private void FixedUpdate()
{
if (nextRing == null)
{
foreach (var ring in rings)
{
if (ring != null && (this.transform.position - ring.transform.position).magnitude < lightDashDistance)
{
nextRing = ring;
//rings.Remove(nextRing);
}
}
}
if (nextRing != null)
{
this.transform.LookAt(nextRing.transform);
sonic.AddForce(transform.forward * lightDashSpeed * Time.deltaTime, ForceMode.VelocityChange);
}
else
{
StopLightDash();
}
}
private void StopLightDash()
{
GetComponent<Dir>().enabled = true;
GetComponent<HomingAttack>().enabled = true;
GetComponent<HomingAttack>().chargeState = 3f;
sonic.useGravity = true;
sonic.velocity = Vector3.zero;
this.enabled = false;
}
}