Instantiate w/ Mouse Click: Random(?) Z.Axis problem (2D)

Hey everyone,

Struggling with a bit of code here. I’m working primarily in the X and Y-axes. Since the game will be 2D, I’m ignoring the Z-axis (or at least trying to.) This is where I am at now.

A) Player clicks a spot at will and an object(Exploder) instantiates at that point.

B) Object comes in and throws out an AddExplosionForce - pushing away any surrounding game objects in the opposite direction.

C) Object then destroys itself.

The problem I’m having is that the Exploders are coming it at wildly varying Z-axes.

I’ve tried using RaycastHits, Input.mousePosition, and camera.ScreenPointToRay to ignore or at least manually set the Z-axis to 0 but haven’t had any luck.

Any suggestions?

Trigger Code

using UnityEngine;
using System.Collections;

public class Trigger : MonoBehaviour {

	
	public GameObject exploderPrefab;
		
	Vector3 mousePosition;
		
	void Start () 
	{
		
	}
	
	void Update () 
	{
		if(Input.GetMouseButtonDown(0))
		{
		// Construct a  ray from the current mouse coordinates
			mousePosition = Input.mousePosition;
						
			Ray ray = camera.ScreenPointToRay(new Vector3(mousePosition.x, mousePosition.y, 10));
			mousePosition.z = 10;
			RaycastHit hit;
						
			if(Physics.Raycast(ray, out hit))
			{
				
				//Create the explosion prefab
				Instantiate(exploderPrefab, hit.point, Quaternion.identity);
				Debug.Log(hit.point);
			}
		}
	}
}

Exploder Code

using UnityEngine;
using System.Collections;

public class Exploder : MonoBehaviour {

public float radius = 5.0f;
public float power = 500.0f;

public Vector3 explosionPos;


void Start () 
{
}

void Awake()
{
	AddExplosion();
	Debug.Log("Exploder enters.");
	//Destroy(this.gameObject);
	//Debug.Log("Exploder exits");
}

// Update is called once per frame
void Update () 
{
}

void AddExplosion()
	{
		Debug.Log("Detector on.");
		Collider[] objectsInRange = Physics.OverlapSphere(transform.position, radius);
		foreach (Collider hit in objectsInRange)
   			{	
     			if (!hit)
     			Debug.Log("Miss!");

     			if (hit.rigidbody)
     			hit.rigidbody.AddExplosionForce(power, transform.position, radius, 0);
     			Debug.Log("Hit " + hit.rigidbody);
   			}
	} 
}

Thanks for your time!

edit:

Changed the code of Trigger to match Mr. Reynold’s suggestion. Added screen shots describe further troubles.

I tried implementing the code suggested by Mr. Reynold’s and was met with mixed results. While my Exploder game object now instantiates at an almost 0-coordinate on the Z axis, it doesn’t instantiate at all along the Y axis. (See screen shot 1 and debug.log to see spawn coordinates.)

alt text

The exception is that if you click almost exactly on the last spawned instance of Exploder, it will kind of “stack” allowing you to gradually move up along the Y-axis. (Screen shot 2)

alt text

edit2: On further examination - the Exploder instantiates if you click directly on another game object. I have a game object w/ rigidbody (Petal) that floats down the screen and if you click directly on it the Exploder instantiates fine. I need to make it so it can instantiate in an empty space and then generate force (via AddExplosionForce or some other tool) on the petal object to make it move in a certain direction. Weird how that works…

edit 3:

After finding that I can instantiate my exploder prefab if I click on an actual object, I got the idea to use a cube game object as a sort of wall to be placed right behind my playing field (about z=1 for my 2D playing field.) I dropped the mesh to make it look like nothing is there. Now my clicks actually instantiate off the cube instead of empty air. The initial result is positive, but now I have to figure out to keep the mesh on my Petal game object from getting snagged on my wall. :stuck_out_tongue:

I’m still VERY open to suggestions / alternatives that don’t rely on this method. There has to be some way to make this work.

You can only instantiate the Exploder over an object because Physics.Raycast only returns a result when the ray hits a collider. Have you tried the Plane.Raycast method I suggested? It seems the best alternative, since you would not need the "wall object" - the plane would do this job, but without be drawn or interfere with physics. By the way, the Petal object should have a rigidbody to be affected by explosion forces (you can set Use Gravity to false to disable gravity effects).

No problem. The plane code is already in C#, so you'll not have problems if you need to test it - maybe some typical "JS-guy-trying-C#" errors. Your wall idea may work fine; one thing you could try is to make it a trigger; convert it to a collider (clear collider.isTrigger) right before doing the raycast, and convert it back to trigger (set isTrigger) after the raycast - this way the wall would only have effect when needed.

2 Answers

2

You could freeze movements in the Z axis in all objects. It can be done by hand at the Inspector (very boring!), or you can just add an instruction before AddExplosionForce:

...
if (hit.rigidbody){
    hit.rigidbody.constraints = RigidbodyConstraints.FreezePositionZ;       
    hit.rigidbody.AddExplosionForce(power, transform.position, radius, 0);
}
...

This can control the objects affected by the explosion, but if one of them hit other non freezed object, it may move in z. The best thing could be to find all rigidbodies at start and freeze Z in each one:

function Start(){
    var rBodies: Rigidbody[] = FindObjectsOfType(Rigidbody);
    for (var rbody in rBodies){
        rbody.constraints = RigidbodyConstraints.FreezePositionZ;
    }
}

I forgot the square brackets in the rBodies declaration, but now it's fixed (take a look at the answer above).

You can set the z-value directly:

// from your code:
if(Physics.Raycast(ray, out hit)) {
  Vector3 hp = hit.point; hp.z=10; // or hit.point.z=10 ?
  //Create the explosion prefab
  Instantiate(exploderPrefab, hp, Quaternion.identity);

This is solving the problem that when you raycast to a cube at z=0, hit.point is at z=-0.5.

mousePosition.z is how far from the camera you start the ray, so is only useful for skipping nearby objects. You’ll also want the locking on z (above A,) since the explosion can easily send things skittering a bit sideways.