Planning - weapons module
If the magazine is loaded with bullets, it can be fired; Otherwise, wait for magazine replacement;
When firing bullets, play sound effects, animation and display sparks;
The player's gun can be single shot or continuous shot;
Player bullet
- HP of the enemy will be reduced after hitting the enemy, and HP of different degrees will be reduced according to the position of hitting the enemy
- The bullet flies to the target point, destroys it, and creates the corresponding special effects
Enemy bullet
- After hitting the player, the player's HP is reduced
- The bullet flies to the target point, destroys it, and creates the corresponding special effects
- Shoot at the player's head. The flight speed is slow, which is convenient for players to avoid
requirement analysis
Create script: the player Gun gun provides the function of firing and changing magazine
Create script: single shot mode SingleGun, inherited from Gun, and call the corresponding firing method according to the player's input
Create script: automatic Gun in continuous firing mode, inherited from Gun, and call the corresponding firing method according to the player's input
Create script: enemy gun EnemyGun, which provides automatic firing function and unlimited ammunition
-------------------
Create script: Bullet bullet, calculate the target point of attack, execute movement, and create contact effects;
Players detect the environment and enemies; Enemy detection environment;
Create script: player Bullet PlayerBullet, inherited from the Bullet, and HP will be deducted after hitting the enemy
Create script: enemy bullet EnemyBullet, deduct HP after hitting the player
Note: for all the above special effects, sound related will not be realized temporarily
Script implementation and explanation
Player part
Player statusIt also provides a reference to the player as a unique object so that all other objects can obtain the player object
Provide methods of injury, death, etc
public class PlayerDemo : MonoBehaviour { //Provides the current object reference public static PlayerDemo Instance { get; private set; } public float HP; private void Start() { Instance = this; HP = 100; } /// <summary> ///Wounded /// </summary> ///< param name = "attacknumber" > injury number < / param > public void Damage(int attackNumber) { HP -= attackNumber; if (HP <= 0) { Death(); } } /// <summary> ///Death /// </summary> private void Death() { Destroy(this.gameObject); } }gun Boxmagazine magazine
The magazine class provides data such as magazine capacity, total bullets and current bullets. It is hung on the parent empty object of the gun model object
public class BoxMagezineDemo : MonoBehaviour { /// <summary> ///Magazine capacity /// </summary> public int boxMagazine = 50; /// <summary> ///Number of bullets in the current magazine /// </summary> public int currentBullet; /// <summary> ///Total bullets /// </summary> public int allBullet; }GunAnimation - gun animation
The gun animation class provides a series of animation playback functions of the gun
AnimationTool class is an animation and animation tool class, which will be described later. It is hung on the parent empty object of the gun model
public class GunAnimation : MonoBehaviour { /// <summary> ///Fire animation /// </summary> public string fireAnimation="Gunfire"; /// <summary> ///Replace magazine animation /// </summary> public string updateAmmoAnimation="GunUpdateAmmo"; /// <summary> ///Missing bullet animation /// </summary> public string lackBulletAnimation="GunLackBullet"; /// <summary> ///Playback tool /// </summary> public AnimationTool action; private void Awake() { action = new AnimationTool(GetComponentInChildren<Animation>()); } }BulletLight - bullet fire
The muzzle firelight object script provides the function of flashing firelight effect and hangs on the firelight object. The firelight object is the child of the parent empty object of the gun model, that is, the brother of the gun model object
public class BulletLightDemo : MonoBehaviour { private GameObject bulletLight; private void Start() { bulletLight = GetResource(); } /// <summary> ///The fire flickered /// </summary> public void DisplayLight() { Destroy(Instantiate(bulletLight, transform.position, Quaternion.identity),0.20F); } private GameObject GetResource() { return Resources.Load<GameObject>("GunTest/Bullet/BulletLight"); } }Gun gun
The parent class of the player's shooting mode provides functions such as shooting and filling the magazine. Note: this script is not hung on the object. What is hung on the object is the shooting mode inherited from this class: SingleGun and AutomaticGun. The shooting mode script is hung on the parent empty object of the gun model object
--------------------------—
ShootingIt is divided into the following two steps: 1. Preparation stage: whether it can shoot; 2. Create bullets;
Preparation stage:
- Is there a bullet in the magazine
- Is the magazine change animation currently playing
/// <summary> ///Bullet preparation /// </summary> /// <returns></returns> private bool Ready() { if (boxMagezine.currentBullet <= 0) { anim.action.Play(anim.lackBulletAnimation);//If there are no bullets, play the animation prompt and return false return false; } if (anim.action.isPlay(anim.updateAmmoAnimation))//If you are changing bullets, return false return false; return true; }
Create bullet
- Ready
- Create bullet
- Play shooting animation and firelight objects
Method of creating bullet object: object. Instance (object template, creation point, initial orientation) method
/// <summary> ///Fire /// </summary> ///< param name = "direction" > muzzle direction < / param > protected virtual void Firing(Vector3 direction) { //Prepare the bullet //Determine whether ready for launch if (!Ready()) return; //Player gun firing, muzzle direction //Create bullet //The orientation here can be Quaternion.LookRotation, but since the Z axis here is not the bullet orientation, I can only change it separately GameObject Bullet = Instantiate(bullet, transform.TransformPoint(Vector3.right), Quaternion.identity); //Since the bullet orientation here is the Y-axis, I want to assign the muzzle direction to the Y-axis direction of the bullet object Bullet.GetComponent<Transform>().up = direction; //Play shooting animation anim.action.Play(anim.fireAnimation); //Play firelight object bulletLight.DisplayLight(); //Play audio //audioSource.PlayOneShot(audio); //The number of bullets in the magazine is reduced by 1 boxMagezine.currentBullet--; }
--------------------------—
Filling magazineWhen the total number of bullets is not 0 or the number of bullets in the current magazine is less than the magazine capacity, it is allowed to fill the magazine
Fill the number of bullets in the magazine and subtract the corresponding number from the total number of bullets. If it cannot be filled, fill all the remaining bullets into the magazine and return the total number of bullets to zero
/// <summary> ///Filling magazine /// </summary> protected void UpdateAmmo() { if (boxMagezine.allBullet > 0&& boxMagezine.currentBullet < boxMagezine.boxMagazine) { anim.action.Play(anim.updateAmmoAnimation);//Play the fill magazine animation int add = boxMagezine.boxMagazine - boxMagezine.currentBullet; if (add <= boxMagezine.allBullet) { boxMagezine.allBullet -= add; boxMagezine.currentBullet += add; } else { boxMagezine.currentBullet += boxMagezine.allBullet; boxMagezine.allBullet = 0; } } else { Debug.Log("FullorNone"); //It indicates that there are no bullets or the magazine is full } }
--------------------------—
Change firing mode/// <summary> ///Switch firing mode /// </summary> private void ChangeFiringMethod() { if (Input.GetKeyDown(KeyCode.B)) { //Switch mode GetComponent<SingleGunDemo>().enabled = !GetComponent<SingleGunDemo>().enabled; GetComponent<AutomaticGunDemo>().enabled = !GetComponent<AutomaticGunDemo>().enabled; } }
--------------------------—
Various resources and descriptions for initializing GunMain fields
/// <summary> ///Bullet type /// </summary> protected GameObject bullet; /// <summary> ///Magazine /// </summary> private BoxMagezineDemo boxMagezine; /// <summary> ///Gun animation script component /// </summary> private GunAnimation anim; /// <summary> ///Muzzle firelight object /// </summary> private BulletLightDemo bulletLight;
initialization
protected virtual void Start() { //Initialize magazine boxMagezine = GetComponent<BoxMagezineDemo>(); //Initialize firelight object bulletLight = transform.GetChild(1).GetComponent<BulletLightDemo>(); //Initialize animated objects anim = GetComponent<GunAnimation>(); //Initialize total bullets boxMagezine.allBullet = 1000; //Obtain bullet resources bullet = GetResource(); //Initial default single point mode GetComponent<SingleGunDemo>().enabled = true; GetComponent<AutomaticGunDemo>().enabled = false; }
Read resources from resource file
It needs to be obtained through the resource path. Write the relative path here. Create a Resources file in Assets. Note that R should be capitalized
Specific methods: resources. Load < GameObject > ("guntest / bullet / playerbullet");
Note that the path here is relative and should be written from the folder in the Resources you created. For example, the path of the player's bullet preform here is:
Assets/Resources/GunTest/Bullet/PlayerBullet, so I should write the path of GunTest/Bullet/PlayerBullet in this method.
/// <summary> ///Get bullet resource file /// </summary> ///< returns > resource object < / returns > private GameObject GetResource() { return Resources.Load<GameObject>("GunTest/Bullet/PlayerBullet"); }SingleGun single shot mode
Hang on the parent empty object of the gun model
/// <summary> ///Single shot mode /// </summary> public class SingleGunDemo : GunDemo { /// <summary> ///Initialization /// </summary> protected override void Start() { //Initialize parent resource base.Start(); } private void Update() { //Call parent class update base.Update(); //Shooting Fire(); } /// <summary> ///Shoot /// </summary> private void Fire() { if (Input.GetKeyDown(KeyCode.O)) { base.Firing(transform.right); } if (Input.GetKeyDown(KeyCode.R)) { base.UpdateAmmo(); } } }AutomaticGun burst mode
Hang on the parent empty object of the gun model
Similar to the single shot mode, the only difference is the selection of GetKey method
/// <summary> ///Continuous mode /// </summary> public class AutomaticGunDemo :GunDemo { /// <summary> ///Initialization /// </summary> protected override void Start() { //Initialize parent resource base.Start(); } private void Update() { //Call parent class update base.Update(); //Shooting Fire(); } /// <summary> ///Shoot /// </summary> private void Fire() { if (Input.GetKey(KeyCode.O)) { base.Firing(transform.right); } if (Input.GetKeyDown(KeyCode.R)) { base.UpdateAmmo(); } } }bullet Bullet bullet
The parent class of all player bullet types, which provides functions such as ray detection
Definition of various parameters/// <summary> ///Layers /// </summary> public LayerMask mask; /// <summary> ///Radiographic object /// </summary> protected RaycastHit hit; /// <summary> ///Hit the target position /// </summary> public Vector3 targetPos;Radiographic testing
Radiographic testing method: physics. Raycast (starting point, direction vector, out output detected object information, distance, layer)
Here, the direction vector should be set as the bullet orientation. When I model the bullet, the direction is the y-axis, so it is transform.up, generally transform.forward
After the object is detected, assign the corresponding position to targetPos and store the target position. If it is not detected, the position will move 100 units towards the target
/// <summary> ///Calculate target point /// </summary> public void BulletHit() { if (Physics.Raycast(this.transform.position,transform.up, out hit, 100, mask)) { //Detected targetPos = hit.point; } else { targetPos = transform.position +transform.up* 100; } //Create special effects at target points }PlayerBullet - player bullet
It inherits the Bullet and provides functions such as the Bullet flying to the target point and judging whether it hit or not
Initialize bullet target pointCall the BulletHit method of the parent class to obtain the target point
private void Start() { BulletHit(); }Judge whether to hit the enemy
Judge whether the object is an enemy through the label on the object. If so, call the other party's injury method to deduct HP
/// <summary> ///Contact judgment /// </summary> private void Touch() { if ((targetPos - transform.position).sqrMagnitude < 0.1f) { if (hit.collider.tag == "Enemy")//If it's the enemy { hit.collider.GetComponent<EnemyDemo>().Damage(10);//Buckle blood DestroyImmediate(this.gameObject); } else { Destroy(this.gameObject); } } }The bullet flew to the target point
Note that if no unit is detected, hit is null. Therefore, null judgment should be added to prevent abnormalities. The bullet will destroy the object immediately after flying to the target point
/// <summary> ///The bullet flew to the target point /// </summary> private void Move() { transform.position = Vector3.MoveTowards(transform.position, targetPos, 50 * Time.deltaTime); if (hit.collider != null) { Touch(); } else { if ((transform.position - targetPos).sqrMagnitude < 0.1f) { Destroy(this.gameObject); } } }
Enemy part
Enemy statusProvide methods for enemy injury, death, etc
public class EnemyDemo : MonoBehaviour { [HideInInspector] public EnemyProduce produce; public float HP; private void Start() { HP = 100; } /// <summary> ///Wounded /// </summary> ///< param name = "attacknumber" > injury number < / param > public void Damage(int attackNumber) { HP -= attackNumber; if (HP <= 0) { Death(); } } /// <summary> ///Death /// </summary> private void Death() { Destroy(this.gameObject); //Set route becomes available this.GetComponent<EnemyAI>().wayLine.IsUsable = true; //Tell the generator that the unit has died and the current number of survivors is - 1 produce.aliveCount--; } }gun
EnemyGun - enemy gun
The enemy has unlimited ammunition and the bullet speed is slow, which is convenient for players to avoid
Definition and initialization of various parameters/// <summary> ///Bullet resources /// </summary> private GameObject bullet; /// <summary> ///Attack timing /// </summary> private float firingTime; /// <summary> ///Attack interval /// </summary> private float attackTime; /// <summary> ///Initialization /// </summary> private void Start() { firingTime = 0; attackTime = 1.5F; bullet = GetResources(); }Obtain bullet resources
/// <summary> ///Obtain bullet resources /// </summary> /// <returns></returns> private GameObject GetResources() { return Resources.Load<GameObject>("GunTest/Bullet/EnemyBullet"); }Attack timing determination
There are two methods:
- Each time it is determined that the attack opportunity is greater than the attack interval, the rendered frame time is accumulated to the attack opportunity. If it is greater than the attack interval, attack and return the attack opportunity to zero
- Each time it is determined that the attack opportunity is less than the game time. After each attack, increase the attack opportunity by an attack interval
/// <summary> ///Attack timing /// </summary> private void AttackTime() { if (firingTime > attackTime) { Firing(); firingTime = 0; } else { firingTime += Time.deltaTime; } }Shooting
/// <summary> ///Shoot /// </summary> private void Firing() { GameObject Bullet = Object.Instantiate(bullet, transform.TransformPoint(Vector3.right), Quaternion.identity); Bullet.GetComponent<Transform>().up = transform.right;//Based on bullet orientation }bullet
EnemyBullet - enemy bullet
Provide bullet flight, trigger and other methods. The enemy bullets here do not use ray detection, and control the low speed
public class EnemyBulletDemo : MonoBehaviour { //In order to enable players to avoid enemy bullets, they do not use rays, but use triggers and set a slower speed so that players can have a chance to avoid them private void OnTriggerEnter(Collider other) { if (other.tag == "Player")//If it's a player { //If you contact the player other.GetComponent<PlayerDemo>().Damage(1); } Destroy(this.gameObject); } private void Update() { transform.Translate(0, Time.deltaTime * 5, 0); Destroy(this.gameObject, 5); } }