Search Unity

raycasting and bullet holes help Javascript

Discussion in 'Scripting' started by AtomicCabbage33, Aug 31, 2015.

  1. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    The player can still jump even though he is already in the air, cant think why this is

    source code:

    var walkAceleration: float = 5.0f;
    var cameraObject : GameObject;
    var rb : Rigidbody;
    @HideInInspector
    var horizontalMovement : Vector2;
    var jumpVelocity : float = 20;
    @HideInInspector
    var grounded : boolean = false;
    var maxSlope : float = 60;


    function Start()
    {
    rb = GetComponent.<Rigidbody>();
    }
    function Update ()
    {

    GetComponent.<Rigidbody>().velocity.z = Mathf.Clamp(GetComponent.<Rigidbody>().velocity.z, -20, 20);
    GetComponent.<Rigidbody>().velocity.x = Mathf.Clamp(GetComponent.<Rigidbody>().velocity.x, -20, 20); //Change the -10 and the 10 to alter movement speed


    transform.rotation = Quaternion.Euler(0, cameraObject.GetComponent(MouseLookScript).currentYRotation, 0);
    rb.AddRelativeForce(Input.GetAxis("Horizontal")* walkAceleration, 0, Input.GetAxis("Vertical")* walkAceleration);

    if (Input.GetButtonDown("Jump"))
    GetComponent.<Rigidbody>().AddForce(0,jumpVelocity,0);
    }

    function OnCollisionStay (collision : Collision)
    {
    for (var contact : ContactPoint in collision.contacts)
    {
    if (Vector3.Angle(contact.normal, Vector3.up) < maxSlope)
    grounded = true;

    }
    }
    function OnCollisionExit()
    {
    grounded = false;
    }
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    You need to track if they've landed on what you consider the ground. If they haven't, don't allow jumping.

    I break these things into their own components for my movement 'styles' (I have a movementmotor that is a state machine for the various movement styles that an entity can have). I call them 'resolvers'.

    I have resolvers like:
    GravityResolver
    GroundingResolver
    SurfaceResolver (like grounding, but treats walls and ceilings as ground as well... for wall walking and climbing)
    JumpResolver

    example:
    GroundingResolver
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4.  
    5. using com.spacepuppy;
    6. using com.spacepuppy.Movement;
    7. using com.spacepuppy.Utils;
    8.  
    9. namespace com.apoc.Movement
    10. {
    11.  
    12.   [AddComponentMenu("Apoc/Movement/Resolver: Grounding")]
    13.   [RequireComponent(typeof(ApocMovementMotor))]
    14.   public class GroundingResolver : SPNotifyingComponent, IGroundingResolver
    15.   {
    16.  
    17.   public enum GroundingState
    18.   {
    19.   Unknown = -2,
    20.   Hanging = -1,
    21.   Grounded = 0,
    22.   Jumping = 1,
    23.   Descending = 2,
    24.   Falling = 3
    25.   }
    26.  
    27.   #region Fields
    28.  
    29.   [Tooltip("Distance to project below the player to check ground. Should be greater than or equal to the skin width of the attached CharacterController.")]
    30.   public float GroundingSkinWidth = 0.05f;
    31.  
    32.   public float TerminalFallDistance = 15.0f;
    33.  
    34.   [Tooltip("Duration of time considered just jumped. This way if we're near the ground, we don't signal as grounded if we're initiating a jump.")]
    35.   public float JustJumpedCooldown = 0.1f;
    36.  
    37.   [Tooltip("The ground normal is calculated using a CapsuleCast which improperly calculates the surface normal. Set this true to repair the surface normal, only if necessary, as it's a lot more extra work.")]
    38.   public bool RepairSurfaceNormal = false;
    39.  
    40.   private ApocMovementMotor _motor;
    41.  
    42.   private Vector2 _groundNormal;
    43.   private GroundingState _currentState;
    44.   private Vector2 _lastGroundedPos;
    45.   private float _lastGroundedTime;
    46.   private float _lastJumpedTime;
    47.  
    48.   #endregion
    49.  
    50.   #region CONSTRUCTOR
    51.  
    52.   protected override void Awake()
    53.   {
    54.   base.Awake();
    55.  
    56.   _motor = this.GetComponent<ApocMovementMotor>();
    57.   }
    58.  
    59.   protected override void OnStartOrEnable()
    60.   {
    61.   base.OnStartOrEnable();
    62.  
    63.   _motor.BeforeUpdateMovement -= this.OnBeforeUpdateMovement;
    64.   _motor.BeforeUpdateMovement += this.OnBeforeUpdateMovement;
    65.   }
    66.  
    67.   protected override void OnDisable()
    68.   {
    69.   base.OnDisable();
    70.  
    71.   _motor.BeforeUpdateMovement -= this.OnBeforeUpdateMovement;
    72.   }
    73.  
    74.   #endregion
    75.  
    76.   #region IGroundingResolver Interface
    77.  
    78.   /// <summary>
    79.   /// Returns true if the last ground test trace hit something
    80.   /// </summary>
    81.   public bool IsGrounded
    82.   {
    83.   get { return _groundNormal != Vector2.zero; }
    84.   }
    85.  
    86.   public Vector2 GroundNormal
    87.   {
    88.   get { return _groundNormal; }
    89.   }
    90.  
    91.   public Vector2 LastGroundedPosition { get { return _lastGroundedPos; } }
    92.  
    93.   /// <summary>
    94.   /// The time at which we last calculated being on the ground.
    95.   /// </summary>
    96.   public float LastGroundedTime { get { return _lastGroundedTime; } }
    97.  
    98.   public Vector2 DesiredJumpNormal { get { return Vector2.up; } }
    99.  
    100.   public float LastJumpedTime { get { return _lastJumpedTime; } }
    101.  
    102.   public void SetJumping()
    103.   {
    104.   _currentState = GroundingState.Jumping;
    105.   _lastGroundedPos = _motor.SurfaceConstraint.ProjectPosition2D(this.entityRoot.transform.position);
    106.   _lastJumpedTime = Time.time;
    107.   }
    108.  
    109.   #endregion
    110.  
    111.   #region Properties
    112.  
    113.   public GroundingState CurrentState { get { return _currentState; } }
    114.  
    115.   /// <summary>
    116.   /// Returns true if the time since the last time jumped is less than JustJumpedCooldown.
    117.   /// </summary>
    118.   public bool JustJumped
    119.   {
    120.   get { return Time.time - _lastJumpedTime < this.JustJumpedCooldown; }
    121.   }
    122.  
    123.   #endregion
    124.  
    125.   #region Methods
    126.  
    127.   public void SetGrounded(Vector2 groundNormal)
    128.   {
    129.   _groundNormal = groundNormal;
    130.  
    131.   _currentState = GroundingState.Grounded;
    132.   var oldPos = _lastGroundedPos;
    133.   _lastGroundedPos = _motor.SurfaceConstraint.ProjectPosition2D(this.entityRoot.transform.position);
    134.  
    135.   Notification.PostNotification<LandedNotification>(this, new LandedNotification(_lastGroundedPos, oldPos, this.GroundNormal), true);
    136.   }
    137.  
    138.   public void SetDropping(bool takeCurrentPositionAsLastGroundedPosition)
    139.   {
    140.   _currentState = GroundingState.Descending;
    141.   if (takeCurrentPositionAsLastGroundedPosition)
    142.   {
    143.   _lastGroundedPos = _motor.SurfaceConstraint.ProjectPosition2D(this.entityRoot.transform.position);
    144.   }
    145.   Notification.PostNotification<DroppedNotification>(this, new DroppedNotification(), true);
    146.   }
    147.  
    148.   public void SetHanging()
    149.   {
    150.   _currentState = GroundingState.Hanging;
    151.   }
    152.  
    153.  
    154.  
    155.  
    156.  
    157.  
    158.   public GroundingState UpdateGroundingState()
    159.   {
    160.   if (_currentState == GroundingState.Hanging)
    161.   {
    162.   return _currentState;
    163.   }
    164.  
    165.   if (_currentState == GroundingState.Grounded)
    166.   {
    167.   _lastGroundedPos = _motor.LastPosition;
    168.   if (!this.IsGrounded)
    169.   {
    170.   //LEFT GROUND
    171.   _currentState = GroundingState.Descending;
    172.   }
    173.   }
    174.   else if (_currentState > GroundingState.Grounded)
    175.   {
    176.   if (this.IsGrounded)
    177.   {
    178.   //LANDED
    179.   _currentState = GroundingState.Grounded;
    180.   var oldPos = _lastGroundedPos;
    181.   _lastGroundedPos = _motor.SurfaceConstraint.ProjectPosition2D(this.entityRoot.transform.position);
    182.  
    183.   Notification.PostNotification<LandedNotification>(this, new LandedNotification(_lastGroundedPos, oldPos, this.GroundNormal), true);
    184.   }
    185.   else if (_currentState == GroundingState.Jumping)
    186.   {
    187.   if (_motor.LastMoveVelocity.y < 0) _currentState = GroundingState.Descending;
    188.   }
    189.   else if (_currentState == GroundingState.Descending)
    190.   {
    191.   if (_lastGroundedPos.y - this.entityRoot.transform.position.y > this.TerminalFallDistance)
    192.   {
    193.   _currentState = GroundingState.Falling;
    194.   Notification.PostNotification<FallingNotification>(this, new FallingNotification(), true);
    195.   }
    196.   }
    197.   else if (_currentState == GroundingState.Falling)
    198.   {
    199.  
    200.   }
    201.  
    202.   }
    203.   else
    204.   {
    205.   _currentState = (this.IsGrounded) ? GroundingState.Grounded : GroundingState.Descending;
    206.   _lastGroundedPos = _motor.SurfaceConstraint.ProjectPosition2D(this.entityRoot.transform.position);
    207.   }
    208.  
    209.   return _currentState;
    210.   }
    211.  
    212.   /// <summary>
    213.   /// Retests the ground normal and returns true if grounded.
    214.   /// </summary>
    215.   /// <returns></returns>
    216.   public bool UpdateGroundNormal()
    217.   {
    218.   if (this.JustJumped)
    219.   {
    220.   _groundNormal = Vector2.zero;
    221.   return false;
    222.   }
    223.  
    224.   var geom = _motor.Controller.GetGeom(true);
    225.   var d = this.GroundingSkinWidth + _motor.Controller.SkinWidth;
    226.   RaycastHit hit;
    227.   if (geom.Cast(Vector3.down, out hit, d, Constants.MASK_SURFACE))
    228.   {
    229.   if(this.RepairSurfaceNormal)
    230.   {
    231.   _groundNormal = _motor.SurfaceConstraint.ProjectVectorTo2D(com.spacepuppy.Geom.PhysicsUtil.RepairHitSurfaceNormal(hit, Constants.MASK_SURFACE));
    232.   }
    233.   else
    234.   {
    235.   _groundNormal = _motor.SurfaceConstraint.ProjectVectorTo2D(hit.normal);
    236.   }
    237.   _lastGroundedTime = Time.time;
    238.   }
    239.   else
    240.   {
    241.   _groundNormal = Vector2.zero;
    242.   }
    243.  
    244.   return _groundNormal != Vector2.zero;
    245.   }
    246.  
    247.   #endregion
    248.  
    249.   #region IMovementEnhancer Interface
    250.  
    251.   private void OnBeforeUpdateMovement(object sender, System.EventArgs e)
    252.   {
    253.   this.UpdateGroundNormal();
    254.   this.UpdateGroundingState();
    255.   }
    256.  
    257.   #endregion
    258.  
    259.  
    260.  
    261.   #region Notification Types
    262.  
    263.   public class LandedNotification : Notification
    264.   {
    265.  
    266.   private Vector2 _pos;
    267.   private Vector2 _lastGroundedPos;
    268.   private Vector2 _groundNormal;
    269.   private float _fallDistance;
    270.  
    271.   public LandedNotification(Vector2 currentAndLastPos, Vector2 groundNormal)
    272.   {
    273.   _pos = currentAndLastPos;
    274.   _lastGroundedPos = currentAndLastPos;
    275.   _groundNormal = groundNormal;
    276.   _fallDistance = 0f;
    277.   }
    278.  
    279.   public LandedNotification(Vector2 currentPos, Vector2 lastGroundedPos, Vector2 groundNormal)
    280.   {
    281.   _pos = currentPos;
    282.   _lastGroundedPos = lastGroundedPos;
    283.   _groundNormal = groundNormal;
    284.   _fallDistance = Mathf.Max(0f, _lastGroundedPos.y - _pos.y);
    285.   }
    286.  
    287.   public Vector2 Position { get { return _pos; } }
    288.  
    289.   public Vector2 LastGroundedPosition { get { return _lastGroundedPos; } }
    290.  
    291.   public Vector2 GroundNormal { get { return _groundNormal; } }
    292.  
    293.   public float FallDistance { get { return _fallDistance; } }
    294.  
    295.   }
    296.  
    297.   public class DroppedNotification : Notification
    298.   {
    299.  
    300.   public DroppedNotification()
    301.   {
    302.  
    303.   }
    304.  
    305.   }
    306.  
    307.   public class FallingNotification : Notification
    308.   {
    309.  
    310.   public FallingNotification()
    311.   {
    312.  
    313.   }
    314.  
    315.   }
    316.  
    317.   #endregion
    318.  
    319.  
    320.   }
    321.  
    322. }
    323.  
    A little complex as I gather a lot of information, a lot of which may be superficial to general usage.

    But used in tandem with one of my JumpResolvers:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4.  
    5. using com.spacepuppy;
    6. using com.spacepuppy.Movement;
    7. using com.spacepuppy.Utils;
    8.  
    9. namespace com.apoc.Movement
    10. {
    11.  
    12.   [AddComponentMenu("Apoc/Movement/Resolver: Jumping")]
    13.   [RequireComponent(typeof(ApocMovementMotor))]
    14.   [RequireLikeComponent(typeof(IGroundingResolver))]
    15.   public class JumpResolver : SPNotifyingComponent, IDoubleJumpResolver
    16.   {
    17.  
    18.   #region Fields
    19.  
    20.   [Tooltip("Duration of time upon leaving the ground that you're still allowed to initialize a jump.")]
    21.   public float JumpInitDelay = 0.1f;
    22.  
    23.   public float JumpSpeed = 7.0f;
    24.  
    25.   public bool DoubleJump = false;
    26.   public float DoubleJumpCooldown = 0.1f;
    27.   [Tooltip("Restrict double jump to when you're at some height in your first jump. Defaults to negative infinity to allow double jump at any time.")]
    28.   public float MinimumHeightAllowDoubleJump = float.NegativeInfinity;
    29.   public float DoubleJumpSpeed = 7.0f;
    30.  
    31.   private ApocMovementMotor _motor;
    32.   private IGroundingResolver _groundingResolver;
    33.  
    34.   private float _cooldownTimer;
    35.   private bool _bDidDoubleJump = false;
    36.  
    37.   private bool _bJumpCached;
    38.   private float? _cachedJumpSpeed;
    39.  
    40.   #endregion
    41.  
    42.   #region CONSTRUCTOR
    43.  
    44.   protected override void Awake()
    45.   {
    46.   base.Awake();
    47.  
    48.   _motor = this.GetComponent<ApocMovementMotor>();
    49.   _groundingResolver = this.GetComponentAlt<IGroundingResolver>();
    50.   }
    51.  
    52.   protected override void OnStartOrEnable()
    53.   {
    54.   base.OnStartOrEnable();
    55.  
    56.   Notification.RegisterObserver<GroundingResolver.LandedNotification>(this.entityRoot, this.OnLanded);
    57.  
    58.   _motor.BeforeUpdateMovement -= this.OnBeforeUpdateMovement;
    59.   _motor.BeforeUpdateMovement += this.OnBeforeUpdateMovement;
    60.   }
    61.  
    62.   protected override void OnDisable()
    63.   {
    64.   base.OnDisable();
    65.  
    66.   Notification.RemoveObserver<GroundingResolver.LandedNotification>(this.entityRoot, this.OnLanded);
    67.  
    68.   _motor.BeforeUpdateMovement -= this.OnBeforeUpdateMovement;
    69.   }
    70.  
    71.   #endregion
    72.  
    73.   #region Properties
    74.  
    75.   public bool IsCoolingDown { get { return _cooldownTimer > 0.0f; } }
    76.  
    77.   public bool DidDoubleJump { get { return _bDidDoubleJump; } }
    78.  
    79.   #endregion
    80.  
    81.   #region Methods
    82.    
    83.   public bool ApplyJump(ref Vector2 mv, float overrideJumpSpeed, bool bDesiresToJump = false)
    84.   {
    85.   if (!this.enabled) return false;
    86.   if (this.IsCoolingDown) return false;
    87.  
    88.   var t = Time.time;
    89.   if (_groundingResolver.IsGrounded ||
    90.   (t - _groundingResolver.LastJumpedTime > this.JumpInitDelay && t - _groundingResolver.LastGroundedTime < this.JumpInitDelay))
    91.   {
    92.   if (_bJumpCached || bDesiresToJump)
    93.   {
    94.   var spd = (_cachedJumpSpeed != null) ? _cachedJumpSpeed.Value : overrideJumpSpeed;
    95.   //mv.y = spd;
    96.  
    97.   mv = VectorUtil.SetLengthOnAxis(mv, _groundingResolver.DesiredJumpNormal, spd);
    98.   _bJumpCached = false;
    99.   _cachedJumpSpeed = null;
    100.   _cooldownTimer = this.DoubleJumpCooldown;
    101.   return true;
    102.   }
    103.   }
    104.   else if (this.DoubleJump && !_bDidDoubleJump)
    105.   {
    106.   if (_bJumpCached || bDesiresToJump)
    107.   {
    108.   if (!_groundingResolver.IsGrounded && (_motor.Position.y - _groundingResolver.LastGroundedPosition.y) > this.MinimumHeightAllowDoubleJump)
    109.   {
    110.   var spd = (_cachedJumpSpeed != null) ? _cachedJumpSpeed.Value : overrideJumpSpeed;
    111.   //mv.y = spd;
    112.  
    113.   mv = VectorUtil.SetLengthOnAxis(mv, _groundingResolver.DesiredJumpNormal, spd);
    114.   _bJumpCached = false;
    115.   _cachedJumpSpeed = null;
    116.   _cooldownTimer = this.DoubleJumpCooldown;
    117.   _bDidDoubleJump = true;
    118.  
    119.   return true;
    120.   }
    121.   }
    122.   }
    123.  
    124.   _bJumpCached = false;
    125.   return false;
    126.   }
    127.  
    128.   public void CacheJump(float overrideJumpSpeed)
    129.   {
    130.   if (this.IsCoolingDown) return;
    131.  
    132.   _bJumpCached = true;
    133.   _cachedJumpSpeed = overrideJumpSpeed;
    134.   }
    135.  
    136.   public void ResetCooldown()
    137.   {
    138.   _cooldownTimer = 0.0f;
    139.   }
    140.  
    141.   #endregion
    142.  
    143.   #region IJumpResolver Interface
    144.  
    145.   public bool IsGrounded
    146.   {
    147.   get { return _groundingResolver.IsGrounded; }
    148.   }
    149.  
    150.   public bool ApplyJump(ref Vector2 mv, bool bDesiresToJump = false)
    151.   {
    152.   if (!this.enabled) return false;
    153.   if (this.IsCoolingDown) return false;
    154.  
    155.   var t = Time.time;
    156.   if (_groundingResolver.IsGrounded ||
    157.   (t - _groundingResolver.LastJumpedTime > this.JumpInitDelay && t - _groundingResolver.LastGroundedTime < this.JumpInitDelay))
    158.   {
    159.   if (_bJumpCached || bDesiresToJump)
    160.   {
    161.   var spd = (_cachedJumpSpeed != null) ? _cachedJumpSpeed.Value : this.JumpSpeed;
    162.   //mv.y = spd;
    163.   mv = VectorUtil.SetLengthOnAxis(mv, _groundingResolver.DesiredJumpNormal, spd);
    164.  
    165.   _bJumpCached = false;
    166.   _cachedJumpSpeed = null;
    167.   _cooldownTimer = this.DoubleJumpCooldown;
    168.   return true;
    169.   }
    170.   }
    171.   else if (this.DoubleJump && !_bDidDoubleJump)
    172.   {
    173.   if (_bJumpCached || bDesiresToJump)
    174.   {
    175.   if (!_groundingResolver.IsGrounded && (_motor.Position.y - _groundingResolver.LastGroundedPosition.y) > this.MinimumHeightAllowDoubleJump)
    176.   {
    177.   var spd = (_cachedJumpSpeed != null) ? _cachedJumpSpeed.Value : this.DoubleJumpSpeed;
    178.   //mv.y = spd;
    179.   mv = VectorUtil.SetLengthOnAxis(mv, _groundingResolver.DesiredJumpNormal, spd);
    180.  
    181.   _bJumpCached = false;
    182.   _cachedJumpSpeed = null;
    183.   _cooldownTimer = this.DoubleJumpCooldown;
    184.   _bDidDoubleJump = true;
    185.  
    186.   return true;
    187.   }
    188.   }
    189.   }
    190.  
    191.   _bJumpCached = false;
    192.   return false;
    193.   }
    194.  
    195.   public void CacheJump()
    196.   {
    197.   if (this.IsCoolingDown) return;
    198.  
    199.   _bJumpCached = true;
    200.   _cachedJumpSpeed = null;
    201.   }
    202.  
    203.   public void SignalJumping()
    204.   {
    205.   _groundingResolver.SetJumping();
    206.   Notification.PostNotification<JumpedNotification>(this, JumpedNotification.Create(_bDidDoubleJump), true);
    207.   }
    208.  
    209.   public void ResetDoubleJump()
    210.   {
    211.   _bDidDoubleJump = false;
    212.   }
    213.  
    214.   #endregion
    215.  
    216.   #region Notification Handlers
    217.  
    218.   private void OnLanded(object sender, GroundingResolver.LandedNotification n)
    219.   {
    220.   this.ResetCooldown();
    221.   this.ResetDoubleJump();
    222.   }
    223.  
    224.   #endregion
    225.  
    226.   #region IMovementEnhancer Interface
    227.  
    228.   private void OnBeforeUpdateMovement(object sender, System.EventArgs e)
    229.   {
    230.   if (_cooldownTimer > 0f)
    231.   {
    232.   _cooldownTimer -= Time.deltaTime;
    233.   if (_cooldownTimer < 0.0f)
    234.   {
    235.   _cooldownTimer = 0.0f;
    236.   }
    237.   }
    238.   }
    239.  
    240.   #endregion
    241.  
    242.  
    243.    
    244.   }
    245.  
    246. }
    247.  
    Of course each implement an interface of IGroundingResolver and IJumpResolver in case I need to write an alternate version of each.

    Then from my movement script I just call 'ApplyJump' to my velocity vector, to get jumps added on.
     
  3. AtomicCabbage33

    AtomicCabbage33

    Joined:
    Aug 31, 2015
    Posts:
    141
    thanks so much, but now I've got another issue- my bullet holes are not spawning when i press the left mouse key. I get an error in the console 'Object reference not set to an instance of an object'. My gunscript is :

    var cameraMain : Camera;
    @HideInInspector
    var cameraaim : Camera;
    var fireSpeed : float = 15;
    @HideInInspector
    var waitTillNextFire : float = 0;
    var bullet : GameObject;
    var bulletSpawn : GameObject;
    function Start () {
    cameraMain.enabled = true;
    cameraaim.enabled = false;
    }
    function Update ()
    {
    if (Input.GetButton("Fire1"))
    {
    if (waitTillNextFire <=0)
    {
    if (bullet)
    Instantiate(bullet,bulletSpawn.transform.position, bulletSpawn.transform.rotation);
    waitTillNextFire = 1;
    }
    }
    waitTillNextFire -= Time.deltaTime * fireSpeed;


    if (Input.GetButtonDown("Fire2")){
    if ( cameraMain.enabled == true){
    cameraaim.enabled = true;
    cameraMain.enabled = false;
    }
    else if (cameraaim.enabled == true){
    cameraMain.enabled = true;
    cameraaim.enabled = false;


    }
    }
    }


    and my bullet script is:

    var maxDist : float = 100000;
    var decalHitWall : GameObject;
    var floatInFrontOfWall : float = 0.0001;

    function Update ()
    {
    var hit : RaycastHit;
    if (Physics.Raycast(transform.position, transform.forward, hit, maxDist))
    {
    if (decalHitWall && hit.transform.tag == "Level")
    Instantiate(decalHitWall, hit.point + (HierarchyType.normal * floatInFrontOfWall), Quaternion.LookRotation(hit.normal));
    }
    Destroy(gameObject);
    }



    I have a bullet spawn which is set at the end of the gun barrel and the gun itself has the gunscript attached. I also have a bullethole prefab which is attached to the bullet.. sorry if this doesnt make sense didnt know how to phrase it all :)