- Home /
Turret With Raycast Camera
So I made a turret that has a sphere as a trigger and shoots at the player when he enters it, which works fine, except it also shoots at the player when hes behind walls, and I don't want that.
I thought about making a cone shaped trigger in front of the turret kind of like a view area but the turret would still shoot at the player behind a wall if the trigger was going through it, and I don't want to have to individually resize the trigger for each scenario.
And my final conclusion was to make a child camera of the turret that would raycast and shoot only if it hits an object with a tag "Player".
So I have a couple questions about that.
Is it a good way, or is it resource expensive?
Is there a better way?
How would I do it? Something like this like in the unity docs?
function Update () { var hit : RaycastHit; if (Physics.Raycast (transform.position, -Vector3(0,0,1), hit, 100.0)) { var distanceToGround = hit.distance; } }
And then how would I make it react only to an object with tag and execute a function in its parent?
Raycast is really confusing to me even tho I can visualize it I don't understand how the code works, none of the tuts on raycasting helped me, and I could never understand Unity docs. x'D
PS: Sorry for the code not being in code quotes its not working now for some reason, it does usually.
For an accurate answer, please post your current Turret ai$$anonymous$$g code.
Sorry, here. xD Its a code I used in a tower defense game and while it worked there its not good enough for this game.
#pragma strict
class Turret_Cannon extends Turret_Base
{
var myProjectile : GameObject;
var reloadTime : float = 1f;
var turnSpeed : float = 5f;
var firePauseTime : float = .25f;
var muzzleEffect : GameObject;
var myExplossion : GameObject;
var errorAmount : float = .001;
var myTarget : Transform;
var muzzlePositions : Transform[];
var turretBall : Transform;
private var nextFireTime : float;
private var next$$anonymous$$oveTime : float;
private var desiredRotation : Quaternion;
private var aimError : float;
function Start ()
{
}
function Update ()
{
if(myTarget)
{
if(Time.time >= next$$anonymous$$oveTime)
{
CalculateAimPosition(myTarget.position);
turretBall.rotation = Quaternion.Lerp(turretBall.rotation, desiredRotation, Time.deltaTime*turnSpeed);
}
if(Time.time >= nextFireTime)
{
FireProjectile();
}
}
}
/*function OnTriggerEnter(other : Collider)
{
if(other.gameObject.tag == "Enemy")
{
nextFireTime = Time.time+(reloadTime*.5);
myTarget = other.gameObject.transform;
}
}
*/
function OnTriggerStay(other : Collider)
{
if(!myTarget)//if I don't already have a target
{
if(other.gameObject.tag == "Player" || other.gameObject.tag == "ShipLoaded")
{
nextFireTime = Time.time+(reloadTime*.5);
myTarget = other.gameObject.transform;
}
}
}
function OnTriggerExit(other : Collider)
{
if(other.gameObject.transform == myTarget)
{
myTarget = null;
}
}
function CalculateAimPosition(targetPos : Vector3)
{
var aimPoint = Vector3(targetPos.x+aimError, targetPos.y+aimError, targetPos.z+aimError);
desiredRotation = Quaternion.LookRotation(aimPoint - turretBall.position);
}
function CalculateAimError()
{
aimError= Random.Range(-errorAmount, errorAmount);
}
function FireProjectile()
{
audio.Play();
nextFireTime = Time.time+reloadTime;
next$$anonymous$$oveTime = Time.time+firePauseTime;
CalculateAimError();
for(the$$anonymous$$uzzlePos in muzzlePositions)
{
Instantiate(myProjectile, the$$anonymous$$uzzlePos.position, the$$anonymous$$uzzlePos.rotation);
Instantiate(muzzleEffect, the$$anonymous$$uzzlePos.position, the$$anonymous$$uzzlePos.rotation);
}
}
}
function OnCollisionEnter(coll : Collision)
{
if (coll.gameObject.tag == "Bullet")
{
Instantiate(myExplossion, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
Answer by robertbu · Aug 27, 2013 at 06:17 PM
Having examined you code, I'm not sure what functionality you want. Do you want it to not track the player if the player cannot be "seen" or do you want it so not fire if the player cannot be seen? In either case, I'd recommend a Physics.LineCast():
function CanSeePlayer() : boolean {
var hit : RaycastHit;
if (Physics.Linecast(transform.position, myTarget.transform.position, hit)) {
if (hit.collider.tag == "Player")
return true;
// An alternate check that does not depend on the tag
if (hit.transform == myTarget)
return true;
}
return false;
}
Note this only check to make sure the pivot point of the turret can see the pivot point of the player. If the player is only partly visible, this may return false. A more complete check would linecast against the corners of the either the renderer.bounds or the mesh.bounds (translated into world space).
Yes I want it to not track or shoot at the player when he can not be "seen". Tracking is fine but shooting not.
Ok so do I attach that to the turret or the camera child of the turret? I don't understand how will the turret "see" without the camera. :S
Start by dropping the CanSeePlayer() method into the Turret_Cannon class above. Then insert as the first line in FireProjectile() method:
if (!CanSeePlayer()) return;
This may not be how you use it long term. Note Raycasting has nothing to do with cameras. You can construct a ray from a mouse position using a camera, but you can also just Raycast from some position in world space, or between two points using Linecast as I've done here.
Wow thank you it works great! :D I had no idea you can raycast without cameras. I thought raycasting is throwing rays from the camera to everything the camera sees. xD
You're the first one that made me understand raycasting code a bit better.
I don't get one thing tho, if you got a $$anonymous$$ to reply one more time. xD
The line
if (!CanSeePlayer()) return;
It means, if CanSeePlayer is not true right? Cause of the !. Why does it execute the fire code when it sees the player? Or does it mean, if CanSeePlayer not true return and do nothing, else execute the code in brackets?
CanSeePlayer() return true if the raycast hits the player. The '!' inverts the logic. So it means if you cannot see the the player, then return (i.e. don't fire). That prevents the turret from firing if it cannot see the player.
Actually from a "good program$$anonymous$$g" point of view, your way is better. I picked the line I suggested because it was simplest to describe and easiest to get right.