Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Mikhailzrick · Mar 06, 2021 at 11:44 PM · c#fpsprojectileprojectilesreflect

Bullet ricochet

I've been using the projectile script from the FPS microgame and I'm trying to figure out how to implement a way to have the bullets ricochet. Or specifically where I can put an if(isRicochet) "ricochet code here" in the script without breaking the rest of the code as I use this code for all projectiles and just have public bools to control any added customization to the script. For example I already have some projectiles with trail renders, and another separate script to control homing in on the player for an enemy projectile.


Projectiles are physical objects, so maybe just add a rigid body? Cast a ray and use Vector3.Reflect? Tried a few things and not having any luck with editing the existing code to get the effect I want. Or maybe I'd be better off with a separate script that pulls data from the projectile script. Not sure.


Essentially what I'd like is like the old school Unreal Tournament Flak Cannon where you could bounce the projectiles off walls etc. and hit targets.

Any help appreciated to point me in the right direction.

 using System.Collections.Generic;
 using UnityEngine;
 
 [RequireComponent(typeof(ProjectileBase))]
 public class ProjectileStandard : MonoBehaviour
 {
     [Header("General")]
     [Tooltip("Radius of this projectile's collision detection")]
     public float radius = 0.01f;
     [Tooltip("Transform representing the root of the projectile (used for accurate collision detection)")]
     public Transform root;
     [Tooltip("Transform representing the tip of the projectile (used for accurate collision detection)")]
     public Transform tip;
     [Tooltip("LifeTime of the projectile")]
     public float maxLifeTime = 5f;
     [Tooltip("VFX prefab to spawn upon impact")]
     public GameObject impactVFX;
     [Tooltip("LifeTime of the VFX before being destroyed")]
     public float impactVFXLifetime = 5f;
     [Tooltip("Offset along the hit normal where the VFX will be spawned")]
     public float impactVFXSpawnOffset = 0.1f;
     [Tooltip("Clip to play on impact")]
     public AudioClip impactSFXClip;
     [Tooltip("Layers this projectile can collide with")]
     public LayerMask hittableLayers = -1;
 
     [Header("Movement")]
     [Tooltip("Speed of the projectile")]
     public float speed = 20f;
     [Tooltip("Downward acceleration from gravity")]
     public float gravityDownAcceleration = 0f;
     [Tooltip("Distance over which the projectile will correct its course to fit the intended trajectory (used to drift projectiles towards center of screen in First Person view). At values under 0, there is no correction")]
     public float trajectoryCorrectionDistance = -1;
     [Tooltip("Determines if the projectile inherits the velocity that the weapon's muzzle had when firing")]
     public bool inheritWeaponVelocity = false;
     public bool isHoming = false;
     public bool hasTrail = false;
     public TrailRenderer projectileTrail;
 
     [Header("Damage")]
     [Tooltip("Damage of the projectile")]
     public float damage = 40f;
     [Tooltip("Area of damage. Keep empty if you don<t want area damage")]
     public DamageArea areaOfDamage;
 
     [Header("Debug")]
     [Tooltip("Color of the projectile radius debug view")]
     public Color radiusColor = Color.cyan * 0.2f;
 
     ProjectileBase m_ProjectileBase;
     Vector3 m_LastRootPosition;
     Vector3 m_Velocity;
     bool m_HasTrajectoryOverride;
     float m_ShootTime;
     Vector3 m_TrajectoryCorrectionVector;
     Vector3 m_ConsumedTrajectoryCorrectionVector;
     List<Collider> m_IgnoredColliders;
 
     const QueryTriggerInteraction k_TriggerInteraction = QueryTriggerInteraction.Collide;
 
     private void OnEnable()
     {
         m_ProjectileBase = GetComponent<ProjectileBase>();
         DebugUtility.HandleErrorIfNullGetComponent<ProjectileBase, ProjectileStandard>(m_ProjectileBase, this, gameObject);
 
         m_ProjectileBase.onShoot += OnShoot;
 
         Destroy(gameObject, maxLifeTime);
     }
 
     void OnShoot()
     {
         m_ShootTime = Time.time;
         m_LastRootPosition = root.position;
         m_Velocity = transform.forward * speed;
         m_IgnoredColliders = new List<Collider>();
         transform.position += m_ProjectileBase.inheritedMuzzleVelocity * Time.deltaTime;
 
         // Ignore colliders of owner
         Collider[] ownerColliders = m_ProjectileBase.owner.GetComponentsInChildren<Collider>();
         m_IgnoredColliders.AddRange(ownerColliders);
 
         // Handle case of player shooting (make projectiles not go through walls, and remember center-of-screen trajectory)
         PlayerWeaponsManager playerWeaponsManager = m_ProjectileBase.owner.GetComponent<PlayerWeaponsManager>();
         if(playerWeaponsManager)
         {
             m_HasTrajectoryOverride = true;
 
             Vector3 cameraToMuzzle = (m_ProjectileBase.initialPosition - playerWeaponsManager.weaponCamera.transform.position);
 
             m_TrajectoryCorrectionVector = Vector3.ProjectOnPlane(-cameraToMuzzle, playerWeaponsManager.weaponCamera.transform.forward);
             if (trajectoryCorrectionDistance == 0)
             {
                 transform.position += m_TrajectoryCorrectionVector;
                 m_ConsumedTrajectoryCorrectionVector = m_TrajectoryCorrectionVector;
             }
             else if (trajectoryCorrectionDistance < 0)
             {
                 m_HasTrajectoryOverride = false;
             }
             
             if (Physics.Raycast(playerWeaponsManager.weaponCamera.transform.position, cameraToMuzzle.normalized, out RaycastHit hit, cameraToMuzzle.magnitude, hittableLayers, k_TriggerInteraction))
             {
                 if (IsHitValid(hit))
                 {
                     OnHit(hit.point, hit.normal, hit.collider);
                 }
             }
         }
     }
 
     void Update()
     {
         // Move        
         if (!isHoming)
         {
             transform.position += m_Velocity * Time.deltaTime;
         }
         if (inheritWeaponVelocity)
         {
             transform.position += m_ProjectileBase.inheritedMuzzleVelocity * Time.deltaTime;
         }
 
         // Drift towards trajectory override (this is so that projectiles can be centered 
         // with the camera center even though the actual weapon is offset)
         if (m_HasTrajectoryOverride && m_ConsumedTrajectoryCorrectionVector.sqrMagnitude < m_TrajectoryCorrectionVector.sqrMagnitude)
         {
             Vector3 correctionLeft = m_TrajectoryCorrectionVector - m_ConsumedTrajectoryCorrectionVector;
             float distanceThisFrame = (root.position - m_LastRootPosition).magnitude;
             Vector3 correctionThisFrame = (distanceThisFrame / trajectoryCorrectionDistance) * m_TrajectoryCorrectionVector;
             correctionThisFrame = Vector3.ClampMagnitude(correctionThisFrame, correctionLeft.magnitude);
             m_ConsumedTrajectoryCorrectionVector += correctionThisFrame;
 
             // Detect end of correction
             if(m_ConsumedTrajectoryCorrectionVector.sqrMagnitude == m_TrajectoryCorrectionVector.sqrMagnitude)
             {
                 m_HasTrajectoryOverride = false;
             }
 
             transform.position += correctionThisFrame;
         }
 
         // Orient towards velocity
         if (!isHoming)
         {
             transform.forward = m_Velocity.normalized;
         }
 
         // Gravity
         if (gravityDownAcceleration > 0)
         {
             // add gravity to the projectile velocity for ballistic effect
             m_Velocity += Vector3.down * gravityDownAcceleration * Time.deltaTime;
         }
 
         // Hit detection
         {
             RaycastHit closestHit = new RaycastHit();
             closestHit.distance = Mathf.Infinity;
             bool foundHit = false;
 
             // Sphere cast
             Vector3 displacementSinceLastFrame = tip.position - m_LastRootPosition;
             RaycastHit[] hits = Physics.SphereCastAll(m_LastRootPosition, radius, displacementSinceLastFrame.normalized, displacementSinceLastFrame.magnitude, hittableLayers, k_TriggerInteraction);
             foreach (var hit in hits)
             {
                 if (IsHitValid(hit) && hit.distance < closestHit.distance)
                 {
                     foundHit = true;
                     closestHit = hit;
                 }
             }
 
             if (foundHit)
             {
                 // Handle case of casting while already inside a collider
                 if(closestHit.distance <= 0f)
                 {
                     closestHit.point = root.position;
                     closestHit.normal = -transform.forward;
                 }
 
                 OnHit(closestHit.point, closestHit.normal, closestHit.collider);
             }
         }
 
         m_LastRootPosition = root.position;
     }
 
     bool IsHitValid(RaycastHit hit)
     {
         // ignore hits with an ignore component
         if(hit.collider.GetComponent<IgnoreHitDetection>())
         {
             return false;
         }
 
         // ignore hits with triggers that don't have a Damageable component
         if(hit.collider.isTrigger && hit.collider.GetComponent<Damageable>() == null)
         {
             return false;
         }
 
         // ignore hits with specific ignored colliders (self colliders, by default)
         if (m_IgnoredColliders != null && m_IgnoredColliders.Contains(hit.collider))
         {
             return false;
         }
 
         return true;
     }
 
     void OnHit(Vector3 point, Vector3 normal, Collider collider)
     { 
         // damage
         if (areaOfDamage)
         {
             // area damage
             areaOfDamage.InflictDamageInArea(damage, point, hittableLayers, k_TriggerInteraction, m_ProjectileBase.owner);
         }
         else
         {
             // point damage
             Damageable damageable = collider.GetComponent<Damageable>();
             if (damageable)
             {
                 damageable.InflictDamage(damage, false, m_ProjectileBase.owner);
             }
         }
 
         // impact vfx
         if (impactVFX)
         {
             GameObject impactVFXInstance = Instantiate(impactVFX, point + (normal * impactVFXSpawnOffset), Quaternion.LookRotation(normal));
             if (impactVFXLifetime > 0)
             {
                 Destroy(impactVFXInstance.gameObject, impactVFXLifetime);
             }
         }
 
         // impact sfx
         if (impactSFXClip)
         {
             AudioUtility.CreateSFX(impactSFXClip, point, AudioUtility.AudioGroups.Impact, 1f, 3f);
         }
 
         // Self Destruct
         if (!hasTrail)
         {
             Destroy(this.gameObject);
         }
         else
         {
             projectileTrail.transform.parent = null;
             projectileTrail.autodestruct = true;
             Destroy(this.gameObject);
         }
     }
 
     private void OnDrawGizmosSelected()
     {
         Gizmos.color = radiusColor;
         Gizmos.DrawSphere(transform.position, radius);
     }
 }
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

707 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Multiple Cars not working 1 Answer

Shooting Script -- Bullet won't fire in correct direction First Person View 3D 2 Answers

Distribute terrain in zones 3 Answers

UFPS Projectile Spawn Point (SOLVED) 2 Answers

Don't allow the player to shoot while projectile is travelling 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges