*Edit: Solved…
if (Physics.Raycast(thisTransform.position, heading, ref hit, speed))
should be if (Physics.Raycast(thisTransform.position, heading, out hit, speed))
Hello again. I have a ball bouncing around inside of some walls, over time the ball speeds up so I have decided to use ray casting to check for collisions; since currently after a specific speed the ball moves so fast it goes through the wall when using the rigid body collide. However I have run into a problem with the code. I looked at the Unity Script Reference on Physics.Raycast and came up with the following
using UnityEngine;
using System.Collections;
public class Ball : MonoBehaviour
{
// speed, location, heading, raycast
private Transform thisTransform;
private Vector3 heading;
public float speed;
public float speedMax;
public float speedMin;
RaycastHit hit;
// attached prefabs
public GameObject BallBrickExplosionPrefab;
public GameObject ballPrefab;
public bool bottomKill; // toggle death on bottom hit on and off
void Start()
{
// init thisTransform to the objects transform
thisTransform = transform;
// set the balls position to the starting position
//thisTransform.position = startingPosition;
// set the normalized vector to (1,0,0)
heading = Vector3.up;
// set up the velocity
rigidbody.velocity = heading * speed;
}
void Update()
{
// enforce the speed cap and lock z to zero
Vector3 velocityNormal = rigidbody.velocity.normalized;
velocityNormal.z = 0;
rigidbody.velocity = velocityNormal*speed;
// project a ray out from the heading foward the speed
if (Physics.Raycast(thisTransform.position, heading, ref hit, speed))
Debug.Log(hit.collider.tag.ToString() + " is infront of the ball");
}
Unity is informing me that The best overloaded method match for
UnityEngine.Physics.Raycast(UnityEngine.Vector3, UnityEngine.Vector3, out UnityEngine.RaycastHit, float)’ has some invalid arguments
What I do not understand is thisTransform.position is a Vector3, heading is a Vector3, raycastHit, is a raycastHit, and speed is a float… so why is unity so mad?
Can you post the solution to your code just in case anyone else comes along with the same issue.
While I was looking at your code(and really only reason I’m commenting
) though I see your using “ref hit”, just wondering for my own curiosity is there a reason you went that route?
It’s probably hardly a noticeable difference but using out is a bit faster to compute.
I will post the solution once the speed issue is resolved. As far as ref hit im not sure, I do not know how to actually use the ray cast, but ref hit is the object returned by the ray cast, I was hoping there was some way to access the collision from that returned object. As of now I am not using it for anything other then drawing the ray in debug.
I would use something like →
RaycastHit hit = new RaycastHit();
if(Physics.Raycast(transform.position, -Vector3.up,out hit, 100))
float distanceToGround = hit.distance;
Take out the declaration from the top out. That just makes the computer have to do a few extra steps rather then just letting the method do it. When you get inside that if statement you are essentially accessing the collision otherwise you would not be in it. You would need some extra code probably something like →
RaycastHit hit = new RaycastHit();
if(Physics.Raycast(transform.position, -Vector3.up,out hit, 100)){
if(hit.collider.tag == "myBall"){
// Now that you are here do whatever you need.
}
}
Does that help with anything?
Yes weylin, that does make a lot of since, but I am still stuck on a few points.
RaycastHit hit = new RaycastHit();
if(Physics.Raycast(thisTransform.position, heading, out hit, speed))
{
if(hit.collider.tag == "myBall")
{
// Now that you are here do whatever you need.
}
}
With the above code doesn’t the raycast trigger a collision within 100 units. I will admit that I do not fully understand a raycast, but I set up the raycast in my game to project the ray at the heading as far out as the speed of the object. This would trigger a collision too soon wouldn’t it? For testing I have the ray that is being projected by my ball proceeding it and I noticed that it to triggers many updates before the actual collision should happen. Also is there a way to pass the two objects that are colliding into the unity physics engine and let it figure out the new trajectories?
Couple questions…
-
Does your ball get to a point where it moves so fast it is going through walls? If not, you don’t need raycasting.
-
If you want to stick with raycasting anyway, does your ball ever change direction after the heading is set? Or will it continue in a straight line until it impacts something?
These 2 questions will help solve your issues.
If you go with raycasting, and the ball continues in a direct line until it impacts something, then do not give your raycast a distance check (remove ‘speed’ from your posted code above in the raycast check). This way, the ray will be cast until it makes impact.
Impact via raycast does not actually //do// anything. unless you tell it to. So, in the above example of your code, you could write a function to determine when to use your impact function based on the distance between your ball and the object.
Now, I assume your ball is what is casting rays, right? If so, the above example of “hit.collider.tag == myBall” will not work. (given, it was only an example).
You would instead do something like:
RaycastHit hit = new RaycastHit();
if(Physics.Raycast(thisTransform.position, heading, out hit))
{
//either determine a distance that you want to act at using if (hit.distance <= #)
//or calc your speed*heading*Time.deltaTime, and figure out how long it's going to take the ball to get there, and set up a coroutine or etc to launch the *impact* function you have at that time.
}
I’ll try and clarify later if I can. On break from work atm, so, gtg!
-Rob
Ezzerland, thank you for your response!
- The ball does get moving so fast that eventually it hops over the walls and the bricks, which is why I started down the raycasting trail.
- The ball will stay going in a straight line until it either hits something, or something else hits it; like another ball.
I did change my function to this…
// project a ray out from the heading foward the speed
if (Physics.Raycast(thisTransform.position, heading, out hit))
{
Debug.DrawRay(thisTransform.position, heading * hit.distance, Color.yellow);
Debug.Log(hit.collider.tag.ToString() + " is " + hit.distance.ToString() + "infront of the ball");
if (hit.distance <= 0)
{
Debug.Log(" Ball Hit: " + hit.collider.gameObject.tag.ToString());
// something to trigger a rigid body collision
// ?? how to trigger collision
}
}
}
Is there a way to use the unity physics engine to calculate the collision? Once there is a collision triggered by the raycast check can I pass this object, and the hit.gameObject to the same functions that unity use to collide two objects?
With the above code snippet, keep in mind that a ray will never hit something in-front of you at a distance of less than 0.
replace:
// ?? how to trigger collision
with whatever you would do if you collided, because when that if statement executes that line of code, you have collided. So ‘hit’ is what you’ve collided with. So compare it’s collider with the different things you could of hit “otherBall” or “wall” or whatever you have things tagged as, and continue on with your collision code as normal (same way you did with your past collision checks prior to raycasting).
Sorry if it seems like I am dense, but I don’t have collision code, I have been letting unity handle the collisions until now. That is why I was asking about using unity’s built in collision processes.
Maybe let us know what exactly you are trying to do. Once your inside th if statement the ray has collided with something. Once you determine you have collided with the intended object you will put whatever code you need to accomplish whatever your trying to do.
Sure thing, this is exactly what I am trying to do. I have a ball, over time it can replicate creating new balls. Those balls balls bounce around the screen hitting various objects such as bricks, walls, and a paddle, exactly like breakout. Right now if I increase the speed of a ball over 100 there is a small chance it will either move though the objects, or develop z plane movements. I’m not sure how it is possible since I set its z to zero every update, but that is another problem entirely. Since the objects quickly start moving faster then the unity can calculate I decided to start using raycasting, however since I never actually calculate any collision reactions I am not sure how to proceed. I have attached my ball class so you can see what I am working on. Now I am new to unity, and such so if there is a “right” way or a better way to attempt what I am trying to do I will be happy to take that approach.
using UnityEngine;
using System.Collections;
public class Ball : MonoBehaviour
{
// !! Disabled due to the replication system !! where to go when restarting
// public Vector3 startingPosition;
// speed, location, heading, raycast
private Transform thisTransform;
private Vector3 heading;
public float speed;
public float speedMax;
public float speedMin;
RaycastHit hit;
// attached prefabs
public GameObject BallBrickExplosionPrefab;
public GameObject ballPrefab;
public GameObject ballTrail;
// ball replication system
public int replicateNeeded; // number of brick hits needed to replicate the ball
private int replicateCount = 0; // internal tracker
public bool bottomKill; // toggle death on bottom hit on and off
void Start()
{
// init thisTransform to the objects transform
thisTransform = transform;
// set the balls position to the starting position
//thisTransform.position = startingPosition;
// set the normalized vector to (1,0,0)
heading = Vector3.up;
// set up the velocity
rigidbody.velocity = heading * speed;
}
// called every fixed frame rate update.
void FixedUpdate()
{
// enforce the speed cap and lock z to zero
heading = rigidbody.velocity.normalized;
heading.z = 0;
rigidbody.velocity = heading * speed;
// draw particle trail
Instantiate(ballTrail, thisTransform.position, Quaternion.identity);
// project a ray out from the heading foward the speed
if (Physics.Raycast(thisTransform.position, heading, out hit))
{
Debug.DrawRay(thisTransform.position, heading * hit.distance, Color.yellow);
Debug.Log(hit.collider.tag.ToString() + " is " + hit.distance.ToString() + "infront of the ball");
if (hit.distance <= 0)
{
Debug.Log(" Ball Hit: " + hit.collider.gameObject.tag.ToString());
// something to trigger a rigid body collision
}
}
}
//public void Reset()
//{
// // set the location to the starting location
// thisTransform.position = spawnPoint;
//}
void OnTriggerEnter(Collider otherObject)
{
Debug.Log("otherObject tag = " + otherObject.tag.ToString());
//check if the otherObject is the paddle
if (otherObject.tag == "paddle")
{
Debug.Log("collision with paddle");
// determine the distance from impact to the center of the paddle
float ballDist = thisTransform.position.x - otherObject.transform.position.x;
Debug.Log("ballDist = " + ballDist.ToString());
// convert the distance to a percentage based off te size of the paddle
float percentDist = (ballDist / otherObject.transform.localScale.x);
Debug.Log("other objects local scale = " + otherObject.transform.localScale.x);
Debug.Log("percentDist = " + percentDist.ToString());
// calculate the new heading
heading.x = ballDist / otherObject.transform.localScale.x;
heading.y = 1 - Mathf.Abs(heading.x);
// set the new velocity
Vector3 newVelocity = heading * speed;
newVelocity.z = 0;
Debug.Log("new x = " + newVelocity.x.ToString() + "new y = " + newVelocity.y.ToString() + "new z = " + newVelocity.z.ToString());
// apply velocity
rigidbody.velocity = newVelocity;
}
if (otherObject.tag == "horizontal")
{
rigidbody.velocity = new Vector3(thisTransform.position.x * -1, thisTransform.position.y, 0);
}
}
void OnCollisionEnter(Collision otherObject)
{
// if the otherObject is a brick
#region Brick Collisions
if (otherObject.gameObject.tag == "brick")
{
Debug.Log("collision with brick");
{
// speed up the ball if it is slower then the max speed
if (speed >= speedMax)
speed = speedMax;
if (speed < speedMax)
speed += 4;
}
// create the explosion
Instantiate(BallBrickExplosionPrefab, otherObject.gameObject.rigidbody.position, Quaternion.identity);
// play collision sound
if (audio !audio.isPlaying)
audio.Play();
// remove the brick
otherObject.gameObject.active = false;
// incrament the replication counter
if (replicateCount > replicateNeeded)
{
replicateCount = 0;
Instantiate(ballPrefab, thisTransform.position, Quaternion.identity);
}
else
{
replicateCount++;
}
}
#endregion
#region Bottom Wall Collision
// if the otherObject is the bottom wall
if (otherObject.gameObject.tag == "bottom")
{
Debug.Log("Collision with bottom");
if(bottomKill)
Destroy(this.gameObject);
}
#endregion
}
}
Does that help explain at all?
The answer is in your code itself mate.
// project a ray out from the heading foward the speed
if (Physics.Raycast(thisTransform.position, heading, out hit))
{
Debug.DrawRay(thisTransform.position, heading * hit.distance, Color.yellow);
Debug.Log(hit.collider.tag.ToString() + " is " + hit.distance.ToString() + "infront of the ball");
if (hit.distance <= 0)
{
Debug.Log(" Ball Hit: " + hit.collider.gameObject.tag.ToString());
// something to trigger a rigid body collision
}
}
}
in your Debug.Log you have “Ball Hit…”
When that if statement executes, your ball has hit the target. That is your collision. So, take the code that is in your collision check and migrate it to the raycast check. Comment the collision code out in the meantime, and play around with it.
First, thank you both for your responses, but I still feel like we are dancing around the question, let me try asking it a different way. Lets say I have two sphere objects with an attached rigid body enclosed in a box. At the start of execution I set both the balls velocity, and I have code for nothing else. Unity will handle the elastic collision for the objects when their rigid bodies overlap with no additional code on my part.
Now lets say those balls started to move so fast that they started to go through each other. If I understand everything correctly this is where raycasting comes in. So I enter the raycasting code to return a hit (or more specifically the distance until a collision). The raycast presents me with the information of when a collision will take place, but does not address the results of that collision. In all of the examples so far we have been using raycasting to learn when a collision will take place, but I need to know how to process the collision. So is there a way to still have the two spherical objects process an elastic collision though, or do I have to code in the collision myself?
If the later is true is there any since in attaching a rigid body to the sphere’s any longer?
if (hit.distance <= 0)
{
Debug.Log(" Ball Hit: " + hit.collider.gameObject.tag.ToString());
// something to trigger a rigid body collision
[B]//This is your actual collision[/B]
}
Edited the above to try and make it clearer. When the distance between the ray is 0, that means you’ve collided. That means everything inside of your collision check can be moved/replicated here. You might want to make that like <= 0.5 just as a safety type thing, but, see how it works. and give it some testing first.
If you intend to keep your collision checks in place, and only use raycasting when the ball is beyond a certain speed, I suggest you let your code know that as well. Using both continuously would be rather costly.
As promised once I figured out the speed thing, I would post my source.
Thank you everyone.
So here it is, but a few things to keep in mind first.
- Some times the ball breaks out for no reason, must restart game,
- Over time the bricks level, at level zero they are gray,
at level two they are red, but when hit turn black.
Over each level they gain requires one more “hit” with the ball
- There is a ball replication system in place its turned off at the moment
because its really kills the frame rate of the game.
- You have unlimited lives, but the game never ends… not sure who wins here.
The ball is the workhorse, check out that script for the raycasting stuff.
This is NOT the best way to do an arkanoid clone, but its working for me so far.
Feed back always welcome.
http://www.filedropper.com/arkanoid