Unity makes mobile fps zombie game


introduce

insert image description here

insert image description here
Use knowledge points such as coroutines, enumerations, animators, and navigation.
Realize movement, gun switching, bomb changing, shooting, zombie tracking, and attacking.


Make a basic UI

Make human blood bars, zombie blood bars, move buttons, reload buttons, shoot buttons, gun cut buttons, and front sights.

insert image description here


Enum controls character movement

insert image description here
Move(Movestate moveState): Control the player's movement according to the incoming movement state. Different moving directions can be selected according to the value of the Movestate enumeration type.
StopMove(): Stop the player's movement and set the movement state to stop state.
MoveForward(): Sets the move state to move forward.
MoveBackward(): Set the moving state to the backward moving state.
MoveLeft(): Set the movement state to move to the left.
MoveRight(): Set the movement state to the right movement state.
Button_Move(string state): Set the move state through the incoming string parameter. Use System.Enum.Parse to parse the string into a value of the Movestate enumeration type.
Button_Drag(): Handle the operation of mouse dragging, obtain the movement amount of the mouse in the horizontal and vertical directions, and call the Rotatingplay() and RotatingCamera() functions to rotate the player and the camera.
Rotatingplay(float x): Rotate the player around the Y axis.
RotatingCamera(float y): Rotate the camera around the X axis, but limit the rotation angle of the camera to ensure that the camera will not rotate beyond a certain angle.
OnTriggerEnter(Collider other): Called when the trigger collides with other objects, outputting debugging information.

using System.Collections; // 引用命名空间 System.Collections
using System.Collections.Generic; // 引用命名空间 System.Collections.Generic
using UnityEngine; // 引用命名空间 UnityEngine

public class player : MonoBehaviour // 定义一个名为 player 的类,并继承自 MonoBehaviour 类
{
    
    
	public enum Movestate{
    
    stop,forward,backward,left,right} // 定义一个名为 Movestate 的枚举类型,表示角色的移动状态

	public Movestate currentState; // 定义一个名为 currentState 的变量,表示当前角色的移动状态
	public float movespeed=1; // 定义一个名为 movespeed 的变量,表示角色的移动速度
	public CharacterController ch; // 定义一个名为 ch 的 CharacterController 变量,用于控制角色移动
	public Transform camtrans; // 定义一个名为 camtrans 的 Transform 变量,用于控制相机旋转

    void Start() // Start 方法,在第一帧开始前执行
    {
    
    
	    ch=GetComponent<CharacterController>(); // 获取角色的 CharacterController 组件,并赋值给 ch 变量
	    camtrans=transform.Find("Main Camera"); // 查找名为 "Main Camera" 的子对象,并将其 Transform 组件赋值给 camtrans 变量
    }

    void Update() // Update 方法,在每一帧更新时执行
    {
    
    
	    Move(currentState); // 调用 Move 方法,传入 currentState 参数
    }
	    
	public void Move(Movestate moveState){
    
     // 定义一个名为 Move 的公共方法,用于控制角色的移动
		
		switch(moveState){
    
     // 根据 moveState 参数的不同,执行不同的操作
		case Movestate.stop: // 如果 moveState 等于 stop,则执行下面的代码
			break; // 跳出 switch 语句
		case Movestate.forward: // 如果 moveState 等于 forward,则执行下面的代码
			//transform.Translate(transform.forward*Time.deltaTime*movespeed); // 使用 Transform 的 Translate 方法,向前移动角色
			ch.SimpleMove(transform.forward*movespeed); // 使用 CharacterController 的 SimpleMove 方法,向前移动角色
			break; // 跳出 switch 语句
		case Movestate.backward: // 如果 moveState 等于 backward,则执行下面的代码
			//transform.Translate(-transform.forward*Time.deltaTime*movespeed); // 使用 Transform 的 Translate 方法,向后移动角色
			ch.SimpleMove(-transform.forward*movespeed); // 使用 CharacterController 的 SimpleMove 方法,向后移动角色
			break; // 跳出 switch 语句
		case Movestate.left: // 如果 moveState 等于 left,则执行下面的代码
			//transform.Translate(-transform.right*Time.deltaTime*movespeed); // 使用 Transform 的 Translate 方法,向左移动角色
			ch.SimpleMove(-transform.right*movespeed); // 使用 CharacterController 的 SimpleMove 方法,向左移动角色
			break; // 跳出 switch 语句
		case Movestate.right: // 如果 moveState 等于 right,则执行下面的代码
			//transform.Translate(transform.right*Time.deltaTime*movespeed); // 使用 Transform 的 Translate 方法,向右移动角色
			ch.SimpleMove(transform.right*movespeed); // 使用 CharacterController 的 SimpleMove 方法,向右移动角色
			break; // 跳出 switch 语句
		default: // 如果 moveState 不等于以上任何一个值,则执行下面的代码
			break; // 跳出 switch 语句
		}
	}
	
	public void StopMove(){
    
     // 定义一个名为 StopMove 的公共方法,用于停止角色的移动
		
		currentState=Movestate.stop; // 将 currentState 变量的值设为 stop
	}
	
	public void MoveForward(){
    
     // 定义一个名为 MoveForward 的公共方法,用于向前移动角色
		
		currentState=Movestate.forward; // 将 currentState 变量的值设为 forward
	}
	
	public void MoveBackward(){
    
     // 定义一个名为 MoveBackward 的公共方法,用于向后移动角色
		
		currentState=Movestate.backward; // 将 currentState 变量的值设为 backward
	}
	
	public void MoveLeft(){
    
     // 定义一个名为 MoveLeft 的公共方法,用于向左移动角色
		
		currentState=Movestate.left; // 将 currentState 变量的值设为 left
	}
	
	public void MoveRight(){
    
     // 定义一个名为 MoveRight 的公共方法,用于向右移动角色
		
		currentState=Movestate.right; // 将 currentState 变量的值设为 right
	}
	
	public void Button_Move(string state){
    
     // 定义一个名为 Button_Move 的公共方法,用于响应移动按钮的点击事件,并根据点击事件的参数改变角色的移动状态
		
		var e=System.Enum.Parse(typeof(player.Movestate),state); // 将字符串类型的 state 参数转换为 Movestate 枚举类型,并赋值给 e 变量
		currentState=(player.Movestate)e; // 将 e 变量的值赋给 currentState 变量,从而改变角色的移动状态
	}
	
	public void Button_Drag(){
    
     // 定义一个名为 Button_Drag 的公共方法,用于响应拖拽事件
		
		float x=Input.GetAxis("Mouse X"); // 获取鼠标水平方向的移动距离
		float y=Input.GetAxis("Mouse Y"); // 获取鼠标垂直方向的移动距离
		Rotatingplay(x); // 调用 Rotatingplay 方法,传入 x 参数,用于旋转角色
		RotatingCamera(y); // 调用 RotatingCamera 方法,传入 y 参数,用于旋转相机
	}
	
	private void Rotatingplay(float x){
    
     // 定义一个名为 Rotatingplay 的私有方法,用于旋转角色
		
		transform.Rotate(0,x,0); // 使用 Transform 的 Rotate 方法,绕 y 轴旋转角色
	}
	
	private void RotatingCamera(float y){
    
     // 定义一个名为 RotatingCamera 的私有方法,用于旋转相机
		
		if ((-45< camtrans.rotation.x)&&(camtrans.rotation.x<45)) // 如果相机的 x 轴旋转角度在 -45 度到 45 度之间
		{
    
    
			camtrans.Rotate(-y,0,0); // 使用 Transform 的 Rotate 方法,绕 x 轴旋转相机
		}
	}
	
	private void OnTriggerEnter(Collider other){
    
     // 定义一个名为 OnTriggerEnter 的私有方法,用于响应角色进入触发器的事件,并输出调试信息
		
		Debug.Log("bang"); // 在控制台输出 "bang" 字符串
	}
}

Cut the gun, set the sound effect, set the bullet power, set the bullet time interval, change the bullet

insert image description here

Button_select(): Select different firearms.
Button_Fire(): Fire, play the corresponding sound effect according to the currently used firearm, and call the castray() method to detect whether the zombie is hit.
pistolfire(): The firing logic of the pistol.
tommyfire(): The firing logic of the submachine gun.
riflefire(): The firing logic of the rifle.
Button_stopfire(): Stop continuous fire (only submachine guns have this function).
showbulletsinfo(): Displays the number of bullets for the currently used firearm.
showtotalbullets(): Displays the total ammo count for all firearms.
Canfire(): Set the canfire variable to true, indicating that it can fire.
Button_Reload(): Reloads the currently used firearm.
Reload(): Reloads the specified firearm.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

// 定义Start1类,继承MonoBehaviour类
public class Start1 : MonoBehaviour
{
    
    
// 声明枚举类型Guntype,包含pistol、tommy、rifle三种枪支类型
public enum Guntype{
    
    pistol, tommy, rifle}


// 当前使用的枪支类型
public Guntype usinggun;

// 枪支声音源和声音片段数组
public AudioSource gunsource;
public AudioClip[ ] gunclip;

// 是否可以开火的标志位、不同枪支的冷却时间、当前使用的枪支弹药数、弹匣容量、总弹药数和枪支伤害值
public bool canfire = true;
public float []cooltime;
public int[] usinggunbulets;
public int[] clapbullets;
public int[] totalbullets;
public float[] gundamage;

// 显示弹药数的文本和总弹药数文本数组、血液特效预制体
public Text showbullets;
public Text[] totalbulletstext;
public GameObject bloodzone;

// Start方法,初始化当前使用的枪支弹药数
private void Start(){
    
    
    usinggunbulets[0] = clapbullets[0];
    usinggunbulets[1] = clapbullets[1];
    usinggunbulets[2] = clapbullets[2];

    // 显示总弹药数
    showtotalbullets();
}

// Update方法,每帧执行一次
// ...

// 开始游戏按钮响应函数
public void startgame()
{
    
    
    // 切换到游戏场景
    SceneManager.LoadScene("游戏场景");
}

// 退出游戏按钮响应函数
public void exitgame(){
    
    
    // 退出应用程序
    Application.Quit();
}

// 开火按钮响应函数
public void Button_Fire(){
    
    
    // 根据当前使用的枪支类型进行开火操作
    switch (usinggun){
    
    
        case Guntype.pistol:
            pistolfire();
            break;
        case Guntype.tommy:
            tommyfire();
            break;
        case Guntype.rifle:
            riflefire();
            break;
    }
}

// 手枪开火函数
private void pistolfire(){
    
    
    // 如果可以开火且当前弹药数大于0
    if (canfire){
    
    
        if (usinggunbulets[(int)Guntype.pistol] > 0){
    
    
            // 播放枪声音效,设置开火标志位为false,延迟一段时间后设置为true,减少当前弹药数,显示弹药数信息,进行射线检测
            gunsource.clip = gunclip[0];
            gunsource.Play();
            canfire = false;
            Invoke("Canfire", cooltime[(int)Guntype.pistol]);
            usinggunbulets[(int)Guntype.pistol]--;
            showbulletsinfo((int)Guntype.pistol);
            castray();
        }
    }
}

// 冲锋枪开火函数
private void tommyfire(){
    
    
    if (canfire){
    
    
        // 播放枪声音效,延迟一段时间后再次调用tommyfire函数进行连发,减少当前弹药数,显示弹药数信息,进行射线检测
        gunsource.clip = gunclip[1];
        gunsource.Play();
        Invoke("tommyfire", cooltime[(int)Guntype.tommy]);
        usinggunbulets[(int)Guntype.tommy]--;
        showbulletsinfo((int)Guntype.tommy);
        castray();
    }
}

// 停止射击按钮响应函数
public void Button_stopfire(){
    
    
    if (usinggun == Guntype.tommy){
    
    
        // 如果当前使用的是冲锋枪,则设置开火标志位为false,延迟一段时间后设置为true
        canfire = false;
        Invoke("Canfire", 0.3f);
    }
}

// 步枪开火函数
private void riflefire(){
    
    
if (canfire){
    
    
if (usinggunbulets[(int)Guntype.rifle] == 0)
return;
// 播放枪声音效,设置开火标志位为false,延迟一段时间后设置为true,减少当前弹药数,显示弹药数信息,进行射线检测
gunsource.clip = gunclip[2];
gunsource.Play();
canfire = false;
Invoke("Canfire", cooltime[(int)Guntype.rifle]);
usinggunbulets[(int)Guntype.rifle]--;
showbulletsinfo((int)Guntype.rifle);
castray();
}
}

clojure
Copy
// 选择枪支按钮响应函数
public void Button_select(int gunid){
    
    
    // 根据选择的枪支id设置当前使用的枪支类型,并显示弹药数信息
    switch(gunid){
    
    
        case 0:
            usinggun = Guntype.pistol;
            showbulletsinfo((int)Guntype.pistol);
            break;
        case 1:
            usinggun = Guntype.tommy;
            showbulletsinfo((int)Guntype.tommy);
            break;
        case 2:
            usinggun = Guntype.rifle;
            showbulletsinfo((int)Guntype.rifle);
            break;
        default :
            break;
    }
}

// 显示当前枪支弹药数信息
private void showbulletsinfo(int gunid){
    
    
    showbullets.text = usinggunbulets[gunid].ToString() + "/" + clapbullets[gunid];
}

// 显示总弹药数信息
private void showtotalbullets(){
    
    
    totalbulletstext[0].text = totalbullets[0].ToString();
    totalbulletstext[1].text = totalbullets[1].ToString();
    totalbulletstext[2].text = totalbullets[2].ToString();
}

// 设置开火标志位为true的函数
private void Canfire(){
    
    
    canfire = true;
}

// 重新装填按钮响应函数
public void Button_Reload(){
    
    
    // 根据当前使用的枪支id执行重新装填操作
    Reload((int)usinggun);
}

// 重新装填函数
public void Reload(int gunid){
    
    
    // 计算需要重新装填的弹药数,如果总弹药数足够,则重新装填弹药,否则只装填剩余的总弹药数,同时更新显示的弹药数信息和总弹药数信息
    int cout = clapbullets[gunid] - usinggunbulets[gunid];
    if (cout <= totalbullets[gunid]){
    
    
        usinggunbulets[gunid] = clapbullets[gunid];
        totalbullets[gunid] -= cout;
    }
    else{
    
    
        totalbullets[gunid] += totalbullets[gunid];
        totalbullets[gunid] = 0;
    }
    showbulletsinfo(gunid);
    showtotalbullets();
}

// 射线检测函数,检测是否射中了敌人
private void castray(){
    
    
    Vector2 v = new Vector2 (Screen.width/2, Screen.height/2);
    RaycastHit hit;
    if (Physics.Raycast(Camera.main.ScreenPointToRay(v), out hit)){
    
    
        if (hit.transform.root.CompareTag("zombie")){
    
    
            // 如果射中了敌人,则播放血液特效并造成伤害
            bloodzone.SetActive(true);
            var zombie = hit.transform.root.GetComponent<health>();
            if (hit.transform.name == "Bip001 Pelvis"){
    
    
                zombie.getdamage(gundamage[(int)usinggun]);
            }
            else{
    
    
                zombie.getdamage(gundamage[(int)usinggun] * 3);
            }
        }
        else{
    
    
            // 如果没有射中敌人,则隐藏血液特效
            bloodzone.SetActive(false);
        }
    }
}
}

front sight control shooting

insert image description here

private void castray(){
    
    
    Vector2 v = new Vector2(Screen.width/2,Screen.height/2); // 创建一个屏幕中心点的 2D 向量 v
    RaycastHit hit; // 创建一个 RaycastHit 变量用于接收射线的碰撞结果
    
    if (Physics.Raycast(Camera.main.ScreenPointToRay(v), out hit)) // 从相机发出一条射线,通过屏幕中心点 v,检测是否与物体发生碰撞,并将结果保存在 hit 变量中
    {
    
    
        if (hit.transform.root.CompareTag("zombie")) // 如果射线碰撞的物体的根节点标签是 "zombie"
        {
    
    
            bloodzone.SetActive(true); // 激活一个名为 "bloodzone" 的游戏对象

            var zombie = hit.transform.root.GetComponent<health>(); // 获取射线碰撞物体的根节点上的 health 组件,赋值给 zombie 变量

            if (hit.transform.name == "Bip001 Pelvis") // 如果射线碰撞到的物体的名字是 "Bip001 Pelvis"
            {
    
    
                zombie.getdamage(gundamage[(int)usinggun]); // 调用 zombie 的 getdamage 方法,并传入 usinggun 变量对应的 gundamage 值作为参数
            }
            else
            {
    
    
                zombie.getdamage(gundamage[(int)usinggun] * 3); // 否则,调用 zombie 的 getdamage 方法,并传入 usinggun 变量对应的 gundamage 值乘以 3 作为参数
            }
        }
        else
        {
    
    
            bloodzone.SetActive(false); // 如果射线碰撞的物体不是 "zombie",则关闭 "bloodzone" 对象
        }
    }
}

The function of this code is to perform ray detection to determine whether the ray collides with the object named "zombie". If there is a collision, activate a game object named "bloodzone" and call the corresponding damage method based on where the ray collided and the name of the object. If there is no collision or the object the ray collides with is not a "zombie", close the "bloodzone" object.


Zombie animation, blood bar

insert image description here

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AI;

public class health : MonoBehaviour
{
    
    
    public float hitpot;  // 角色的当前生命值
    public float maxpot = 100f;  // 角色的最大生命值
    public Slider blood;  // 血条UI元素
    public player player;  // player脚本的引用
    public zombie zom;  // zombie脚本的引用

    public Sprite headcon;  // 头像图标的Sprite
    public Image headimage;  // 头像UI元素的Image组件

    void Start()
    {
    
    
        hitpot = maxpot;  // 设置初始生命值为最大生命值
        blood.maxValue = maxpot;  // 设置血条的最大值为最大生命值
        blood.value = maxpot;  // 设置血条的当前值为最大生命值
        blood.gameObject.SetActive(false);  // 隐藏血条
        headimage.gameObject.SetActive(false);  // 隐藏头像
    }

    void Update()
    {
    
    
        if (zom.agent.enabled)
        {
    
    
            zom.agent.SetDestination(zom.player.position);  // 设置僵尸的目标位置为玩家的位置
        }
        if (Vector3.Distance(zom.transform.position, zom.player.position) <= 1.8)
        {
    
    
            zom.zombieanimator.SetBool("attack", true);  // 设置僵尸的攻击动画为true
        }
        else
        {
    
    
            zom.zombieanimator.SetBool("attack", false);  // 设置僵尸的攻击动画为false
            zom.zombieanimator.SetBool("walk", true);  // 设置僵尸的行走动画为true
        }
    }

    public void getdamage(float dam)
    {
    
    
        blood.gameObject.SetActive(true);  // 显示血条
        headimage.gameObject.SetActive(true);  // 显示头像

        headimage.sprite = headcon;  // 设置头像图标为指定的Sprite

        hitpot -= dam;  // 减去受到的伤害值
        blood.value = hitpot;  // 更新血条的当前值为剩余生命值

        if (hitpot <= 0)
        {
    
    
            GetComponent<Animator>().SetBool("dead", true);  // 设置角色的死亡动画为true
            zom.agent.enabled = false;  // 禁用僵尸的导航代理
        }
    }
}


set navigation

insert image description here

 void Update()
    {
    
    
        if (zom.agent.enabled)
        {
    
    
            zom.agent.SetDestination(zom.player.position);  // 设置僵尸的目标位置为玩家的位置
        }
        if (Vector3.Distance(zom.transform.position, zom.player.position) <= 1.8)
        {
    
    
            zom.zombieanimator.SetBool("attack", true);  // 设置僵尸的攻击动画为true
        }
        else
        {
    
    
            zom.zombieanimator.SetBool("attack", false);  // 设置僵尸的攻击动画为false
            zom.zombieanimator.SetBool("walk", true);  // 设置僵尸的行走动画为true
        }
    }

Guess you like

Origin blog.csdn.net/qq_20179331/article/details/131449301