0
\$\begingroup\$
bool tntFall = true;

void Awake()
{
    tntFallTime = Time.deltaTime / 0.05f;
}

void OnCollisionEnter(Collision coll)
{
    if (CurrentScene != "ColorGame" && CurrentScene != "PaintingGame" && coll.gameObject.tag != "Player" && CurrentScene == "TNT Run" && tntFall)
    {
        Debug.Log(coll.gameObject.GetComponent<MeshRenderer>().material.name);
        if (coll.gameObject.GetComponent<MeshRenderer>().material.name == "TNT_0 (Instance)")
        {
            coll.gameObject.GetComponent<MeshRenderer>().material = TNT_Mat1;
            StartCoroutine(coroutine);
        }
        else if (coll.gameObject.GetComponent<MeshRenderer>().material.name == "TNT_1 (Instance)")
        {
            coll.gameObject.GetComponent<MeshRenderer>().material = TNT_Mat2;
            StartCoroutine(coroutine);
        }
        else if (coll.gameObject.GetComponent<MeshRenderer>().material.name == "TNT_2 (Instance)")
        {
            coll.gameObject.transform.position = Vector3.Lerp(coll.gameObject.transform.position, new Vector3(coll.gameObject.transform.position.x,-10,coll.gameObject.transform.position.z), tntFallTime);
            Destroy(coll.gameObject, 3);
        }
    }
}

IEnumerator TNTFallDelay(int WaitTime)
{
    tntFall = false;
    yield return new WaitForSeconds(WaitTime);
    tntFall = true;
}

This my code from Player script. If you look at my Floor as you can see it's actually cubes holding together. All i want is;

  1. When player touches one of the cubes For the first time it will change material
  2. When player touches that cube Second time it will change material again
  3. When player touches that cube Third time cube is going to fall down.

But in these case (with my code) when i touch one of the cubes it does all of the if-else statements in a second and cube falls down.

\$\endgroup\$
3
  • \$\begingroup\$ How do you move your player? If you're changing its transform.position or using transform.Translate, you can expect OnCollisionEnter to be called every frame, because the physics engine is forced to treat the object like it's teleported and re-process all collisions from scratch. \$\endgroup\$
    – DMGregory
    Commented Apr 22, 2019 at 16:14
  • \$\begingroup\$ you can add a timer to your check to make sure that you have x amount of time in-between changes so if it gets called again early it will wait until the timer is reset to be able to change again. \$\endgroup\$ Commented Apr 22, 2019 at 16:16
  • \$\begingroup\$ @JustinMarkwell i did it, but cubes falls very fast and not synchronized \$\endgroup\$ Commented Apr 23, 2019 at 8:54

3 Answers 3

0
\$\begingroup\$

I'd move the responsibility for this from the player avatar to the tile they're sitting on, and correct some other errors while we're at it.

public class ColorChangingTile : MonoBehaviour 
{

    public Material[] materialSequence;

    Renderer renderer;
    float playerExitTime = float.NegativeInfinity;
    int state = 0;

    void Start()
    {
        renderer = gameObject.GetComponent<MeshRenderer>();
    }

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Player"))
        {
            // Add a little tolerance, so rapid vibration at the edge of collision
            // doesn't advance the state. We need to leave for some time then return.
            if (Time.time - playerExitTime > 0.1f)
                AdvanceState();
        }
    }

    void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("Player"))
        {
            playerExitTime = Time.time;
        }
    }

    void AdvanceState()
    {
        // If we're already falling, ignore further state changes.
        if (state == materialSequence.Length)
            return;

        renderer.sharedMaterial = materialSequence[state];
        state++;

        if (state == materialSequence.Length)
            StartCoroutine(FallThenDestroy(10f, 3f));
    }

    // This lets us animate out the fall before the destruction takes place.
    IEnumerator FallThenDestroy(float distance, float duration)
    {
        // 0.5f seconds later object will start to fall down.
        yield return new WaitForSeconds(0.5f);
        for (float t = 0; t < duration; t += Time.deltaTime)
        {
            // Fall some distance.
            transform.Translate(0, -distance * Time.deltaTime / duration, 0, Space.World);
            // Yield control to the engine to run for a frame, then resume here.
            yield return null;
        }

        // Destroy ourselves once the fall is over.
        Destroy(gameObject);
    }
}
\$\endgroup\$
7
  • \$\begingroup\$ Oh found another bug... If you stay on one of the cube and don't move (for the first time) you can stay there forever, and i don't want that, so need to set a timer and check if player stays again, if he is, change color againg and fall down. \$\endgroup\$ Commented Apr 23, 2019 at 11:14
  • \$\begingroup\$ Ah, you can do that in OnCollisionStay if you want. In future, make sure that's described as part of your original question, or we'll have no way to know that's the behaviour you want. \$\endgroup\$
    – DMGregory
    Commented Apr 23, 2019 at 11:16
  • \$\begingroup\$ Yeah trying to update script with OnCollisionStay , when i'm done i'm gonna edit your answer as the new script, it's easier than updating my question xd \$\endgroup\$ Commented Apr 23, 2019 at 11:20
  • \$\begingroup\$ You can also just post your modified code as your own answer. As long as you're giving credit to the users who helped you find that solution, it's totally OK to answer your own questions here. \$\endgroup\$
    – DMGregory
    Commented Apr 23, 2019 at 11:22
  • \$\begingroup\$ I just wanted to give you +1 reputation, isn't that system work like that? If your answer accepted by the person that post question you got +1 reputation? \$\endgroup\$ Commented Apr 23, 2019 at 11:25
0
\$\begingroup\$

How about using a simple boolean type to store when the player enters/exits in a cube area. My logic is simple... You have a 'colCounter' that increases each time the player collides with the cube. Then when the value is bigger/equal than '2' the cube falls. I used Physics to make the fall(which might be inefficient...). You can call the IEnumerator function @DMGregory instead.

I agree with @DMGregory on using collision check in a separate cube class. So all the cube should have that script and it would look for the player collision.

 public class CubeManager : MonoBehaviour
 {
   public Color[] colors;

   private bool playerEnter; // this helps to prevent continuous collision

   private int colCounter;

   private void OnCollisionEnter(Collision other)
   {
     if (playerEnter == false && other.transform.tag == "Player")
     {
        if (colCounter >= 2)
        {
            // code for falling. I Just used Physics.
            transform.GetComponent<Rigidbody>().isKinematic = false;
            return;
        }
        transform.GetComponent<Renderer>().material.color = colors[colCounter];
        colCounter++;
        playerEnter = true;

    }

  }

  private void OnCollisionExit(Collision other)
  {
    playerEnter = false;
  }
 }
\$\endgroup\$
1
  • \$\begingroup\$ I used void CubeFall(GameObject cube) { cube.transform.position = Vector3.Lerp(cube.transform.position, new Vector3(cube.transform.position.x, -10, cube.transform.position.z), tntFallTime); Destroy(cube, 3); } for falling, but doesn't work properly. Cube's position needs to change -10 on Y axis but it doesn't if i don't stay on it \$\endgroup\$ Commented Apr 23, 2019 at 10:39
0
\$\begingroup\$
public Material []materialSequence;
new public Renderer renderer;

float playerExitTime = float.NegativeInfinity;
int state = 0;

bool PlayerStays = false;

void Awake()
{
    renderer = gameObject.GetComponent<MeshRenderer>();
}

void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.CompareTag("Player"))
    {
        // Add a little tolerance, so rapid vibration at the edge of collision
        // doesn't advance the state. We need to leave for some time then return.
        if (Time.time - playerExitTime > 0.1f)
            AdvanceState();

    }
}

void OnCollisionStay(Collision collision)
{
    if (PlayerStays)
    {
        StartCoroutine(FallThenDestroy(5f, 9f));
        PlayerStays = false;
    }

    if (state == 1)
    {
        StartCoroutine(PlayerCheckStayStatus(1.5f));
    }
}

void OnCollisionExit(Collision collision)
{
    if (collision.gameObject.CompareTag("Player"))
    {
        playerExitTime = Time.time;
    }
}

void AdvanceState()
{
    // If we're already falling, ignore further state changes.
    if (state == materialSequence.Length)
        return;

    renderer.sharedMaterial = materialSequence[state];
    state++;

    if (state == materialSequence.Length)
        StartCoroutine(FallThenDestroy(10f, 3f));
}

// This lets us animate out the fall before the destruction takes place.
IEnumerator FallThenDestroy(float distance, float duration)
{
    PlayerStays = false;
    yield return new WaitForSeconds(0.5f);
    for (float t = 0; t < duration; t += Time.deltaTime)
    {
        // Fall some distance.
        transform.Translate(0, -distance * Time.deltaTime / duration, 0, Space.World);
        // Yield control to the engine to run for a frame, then resume here.
        yield return null;
    }

    // Destroy ourselves once the fall is over.
    Destroy(gameObject);
}

IEnumerator PlayerCheckStayStatus(float time)
{
    yield return new WaitForSeconds(time);
    PlayerStays = true;
    Debug.Log(PlayerStays);
}

Edited code like this, it works nice but i need to ask when cube falls, my character teleports to nearest cube around instead of falling with it. How can i fix it?

\$\endgroup\$
6
  • \$\begingroup\$ You probably don't want to start a new coroutine every frame in OnCollisionStay as long as state == 1. Either start your coroutine in Enter and stop it in Exit, or just increment a lingerTime variable in OnCollisionStay itself. As for the character teleporting, that sounds like a different issue entirely, and we'd need to see your character movement code to help you with it. \$\endgroup\$
    – DMGregory
    Commented Apr 23, 2019 at 12:39
  • \$\begingroup\$ Actually now my character doesn't effect from gravity, and i don't know how did i do that..... \$\endgroup\$ Commented Apr 23, 2019 at 16:40
  • \$\begingroup\$ That's a different question that you can ask about in a new question post. Be sure to include the code you're using to move your character. \$\endgroup\$
    – DMGregory
    Commented Apr 23, 2019 at 16:42
  • \$\begingroup\$ It's not about my script i'm %100 sure about it, 'cause i backup my project files everyday, and i changed my PlayerScript from yesterday's backup file so it needs to be somewhere else \$\endgroup\$ Commented Apr 23, 2019 at 16:46
  • \$\begingroup\$ Consider that if you were wholly correct about your work, you would not have an unsolved bug in the first place. There's something happening here that you don't understand yet. If you want help from others, you have to be willing to let them take a second look - even at parts you think probably aren't the problem. They can still serve as a useful signpost to where the real problem might lie. \$\endgroup\$
    – DMGregory
    Commented Apr 23, 2019 at 16:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .