Unity notes - 12 - exercise item weapon module
plan
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
Function disassembly and gradual realization
Player gun
The player's gun script should be implemented: check the magazine, create bullets, and switch the shooting mode
To fire bullets, the gun is roughly divided into the following steps: check the magazine, create bullets, fire bullets, hit the target, and deduct the target HP
Check magazine
If there is a bullet in the magazine, it can be fired, otherwise it can't be fired
Here you need three variables to store: the total number of bullets you have allBullet; Magazine capacity boxMagazine; Number of bullets in the current magazine currentBullet
When your magazine needs to be filled, the corresponding number of bullets will be deducted from the total number of bullets;
When there is no bullet in the magazine, the bullet cannot be fired;
When the total number of bullets returns to zero, the magazine cannot be filled;
Create bullet
Need to obtain: Bullet object template; Muzzle position; Muzzle direction
Bullet object template
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.
Muzzle position
The muzzle position can be obtained by transforming the muzzle position into world coordinates by using the transform.TransformPoint() method
Muzzle direction
Transform.forward generally uses this. I use transform.right because the muzzle direction of the preform is the x-axis when making the model
Create bullet
Use the object. Instance (object template, create point, initial orientation) method
GameObject Bullet = Object.Instantiate(bullet, transform.TransformPoint(Vector3.right), transform.rotation);
The initial orientation is consistent with the muzzle
It should be noted that when making the model, the axis of the bullet should be consistent with the axis of the muzzle. I have set the muzzle as X axis, so the axis of the bullet should also be x axis, otherwise the animation will be very strange
After creation, you need to configure the bullet firing direction and layer.
To launch a bullet, you need to obtain the firing direction (i.e. muzzle direction, which is assigned here first)
Launch bullets, hit the target, reduce HP and other functions will be explained in detail in bullets
Switch firing mode
Here, you only need to press the B key to enable and close the script. It is relatively simple and will not be explained
Complete code
/// <summary> ///Guns /// </summary> public class GunDemo : MonoBehaviour { /// <summary> ///Bullet type /// </summary> protected GameObject bullet; /// <summary> ///Layer, which will not be described here for the time being. Select the default in the Inspector /// </summary> public LayerMask mask; /// <summary> ///Magazine capacity /// </summary> private int boxMagazine=20; /// <summary> ///Number of bullets in the current magazine /// </summary> public int currentBullet; /// <summary> ///Total bullets /// </summary> public int allBullet; /// <summary> ///Initialization /// </summary> protected virtual void Start() { //Initialize total bullets allBullet = 100; //Obtain bullet resources bullet = GetResource(); //Initial default single point mode GetComponent<SingleGunDemo>().enabled = true; GetComponent<AutomaticGunDemo>().enabled = false; } /// <summary> ///Fire /// </summary> protected virtual void Firing() { //Prepare the bullet //Determine whether the magazine contains bullets if (currentBullet > 0) { //Create bullet GameObject Bullet = Object.Instantiate(bullet, transform.TransformPoint(Vector3.right), transform.rotation); //Get the script component of the bullet object PlayerBulletDemo playerBullet = Bullet.GetComponent<PlayerBulletDemo>(); //Configure firing direction playerBullet.direction =transform.right; playerBullet.mask = mask; //Fire bullets playerBullet.Firing(); currentBullet--; //Create bullets, play audio, play animation } else { Debug.Log("No Bullet"); //It indicates that there are no bullets and the magazine needs to be changed } } /// <summary> ///Get bullet resource file /// </summary> /// <returns></returns> private GameObject GetResource() { return Resources.Load<GameObject>("GunTest/Bullet/PlayerBullet"); } /// <summary> ///Replace magazine /// </summary> protected void UpdateAmmo() { if (allBullet > 0&¤tBullet<boxMagazine) { int add = boxMagazine - currentBullet; if (add <= allBullet) { allBullet -= add; currentBullet += add; } else { currentBullet += allBullet; allBullet = 0; } } else { Debug.Log("FullorNone"); //It indicates that there are no bullets or the magazine is full } } protected void Update() { //There is no collimation here for the time being. First use the line to indicate the muzzle direction Debug.DrawLine(transform.position,transform.TransformPoint(100*Vector3.right)); if (Input.GetKeyDown(KeyCode.B)) { //Switch mode GetComponent<SingleGunDemo>().enabled = !GetComponent<SingleGunDemo>().enabled; GetComponent<AutomaticGunDemo>().enabled=!GetComponent<AutomaticGunDemo>().enabled; } } }
Single shot mode and continuous shot mode
The only difference is whether to use GetKey or GetKeyDown. It's relatively simple and direct to the code
public class SingleGunDemo : GunDemo { /// <summary> ///Initialization /// </summary> protected override void Start() { base.Start(); } private void Update() { base.Update(); if (Input.GetKeyDown(KeyCode.O)) { base.Firing(); } if (Input.GetKeyDown(KeyCode.R)) { base.UpdateAmmo(); } } }
public class AutomaticGunDemo :GunDemo { /// <summary> ///Initialization /// </summary> protected override void Start() { base.Start(); } private void Update() { base.Update(); if (Input.GetKey(KeyCode.O)) { base.Firing(); } if (Input.GetKeyDown(KeyCode.R)) { base.UpdateAmmo(); } } }
Bullets and player bullets
bullet
Note: when the player creates bullets from the gun, the shooting direction and layer will be configured
Bullets need to calculate the shooting target points of players. The main method is ray detection to obtain the shooting target points
There is no bullet parabola here. Instantaneous shooting is used for the time being.
Ray detection method: physics. Raycast (ray starting point, direction vector, out output object, distance, layer)
The detected target hit is obtained through radiographic testing, and then the target point is assigned to targetPos
public class BulletDemo : MonoBehaviour { /// <summary> ///Layers /// </summary> public LayerMask mask; /// <summary> ///Muzzle orientation /// </summary> [HideInInspector] public Vector3 direction; /// <summary> ///Radiographic object /// </summary> protected RaycastHit hit; /// <summary> ///Hit the target position /// </summary> public Vector3 targetPos; /// <summary> ///Calculate target point /// </summary> protected void BulletHit() { if (Physics.Raycast(this.transform.position, direction, out hit, 100, mask)) { //Detected targetPos = hit.point; } else { targetPos = transform.position + transform.right * 5; } //Create special effects at target points } /// <summary> ///Shooting virtual method /// </summary> public virtual void Firing() { } }
Player bullet
If the player shoots with a gun, he can call the fitting method
The bullet will be teleported to the target point to cause damage through the target obtained (lazy here). The corresponding script component will be obtained through the target detected by ray. HP will be deducted and the object will be destroyed if HP is returned to zero
public class PlayerBulletDemo : BulletDemo { public override void Firing() { BulletHit(); transform.position = targetPos; if (hit.collider!= null) { if (hit.collider.tag == "Enemy")//If it's the enemy { Debug.Log("touch it"); hit.collider.GetComponent<EnemyDemo>().HP -= 10;//Buckle blood if (hit.collider.GetComponent<EnemyDemo>().HP <= 0) { Destroy(hit.collider.gameObject); } DestroyImmediate(this.gameObject); } } } }
Enemy gun
Similar to the player's gun, the bullet will automatically shoot without ray detection. After creation, the bullet will automatically move in the positive direction, and HP will be deducted if it touches the player
Set the attack interval and shoot once every 1.5s
public class EnemyGunDemo : MonoBehaviour { //The enemy has unlimited bullets. The bullets are slow and can be caught by the naked eye public LayerMask mask; private GameObject bullet; private float FiringTime; private void Start() { FiringTime = 0; bullet = GetResources(); } private void Firing() { GameObject Bullet = Object.Instantiate(bullet, transform.TransformPoint(Vector3.right), transform.rotation); } private GameObject GetResources() { return Resources.Load<GameObject>("GunTest/Bullet/EnemyBullet"); } private void Update() { if (FiringTime > 1.5) { Firing(); FiringTime = 0; } else { FiringTime += Time.deltaTime; } } }
Enemy bullet
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>().HP -= 1; //Players deduct blood if (other.GetComponent<PlayerDemo>().HP <= 0) { Destroy(other.gameObject); } } Destroy(this.gameObject); } private void Update() { transform.Translate(0, Time.deltaTime * 5, 0); //Auto destroy in 5 seconds Destroy(this.gameObject, 5); } }
Note: if the bullet model orientation and muzzle orientation are different, remember to adjust the bullet orientation separately
problem
In the above code, whether the magazine should be a separate class. If it is written as above, the single engine and continuous engine do not share a magazine, which is unscientific. Therefore, the magazine should be a separate class