Loads of Ray/linecasts, must be an easier way.

Hello

I am working on a game at the moment where i have to use a load of either raycasts or linecasts, I am going to be using them for collision detection, as the regular trigger and colliders arent sufficient as i cant get them to work as i want to.

The game itself is a 2D game where you drag some different blocks from a blockspawner and place them in the level.

I need the raycast/linecast to detect if the current block is going to be colliding with a another object when i place it, as i dont want the player to be able to place two blocks inside of eachother.

My current solution involves 4 linecasts, which works well enough, unless i try to break it.

the issue is, linecasts does not check with both directions.

if you have two cubes that are intersecting with eachother, and the origin of the linecast is inside the cube, while the endpoint of the linecast is outside, then it does not trigger.

So, my question is: Is it possible to make a linecast detect from both sides, by doing something smart, or will i have to hardcode it, resulting in 8 linecasts.

I have tried doing something with some loops, but it is currently outside my abilities.

Hope i can get either some answers, or some advice.

Thanks in advance.

  • Kacer

Edit: Solution:

I’m using 3 lists and 4 GameObjects for this fix, most of my objects will have a triangle or a rectangular form, so this works just fine.

The gameobjects are all placed at the corners of my object, and i cast a line between them, the line going both ways.

Two of the lists contain the 4 GameObjects, the third contain the results of my linecasts.

here’s some code:

public List<GameObject> rOrigin;
public List<GameObject> rTarget;
public List<Collider> rResults;

void Update () {

    RaycastHit hit;

	//Make the linecasts here, a total of 16 lines are being cast, and there's room for optimization,

	//as there are some of the linecasts that have a length of 0

	for(int origin = 0; origin < rOrigin.Count; origin++){

		for(int target = 0; target < rTarget.Count; target++){

			if(Physics.Linecast(rOrigin[origin].transform.position, rTarget[target].transform.position, out hit, 1)){
			}
				
		     //add the results here, null if the lines arent colliding with anything
			rResults.Add(hit.collider);
		}
	}

		//set a variable true, and change the color of the box if i am allowed to place the object
	if(!checkList(rResults)){
		clearance = true;
		gameObject.renderer.material.color = Color.white;
	}else{
		clearance = false;
		gameObject.renderer.material.color = Color.red;
	}
		
	//clear the results list, so i dont end up with thousands of results	
	rResults.Clear();
}

//returns false if all results from the linecasts are null
public bool checkList(List<Collider> list){
	for(int i = 0; i < list.Count; i++){
		if(list *!= null){*
  •   		return true;*
    
  •   	}*
    
  •   }*
    
  •   return false;*
    
  • }*
    placement and movement is being handled in another script.

As you point out, raycasts don’t detect objects when they start inside of them, making them not so good for detecting overlaps.

One standard solution is to keep a 2D (or 3D) array. if Block[y]=0, the spot is free. Place your block there and set Block[y]=1. If every block is 5 wide and starts at x=10, you use (position.x-10)/5 to map world x back to array x.

If the blocks are oddly shaped, or you hate arrays, a quick “cube overlap” test would be nice. Unity only has a sphereOverlap, which gives rough results. You might try placing the block, then if you get any collisions in the next frame, blast it away. Untested:

int plantDelay=2; // wait 2 frames, to be sure.

void FixedUpdate() { if(plantDelay>0) plantDelay--; } // could also be a coroutine

void OnCollisionEnter( ... ) {
  if(plantDelay>0) {
    Destroy(gameObject); // or do a cool fling away, first
  }
}

If this works, could be expanded (OnCollisionStay?) to give feedback as you position the block.