I have been programming for some time now (nearly a year) and im only now beginning to make my first full attempt at a full fps(movement, guns etc). I have been looking at some fps packages and youtube videos but still havent got a solid answer for raycasting. The question is where is the best place to put a raycast? is it from the camera to the centre of the screen(which i currently have)? or is it from the position of the end of the gun then forward? or is there away in which i can position it from the end of the gun and shoot towards the middle of the screen? for the first two options i have tryed the third i have not found away to do this. thanks in advance.
from what I understand, you are looking to use a raycasting method for your gun. you could use the main cameras position (`camera.main.gameObject.transform.position`), or use a `ScreenPointToRay` method. This can be found in the documentation for clicking and instantiating particles, but you just need to replace `Input.MousePosition.x` and `Input.MousePosition.y` with `Screen.width/2` and `Screen.height/2`. When I was doing an fps, I used the `camera.main.gameObject.transform.position` method, and my script is listed below. Feel free to use it, or refrence it for tips. Hope it helps!!! :)
BTW: The utility functions at the bottom are not necessary for the gun, but they were for other scripts that I wrote. Also, some of the code I got from the guns script in the bootcamp demo, simply because it was beyond me.
//Adds a component Menu for the script
//helps making it easy to find.
@script AddComponentMenu("FPS / Weapons / Gun")
//requires the audio source component
@script RequireComponent (AudioSource)
//the enumeration storing the FireType info
enum FireType
{
RayCast,
Projectile
}
//the enumeration storing the ShotType info
enum ShotType
{
Semi_Auto,
Full_Auto,
}
enum ry
{
left,
forward,
right,
back
}
//The number of clips the gun has
var Clips : int;
//The size of the clips
var clipSize : int;
//the boolean unlimited. If checked true, the gun will fire endless bullets
//good for power ups or testing
var unlimited : boolean = false;
//the boolean autoReload. if checked true, the gun will auto reload.
//using this and a small clip will make a burst type gun
var autoReload : boolean = true;
//the range of the gun. type "Infinity" if you want it to be infinite.
var gunRange : float;
//the fire rate of the gun
var fireRate : float;
// the projectile prefab. this will only affect the gun if the fireType is set to Projectile
var projectilePrefab : Rigidbody;
//the shot power. once again, this will only affect the gun if the fireType is set to Projectile
var projectileShotPower : float;
//the damage each shot deals
var Damage : int;
//the fire type variable. your choices are listed in the FireType enumeration above.
var fireType : FireType;
//the shot type variable. your choices are listed in the ShotType enumeration above.
var shotType : ShotType;
//the shot sound of the gun
var shotSound : AudioClip;
// the out of ammo sound of the gun
var OutOfAmmoSound : AudioClip;
//the reload sound of the gun
var reloadSound : AudioClip;
// the particle effects that the gun has. usually particles that look like bullets, or a muzzle flash
var ShotEmitter : ParticleEmitter[];
//the transform refrence to the tip of the gun
var tipOfGun : Transform;
// the transform refrence to the center of the sceen
var centerScreen : Transform;
//The following are the particles for different surfaces.
class Particles
{
//do we use the tag system?
var useTags : boolean = false;
//Wood
var WoodParticle : GameObject;
//Metal
var MetalParticle : GameObject;
//Concrete
var ConcreteParticle : GameObject;
//Dirt
var DirtParticle : GameObject;
//Snow
var SnowParticle : GameObject;
//Water
var WaterParticle : GameObject;
//enemies
var EnemyParticle : GameObject;
// untagged
var UntaggedParticle : GameObject;
}
//the refrence in the inspector to the above particles
var Particles : Particles = Particles;
//the array for using the non tag system.
var HParticles : GameObject[];
//the name of the gun
var gunName : String;
// the key pressed to access this gun. NOT THE KEY TO FIRE, but the key that when pressed and this gun is not the current gun, it activates this gun and deacivates all other guns in the gun manager
var keyToActivate : KeyCode;
//the bullet mark of the gun
var bulletMark : GameObject;
//Do we leave a bullet mark?
var leaveBM : boolean = false;
// the elapse for the reload
var reloadElapse : float;
//how much power this will have on rigidbodies
var pushPower : float;
//the shot light
var shotLight : GameObject;
//the muzzle Flash prefab
var muzzleFlash : GameObject;
//roate raycast is for the way the model was rotated
var rotateRaycast : ry;
//icon is for gun manager
var Icon : Texture2D;
//@HideInInspector is a line used to make a public var not appear in the inspector.
// the shots left before the clip is empty
@HideInInspector
var shotsLeft : int;
//Are we shooting?
//@HideInInspector
var shooting : boolean = false;
// the audio source
private var Audio : AudioSource;
//can we currently shoot?
private var freeToShoot : boolean = true;
//can we currently reload?
private var freeToReload : boolean = true;
//the clips left before the gun is useless.
private var clipsLeft : int;
//should we be shooting?
private var shouldShoot : boolean = true;
//are we reloading?
private var reloading : boolean = false;
//the last shot time
private var lastShotTime : float;
//rlInt will be used for reloading
private var rlInt : float;
//v3 is for rotate raycast
private var v3 : Vector3 = Vector3.zero;
//We call On Enable instead of Awake becuase this object(Gun) will be enabled multiple times throughout the game.
function OnEnable()
{
//a for loop executes a certain line of code for a specified number of times.
//Unless writing very specific code, use only for arrays.
for(var i = 0; i < ShotEmitter.length; i++)
{
//sets the visual effects to off.
ShotEmitter*.emit = false;*
*}*
*//gets an audio source*
*Audio = gameObject.GetComponent(AudioSource);*
*//sets the shots left*
*shotsLeft = clipSize;*
*//sets the clips left*
*clipsLeft = Clips;*
*//if there is a projectile set, then make this be a projectile launcher*
*if(projectilePrefab)*
*{*
*fireType = FireType.Projectile;*
*}*
*}*
*function Update ()*
*{*
*HandleInput();*
*HandleValues();*
*HandleReloading();*
*}*
*function HandleInput()*
*{*
*if(Input.GetButton("Fire1") && shotType == ShotType.Full_Auto && fireType == FireType.RayCast && Time.time > lastShotTime) //full auto, raycast*
*{*
*lastShotTime = Time.time + fireRate;*
*Shoot(false, false);*
*} else if(Input.GetButtonDown("Fire1") && shotType == ShotType.Semi_Auto && fireType == FireType.RayCast) //Semi Auto, RayCast*
*{*
*Shoot(true, false);*
*} else if(Input.GetButtonDown("Fire1") && fireType == FireType.Projectile) //Projectile*
*{*
*Shoot(false, true);*
*} else if(Input.GetButton("Fire1") && shotType == ShotType.Full_Auto && fireType == FireType.Projectile && Time.time > lastShotTime)*
*{*
*lastShotTime = Time.time + fireRate;*
*Shoot(true, true);*
*} else {*
*freeToShoot = true;*
*}*
*}*
*function Shoot(oneShot : boolean, isProjectile : boolean) //function shoot handles the shooting logic.*
*{*
*if(freeToShoot)*
*{*
*//we are shooting*
*shooting = true;*
*//gets vars for raycasting*
*var hit : RaycastHit;*
*var fwd = transform.TransformDirection(v3);*
*PlayShotSound();*
*if(!unlimited)*
*{*
*shotsLeft--;//subtract one bullet*
*}*
*if(!isProjectile)*
*{*
*GenerateShotGraphics();*
_Debug.DrawRay(centerScreen.transform.position, fwd*gunRange, Color.blue);_
*if(Physics.Raycast(centerScreen.transform.position, fwd, hit, gunRange)) //The following lines are for raycasting. you can skip this if you want.*
*{*
*GenerateHitGraphics(hit, hit);*
*ApplyForce(hit);*
*}*
*if(oneShot)*
*{*
*freeToShoot = false;//if we are semi auto, dont keep fireing*
*}*
*} else*
*{*
*//Instantiates the projectile.*
*var instantiatedProjectile : Rigidbody;*
*instantiatedProjectile = Instantiate(projectilePrefab, tipOfGun.transform.position, transform.rotation);*
_instantiatedProjectile.velocity = transform.TransformDirection(Vector3.forward * projectileShotPower);_
*if(shotType == ShotType.Semi_Auto)*
*{*
*freeToShoot = false;*
*}*
*}*
*}*
*//we are no longer shooting;*
*shooting = false;*
*}*
*function GenerateHitGraphics(hit : RaycastHit, BMhit : RaycastHit) //HERE Is where we create the graphics for the HIT. NOT the SHOT!*
*{*
*//vars for the particles.*
*var go : GameObject;*
*var delta : float = -0.02;*
*var hitUpDir : Vector3 = hit.normal;*
*//leaves a bullet hole*
*if(leaveBM)*
*{*
*if(BMhit.collider.tag == "Wood" || "Metal" || "Concrete")*
*{*
*if(!BMhit.collider.rigidbody && !BMhit.collider.isTrigger)*
*{*
*var bm = Instantiate(bulletMark, BMhit.point, Quaternion.FromToRotation(Vector3.forward, -BMhit.normal));*
*bm.AddComponent(BulletMark);*
*}*
*} else {*
*return;*
*}*
*}*
*//sends the apply damage message to the enemy that we hit*
*if(hit.collider.tag == "Enemy")*
*{*
*hit.collider.SendMessageUpwards("ApplyDamage", Damage, SendMessageOptions.DontRequireReceiver);*
*}*
*if(Particles.useTags)*
*{*
*//changes the type of particle.*
*switch(hit.collider.tag)*
*{*
*case "Wood":*
*go = Instantiate(Particles.WoodParticle, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*
*break;*
*case "Metal":*
*go = Instantiate(Particles.MetalParticle, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*
*break;*
*case "Snow":*
*go = Instantiate(Particles.SnowParticle, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*
*break;*
*case "Concrete":*
*go = Instantiate(Particles.ConcreteParticle, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*
*break;*
*case "Dirt":*
*go = Instantiate(Particles.DirtParticle, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*
*break;*
*case "water":*
*go = Instantiate(Particles.WaterParticle, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*
*break;*
*case "Enemy":*
*go = Instantiate(Particles.EnemyParticle, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*
*break;*
*case "Untagged":*
*go = Instantiate(Particles.UntaggedParticle, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*
*break;*
*}*
*Destroy(go, go.gameObject.GetComponent(ParticleEmitter).maxEnergy);*
*} else {*
*for(i = 0; i < HParticles.length; i++)*
*{*
_var Go : GameObject = Instantiate(HParticles*, hit.point, Quaternion.FromToRotation(Vector3.forward, hitUpDir)) as GameObject;*_
_*Destroy(Go, Go.gameObject.GetComponent(ParticleEmitter).maxEnergy);*_
_*}*_
_*}*_
_*}*_
_*//here is where the shot graphics are made.*_
_*function GenerateShotGraphics()*_
_*{*_
_*//Instantiates the muzzle flash*_
_*if(muzzleFlash != null)*_
_*{*_
_*var mf : GameObject = Instantiate(muzzleFlash, tipOfGun.transform.position, Quaternion.identity);*_
_*Destroy(mf, 0.1);*_
_*}*_
_*//emits once the shot visual effects*_
_*for(var i = 0; i < ShotEmitter.length; i++)*_
_*{*_
<em>_ShotEmitter*.Emit();*_</em>
<em>_*}*_</em>
<em>_*//creates a shot light*_</em>
<em>_*if(shotLight != null)*_</em>
<em>_*{*_</em>
<em>_*var go : GameObject = Instantiate(shotLight, tipOfGun.transform.position, Quaternion.identity);*_</em>
<em>_*Destroy(go, 0.1);*_</em>
<em>_*}*_</em>
<em>_*}*_</em>
<em>_*//applys force to all rigidbodies that are hit.*_</em>
<em>_*function ApplyForce(hit : RaycastHit)*_</em>
<em>_*{*_</em>
<em>_*var direction : Vector3 = hit.collider.transform.position - centerScreen.position;*_</em>
<em>_*var body : Rigidbody = hit.collider.rigidbody;*_</em>
<em>_*if(body)*_</em>
<em>_*if(!body.isKinematic)*_</em>
<em><em>_body.AddForceAtPosition(direction.normalized * pushPower, hit.point, ForceMode.Impulse);_</em></em>
<em>_*}*_</em>
<em>_*function HandleValues()*_</em>
<em>_*{*_</em>
<em>_*if(shotsLeft <= 0)*_</em>
<em>_*{*_</em>
<em>_*shotsLeft = 0;//if we don't have any more bullets, we can't shoot*_</em>
<em>_*freeToShoot = false;*_</em>
<em>_*}*_</em>
<em>_*switch(rotateRaycast)*_</em>
<em>_*{*_</em>
<em>_*case ry.left:*_</em>
<em>_*v3 = Vector3.left;*_</em>
<em>_*break;*_</em>
<em>_*case ry.forward:*_</em>
<em>_*v3 = Vector3.forward;*_</em>
<em>_*break;*_</em>
<em>_*case ry.right:*_</em>
<em>_*v3 = Vector3.right;*_</em>
<em>_*break;*_</em>
<em>_*case ry.back:*_</em>
<em>_*v3 = -Vector3.forward;*_</em>
<em>_*break;*_</em>
<em>_*}*_</em>
<em>_*}*_</em>
<em>_*function HandleReloading()*_</em>
<em>_*{*_</em>
<em>_*if(Input.GetButtonDown("Fire2") || Input.GetKeyDown(KeyCode.R))*_</em>
<em>_*{*_</em>
<em>_*Reload();// pressed the reload button, reload.*_</em>
<em>_*}*_</em>
<em>_*if(reloading)*_</em>
<em>_*{*_</em>
<em>_*freeToReload = false;*_</em>
<em>_*rlInt -= Time.deltaTime;*_</em>
<em>_*if(rlInt <= 0.0)*_</em>
<em>_*{*_</em>
<em>_*reloading = false;*_</em>
<em>_*shotsLeft = clipSize;*_</em>
<em>_*freeToReload = true;*_</em>
<em>_*}*_</em>
<em>_*}*_</em>
<em>_*if(reloading)*_</em>
<em>_*{*_</em>
<em>_*freeToShoot = false;*_</em>
<em>_*} else {*_</em>
<em>_*freeToShoot = true;*_</em>
<em>_*}*_</em>
<em>_*if(shotsLeft <= 0 && autoReload) //if we auto reload*_</em>
<em>_*{*_</em>
<em>_*Reload();// reload*_</em>
<em>_*freeToShoot = false;//we can't shoot while reloading*_</em>
<em>_*}*_</em>
<em>_*if(clipsLeft == 0)*_</em>
<em>_*{*_</em>
<em>_*freeToReload = false;//if we don't have any more clips, then we can't reload*_</em>
<em>_*}*_</em>
<em>_*if(reloading)*_</em>
<em>_*{*_</em>
<em>_*freeToShoot = false;*_</em>
<em>_*freeToReload = false;*_</em>
<em>_*} else {*_</em>
<em>_*freeToShoot = true;*_</em>
<em>_*freeToReload = true;*_</em>
<em>_*}*_</em>
<em>_*}*_</em>
<em>_*//the reload function.*_</em>
<em>_*function Reload()*_</em>
<em>_*{*_</em>
<em>_*if(freeToReload)*_</em>
<em>_*{*_</em>
<em>_*if(clipsLeft > 0 && shotsLeft < clipSize)*_</em>
<em>_*{*_</em>
<em>_*PlayReloadSound();*_</em>
<em>_*reloading = true;*_</em>
<em>_*rlInt = reloadElapse;*_</em>
<em>_*}*_</em>
<em>_*if(!unlimited)*_</em>
<em>_*{*_</em>
<em>_*clipsLeft--;*_</em>
<em>_*}*_</em>
<em>_*}*_</em>
<em>_*}*_</em>
<em>_*function PlayShotSound()*_</em>
<em>_*{*_</em>
<em>_*Audio.PlayOneShot(shotSound);*_</em>
<em>_*}*_</em>
<em>_*function PlayOutOfAmmoSound()*_</em>
<em>_*{*_</em>
<em>_*Audio.PlayOneShot(OutOfAmmoSound, 1);*_</em>
<em>_*}*_</em>
<em>_*function PlayReloadSound()*_</em>
<em>_*{*_</em>
<em>_*Audio.PlayOneShot(reloadSound);*_</em>
<em>_*}*_</em>
<em>_*function GetBulletsLeft()*_</em>
<em>_*{*_</em>
<em>_*return(shotsLeft);*_</em>
<em>_*}*_</em>
<em>_*function GetClipsLeft()*_</em>
<em>_*{*_</em>
<em>_*return(clipsLeft);*_</em>
<em>_*}*_</em>
<em>_*function GetName()*_</em>
<em>_*{*_</em>
<em>_*return(gunName);*_</em>
<em>_*}*_</em>
<em>_*function AddAmmo(amount : int)*_</em>
<em>_*{*_</em>
<em>_*clipsLeft += amount;*_</em>
<em>_*shotsLeft += amount;*_</em>
<em>_*}*_</em>
<em>_*function OnDrawGizmosSelected()*_</em>
<em>_*{*_</em>
<em>_*Gizmos.color = Color.red;*_</em>
<em>_*var fwd = transform.TransformDirection(Vector3.left);*_</em>
<em><em>_Gizmos.DrawRay(transform.position, fwd * gunRange);_</em></em>
<em>_*}*_</em>
<em>_*```*_</em>
If the center of the screen is you crosshairs you should do the cast from the center of screen in direction of the camera.