assigning a property from an object in a list to a variable

Started by
71 comments, last by ethancodes 5 years, 11 months ago
5 hours ago, ethancodes said:

This is a problem because DestroyAdjacent is called from the DestroyBrick() in the Explosive Brick class. DestroyAdjacent calls FindObjectAt, thus we have FindObjectAt() -> DestroyBrick() -> DestroyAdjacent() -> FindObjectAt() -> DestroyBrick() -> and so on and so on. 

This was the problem, you made a loop. Code fixed:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ExplosiveBrick : Brick {

	private GameObject boardManager;
	private Vector3 currentPosition;

	public override void Update ()
	{
		timer += Time.deltaTime;
		//timer determines when the brick will move
		if (timer >= delay) 
		{
			transform.Translate(0.0f, -1.0f,0.0f);
			timer = 0;
			currentPosition = this.gameObject.transform.position;
		}
	}


	public override void DestroyBrick ()
	{
		if (timesHit >= maxHits) {
			breakableCount--;
			PuffSmoke ();
			DestroyAdjacent ();
			levelManager.BrickDestroyed ();
			Destroy (gameObject);
		} else {
			LoadSprites ();
		}
	}
		

	//Lets make it so this destroys a brick
	public void DestroyObjectAt (float InX, float InY)
	{
		RaycastHit2D hit = Physics2D.Raycast (new Vector3 (InX, InY, -0.02f), Vector3.forward, 0.02f);
		if (hit.collider != null) {
			//Checking that it isn't a explosive brick is a easy fix for now.
			//Accurately aiming your ray will be better. Remember that the ray hits in unity space
			if (hit.collider.tag == "Breakable" && !(hit.collider.GetComponent<Brick>() is ExplosiveBrick)) {
				//This will now call destroy on a brick IF it is hit.
				hit.collider.GetComponent<Brick> ().DestroyBrick ();
			}
		}

	}

	//This will destroy all the bricks now
	public void DestroyAdjacent ()
	{
		//The rays actually hit this object also so lets expand a bit
		//check right
		DestroyObjectAt(currentPosition.x + 1f, currentPosition.y);
		//check above
		DestroyObjectAt(currentPosition.x, currentPosition.y +1f);
		//check left
		DestroyObjectAt(currentPosition.x - 1f, currentPosition.y);
		//check below
		DestroyObjectAt(currentPosition.x, currentPosition.y -1f);
		//Check up and right
		DestroyObjectAt(currentPosition.x + 1f, currentPosition.y + 1f);
		//check down and right
		DestroyObjectAt(currentPosition.x + 1f, currentPosition.y - 1f);
		//check up and left
		DestroyObjectAt(currentPosition.x - 1, currentPosition.y + 1f);
		//check down and left
		DestroyObjectAt(currentPosition.x - 1, currentPosition.y - 1);
	}

}

In short I turn the "FindObject" into "DestroyObject" so that the "DestroyAdjacent" destroys each in turn.

I also check that it doesn't use DestroyBrick again on the explosion object.

 

Also your rays aren't aimed well you just use +1. This means the ray also hits the explosion block because. Remember that you now use actual Position as in the point where the object is in the world.

Because your sprite isn't centered, it starts from the corner, +1 to the right means you miss and -1 to the left means you almost miss the object to the left:

MissAimed.jpg.c783c3a765bbd333dfc5f899bed2b711.jpg

So you keep missing all the blocks except for the explosive block itself. To fix this either adjust the values of fix the pivot point.

Advertisement
On 5/5/2018 at 3:37 AM, Scouting Ninja said:

Also your rays aren't aimed well you just use +1. This means the ray also hits the explosion block because. Remember that you now use actual Position as in the point where the object is in the world.

Because your sprite isn't centered, it starts from the corner, +1 to the right means you miss and -1 to the left means you almost miss the object to the left:

MissAimed.jpg.c783c3a765bbd333dfc5f899bed2b711.jpg

So you keep missing all the blocks except for the explosive block itself. To fix this either adjust the values of fix the pivot point.

I hadn't considered this issue. I did what I thought should fix it, but I'm still not able to destroy the adjacent bricks, only the explosive brick. here is what I thought should have fixed the aiming of the raycast:


public void DestroyAdjacent ()
	{
		//check right
		DestroyObjectAt(currentPosition.x + 1.5f, currentPosition.y + 0.5f);
		//check above
		DestroyObjectAt(currentPosition.x + 0.5f, currentPosition.y + 1.5f);
		//check left
		DestroyObjectAt(currentPosition.x - 0.5f, currentPosition.y + 0.5f);
		//check below
		DestroyObjectAt(currentPosition.x + 0.5f, currentPosition.y - 0.5f);
		//Check up and right
		DestroyObjectAt(currentPosition.x + 1.5f, currentPosition.y + 1.5f);
		//check down and right
		DestroyObjectAt(currentPosition.x + 1.5f, currentPosition.y - 0.5f);
		//check up and left
		DestroyObjectAt(currentPosition.x - 0.5f, currentPosition.y + 1.5f);
		//check down and left
		DestroyObjectAt(currentPosition.x - 0.5f, currentPosition.y - 0.5f);
	}

 

Someone had recommended using the OverlapCircleAll method for this. It seems much simpler, but I am still having issues. Here is the code:


public void DestroyAdjacent ()
	{
		Vector3 explosiveBrickOrigin = this.transform.position;

		var hitObjects = Physics2D.OverlapCircleAll (explosiveBrickOrigin, 1);

		foreach (var item in hitObjects) 
		{
			if (item.gameObject.tag == "Breakable") 
			{
				item.gameObject.GetComponent<Brick>().DestroyBrick();
			}
		}
	}

I am getting a stack overflow exception when I hit the explosive brick. The exception is leading me to the PuffSmoke() method. Here is the code for that:


protected void PuffSmoke ()
	{
		var smokePuff = Instantiate(smoke, transform.position, Quaternion.identity);
			var effect = smokePuff.GetComponent<ParticleSystem>().main;

			effect.startColor = GetComponent<SpriteRenderer>().color; 
	}

Just a pretty straight forward particle system for some smoke when a brick gets destroyed. If I comment everything out inside the PuffSmoke method, and then run it, I get a different stack overflow exception. I'm not sure what's happening here. Is it possibly an issue with multiple bricks getting destroyed so quickly that the PuffSmoke method needs to be asynchronous? I'm really at a loss here.

Just a guess off the top of my head, but you've probably got a circular collision going on.  Like, you are probably checking for collision against the very brick that is exploding, which causes a chain reaction of: Hit a brick-->do explosion --> oh we hit a brick --> lets explode -->oh we hit a break -->lets explode ..etc.  The easy way to do this, is to instantiate the explosion and destroy the brick, then have the explosion have the script that does the overlap call in its update, which gets called on the frame after the brick is destroyed.  (It also has a nice separation of concerns, bricks only do brick things, explosions do explosions.)

 

What @ferrous said is correct. Your collision checks the space and finds the explosion block in it, calling for the explosion again and the new explosion finds the explosion brick again; making a loop.


public void DestroyAdjacent ()
	{
		Vector3 explosiveBrickOrigin = this.transform.position;

		var hitObjects = Physics2D.OverlapCircleAll (explosiveBrickOrigin, 1);

		foreach (var item in hitObjects) 
		{
			if (item.gameObject.tag == "Breakable" && !(hit.collider.GetComponent<Brick>() == this)) 
			{
				item.gameObject.GetComponent<Brick>().DestroyBrick();
			}
		}
	}

The way this code reads now:

if (item.gameObject.tag == "Breakable" // if it is breakable// && // And// ! //it is not// (hit.collider.GetComponent<Brick>() == this) //this block running the code.

If it is breakable And Isn't this block : Do something with it.

 

The reason your code has to work like this is to prevent loops where a object keeps trying to call destroy on it self over and over when the sphere collides with it.

Ah I see. I'll try this tonight. I did consider this issue, but I thought I had fixed it because I went into 2d Physics settings and unchecked the box for queries start in collider. My understanding was that by unchecking that, it would only start to check outside of the collider, and thus not register the object casting the ray. Maybe I misunderstood this though. 

So  I tried this, and I'm still getting a stack over flow error. However, I ran it several times and it did seem to work a few times. I need to spend some time with it to see if I can find the differences between when it is working and when it isn't so I can narrow down the cause of the problem. 

Two things that tend to help a lot when trying to find the source of errors:

1) Debug.Log(), for example, if you printed out who was colliding with what, you might see what was causing the overflow.

2) Set some breakpoints, and attach a debugger.

The latter, especially, is a very important skill to develop.

I know about using Debug.Log(), but I'm not familiar with attaching a debugger. I've always just used breakpoints to walk through the code. I will have to look into this for more info. Thanks!

 

Edit: I just looked this up. I have been doing this all along. lol. I just wasn't familiar with the terminology of attaching a debugger. 

So it seems like I'm getting the stack overflow exception when I have an explosive brick getting destroyed by another explosive brick. This makes sense, since we had previously talked about needing to set up the function to run asynchronously. But I'm not sure how to do that. I've used asynchronous in other programming, but it was very different than this. I'm sure I can look up how to do it, but I'm not really sure where to do it. Do I put it on the DestroyBrick function? Or the DestroyAdjacent function? I want to make it so that the explosive bricks will chain. I don't want the second explosive brick to be destroyed without destroying the bricks touching it as well.

This topic is closed to new replies.

Advertisement