Unity makes ghost hunter shooting game


introduce

insert image description here

insert image description here

The player's mouse controls the direction of the character.
The player's mouse clicks to control the end point of the light emission.
The player is hurt and the screen flashes red.
There are three monster spawn points.
The player shoots and kills the enemy to get points

Key technologies: animator, screen ray detection is responsible for turning, muzzle particle effects, muzzle lighting, screen ray detection is responsible for emitting light, line renderer, lerp function camera movement, color lerp gradient


The character runs and rotates towards the position clicked by the mouse

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;



public class PlayerMovement : MonoBehaviour
{
    
    
	public float speed = 6f;            // 玩家移动速度

	private Vector3 movement;           // 玩家的移动方向
	private Animator playerAC;          // 玩家的动画控制器
	private Rigidbody playerRigidbody; // 玩家的刚体组件

	LayerMask floorMask;


	// 初始化
	void Start()
	{
    
    
		// 获取动画控制器和刚体组件
		playerAC = GetComponent<Animator>();
		playerRigidbody = GetComponent<Rigidbody>();
		
		floorMask = LayerMask.GetMask("floor");
	}

	// 固定时问见新
	void FixedUpdate()
	{
    
    
		float h = Input.GetAxisRaw("Horizontal");
		float v = Input.GetAxisRaw("Vertical");
		// 移动 横向 和纵向
		Move(h, v);
		// 检测是否在移动,播放相应动画
		Animating(h, v);
		turning();
	}

	// 检测是否在移动,播放相应动画
	void Animating(float h, float v)
	{
    
    
		// 只有h不等于0或者v不等于0才应该是移动
		bool walking = h != 0f || v != 0f;
		playerAC.SetBool("iswalking", walking);
	}

	// 移动
	void Move(float h, float v)
	{
    
    
		// 设置移动的方向向量
		movement.Set(h, 0f, v);
		movement = movement.normalized * speed * Time.deltaTime;
		// 使用Rigidbody组件移动玩家
		playerRigidbody.MovePosition(transform.position + movement);
	}
	
	
	
	void turning()
	{
    
    
		Ray cameraRay = Camera.main.ScreenPointToRay(Input.mousePosition);
		RaycastHit cameraHit;
		if (Physics.Raycast(cameraRay, out cameraHit, 100f, floorMask))
		{
    
    
			Vector3 playerToMouse = cameraHit.point - transform.position;
			playerToMouse.y = 0f;
			Quaternion newQuaternion = Quaternion.LookRotation(playerToMouse);
			playerRigidbody.MoveRotation(newQuaternion);
		}
	}

}


void Start()

This function is called when the script starts running.
It gets the animation controller (playerAC) and rigidbody component (playerRigidbody).
The mask (floorMask) of the ground layer is set.
void FixedUpdate()

This function is called at regular intervals for physics related updates.
Get the input values ​​for the horizontal (h) and vertical (v) axes.
Call the Move(h, v) function to move.
Call the Animating(h, v) function to play the corresponding animation according to the moving state.
Call the turning() function to rotate the player character according to the mouse position.
void Animating(float h, float v)

Detect whether it is moving, and set animation parameters according to the moving state.
When h or v is not equal to 0, set the iswalking Boolean parameter to true, indicating that it is moving.
void Move(float h, float v)

Sets the movement direction vector movement.
Multiply the velocity and time interval by the normalized movement direction vector to get the movement displacement vector.
Use the rigid body component (playerRigidbody) to move the player's position.
void turning()

Creates a ray (cameraRay) from the main camera through the mouse position.
Use the ray and the ground layer mask (floorMask) for collision detection, and get the collision result (cameraHit).
Computes the vector where the player character points to the mouse (playerToMouse).
Set the y component of the vector to 0 to keep the rotation on the horizontal plane.
Creates a new Quaternion (newQuaternion) representing the target direction for the player character to rotate.
Use the rigidbody component (playerRigidbody) to smoothly interpolate the rotation of the player character.

insert image description here


The lerp function allows the camera to follow smoothly

using UnityEngine;
using System.Collections;

public class CameraFollow : MonoBehaviour {
    
    
	public Transform target;
	public float smoothing = 5f;
	Vector3 offset;

	// Use this for initialization
	void Start () {
    
    
		offset = transform.position - target.position;
	}
    
	// Update is called once per frame
	void Update () {
    
    
		Vector3 pos = target.position + offset;
		transform.position = Vector3.Lerp(transform.position, pos, smoothing * Time.deltaTime);
	}
}

It smoothly moves the position of the camera to the position of the target object by the Lerp method.
First, calculate the new camera position pos, which is the position of the target object plus the initial offset offset.
Then, use the Vector3.Lerp method to perform linear interpolation between the camera's current position (transform.position) and the new position pos to achieve a smooth transition.
The speed of the interpolation is controlled by the smoothing variable and Time.deltaTime.


enemy navigation

using UnityEngine;
using UnityEngine.AI;
using System.Collections;


public class EnemyMovement : MonoBehaviour {
    
    
	 Transform player; // 目标位置:英雄
	NavMeshAgent nav; // 导航代理

	EnemyHealth enemyHealth;
	Playerhealth playerHealth;

	// Use this for initialization
	void Start () {
    
    
		player = GameObject.FindGameObjectWithTag("Player").transform;
		nav = GetComponent<NavMeshAgent>();
		enemyHealth=GetComponent<EnemyHealth>();
		playerHealth=player.GetComponent<Playerhealth>();
	}

	// Update is called once per frame
	void Update () {
    
    
		if(enemyHealth.currentHealth > 0 && playerHealth.currentHealth > 0)
		nav.SetDestination(player.position);
	
	
		else{
    
    
		
			nav.enabled=false;
		
		}
}
}

Start() function: initialize the position and navigation agent of the enemy character, and get the health components of the enemy character and the hero character.
Update() function: If the health status of both the enemy and the hero character is greater than 0, use the navigation agent to move the enemy character to the position of the hero character; otherwise, disable the navigation agent to stop the movement of the enemy character.


enemy attack

using System.Collections;
using UnityEngine.UI;
using UnityEngine;

public class EnemyAttack : MonoBehaviour {
    
    

	
	
	Playerhealth playerHealth;
	
	GameObject player;
	public int attack=10;
	public float attackBetweenTime=0.5f;
	float timer;
	

	
	public AudioSource playerAudio;

	bool inRange;


	void Start () {
    
    
		playerAudio = GetComponent<AudioSource>();
		
		player = GameObject.FindGameObjectWithTag("Player");
		playerHealth = player.GetComponent<Playerhealth>();
		
		
	}

	void Update () {
    
    
		// 如果收到伤害,显示受伤闪烁效果
	
		
		
			timer+=Time.deltaTime;

		// 如果在攻击范围内,执行攻击逻辑
		if (timer > attackBetweenTime&&inRange)
		{
    
    
			Attack();
		}
	}

	void OnTriggerEnter(Collider other) {
    
    
		// 如果检测到玩家进入攻击范围,设置 inRange 标志为 true
		if (other.gameObject == player) {
    
    
			inRange = true;
		}
	}

	void OnTriggerExit(Collider other) {
    
    
		// 如果检测到玩家离开攻击范围,设置 inRange 标志为 fals
		if (other.gameObject == player) {
    
    
			inRange = false;
		}
	}

	void Attack() {
    
    
		
		
		timer=0;
		if (playerHealth.currentHealth > 0) {
    
    
			
			playerHealth.OnAttack(attack);
			
		}
	}

	

	void Die() {
    
    
		// 在此添加死亡的相关逻辑,例如播放死亡动画、停止移动等
	}
}

Start() function: Get the player's health component and game object, and initialize the audio source.
Update() function: detect the timer and execute the attack logic within the attack range.
OnTriggerEnter(Collider other) function: When it is detected that the player enters the attack range, set the inRange flag to true.
OnTriggerExit(Collider other) function: When it is detected that the player leaves the attack range, set the inRange flag to false.
Attack() function: execute the attack logic, reset the timer, check whether the player is alive, and then attack the player.


Shoot bullets at enemies

using UnityEngine;
using System.Collections;

public class PlayerShooting : MonoBehaviour
{
    
    
	AudioSource gunAudio;
	Light gunLight;
	LineRenderer  gunLine;
	
	Ray gunRay;
	RaycastHit gunHit;
	public LayerMask layerMask;
	
	ParticleSystem gunParticies;
	
	float timer;
	public int atk=20;

	void Start()
	{
    
    
		
		gunAudio = GetComponent<AudioSource>();
		gunLight = GetComponent<Light>();
		gunLine = GetComponent<LineRenderer>();
		
		//	layerMask = LayerMask.GetMask("shoot");
		gunParticies=GetComponent<ParticleSystem>();
		
	}

	void Update()
	{
    
    
		
		timer+=Time.deltaTime;
		if (Input.GetButtonDown("Fire1"))
		{
    
    
			shoot();
		}
		
		if (timer>0.1f)
		{
    
    
			timer=0;
			gunLine.enabled=false;
			gunLight.enabled=false;
		}
		
		
		
	}

	void shoot() {
    
    
		//鼓
		gunAudio.Play();
		//光源
		gunLight.enabled = true;
		//枪
		gunLine.enabled = true;
		gunRay.origin = transform.position;
		//gunRay.direction = transform.forward;
		gunRay.direction = transform.TransformDirection(Vector3.forward);

		//检的第一个点
		gunLine.SetPosition(0, transform.position);
		
		gunParticies.Stop();
		gunParticies.Play();
		
		

		//判断是否击中敌人
		if (Physics.Raycast(gunRay, out gunHit, 100f, layerMask)) {
    
    
			
			EnemyHealth enemyHealth = gunHit.collider.GetComponent<EnemyHealth>();
			if (enemyHealth != null)
			{
    
    
				Debug.Log("打到Zombunny");
				// 在这里处理击中敌人的逻辑
				enemyHealth.OnAttack(atk);
			}
			
			gunLine.SetPosition(1, gunHit.point);
			//在这里处理击中敌人的逻辑
		}
		else {
    
    
			gunLine.SetPosition(1, transform.position + gunRay.direction* 100f);
		}
	
	}
	

}

Start() function: Initialize the gun sound audio source, gun light source, ray renderer and particle system.

Update() function: update the timer and trigger the shooting logic when the "Fire1" key is pressed.

shoot() function: handle shooting logic, play gun sound effects, enable gun light sources and ray renderers, and emit rays for hit detection. If the enemy is hit, handle the enemy damage logic and display the hit point on the ray. If no enemies are hit, show the end of the range on the ray.

insert image description here


player health

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

public class Playerhealth : MonoBehaviour
{
    
    
 public int startingHealth = 100;
	public int currentHealth;
	
	
	public Slider slider;
	public Image hurtImage;
	bool isDamage;
	private AudioSource playerAudio;
	public AudioClip deadclip;

	public Color flashColor = new Color(1f, 0f, 0f, 1f);
	public Color clearColor = Color.clear;
	
	Animator anim;
	PlayerMovement playermove;


	// Use this for initialization
	void Start()
	{
    
    
		playerAudio = GetComponent<AudioSource>();
		currentHealth = startingHealth;
		anim=GetComponent<Animator>();
		playermove=GetComponent<PlayerMovement>();
	}

	// Update is called once per frame
	void Update()
	{
    
    

		if (isDamage)
			hurtImage.color = flashColor;
	
		else
		{
    
    
			hurtImage.color = Color.Lerp(hurtImage.color,clearColor,Time.deltaTime*5);
		}
			
		
		isDamage = false;
		// 检查当前生命值是否小于等于 0
		
	}

	

	// 受伤方法
	public void OnAttack(int damage)
	{
    
    
		
		isDamage=true;
		// 减少生命值
		currentHealth -= damage;

		// 更新滑动条的值
		slider.value = currentHealth;

		// 播放受伤音效
		playerAudio.Play();
		
		if (currentHealth <= 0)
		{
    
    
			// 如果生命值小于等于 0,则触发死亡事件
			Die();
		}
	}

	// 死亡方法
	void Die()
	{
    
    
		playerAudio.clip=deadclip;
		playerAudio.Play();
		anim.SetTrigger("die");
		playermove.enabled=false;
		
	}
	
}

Start() function: Initialize the player's health, audio source, animation components and movement components.

Update() function: update the color of the injured image, gradually restore it to transparent, and reset the injured flag.

OnAttack(int damage) function: handle the logic when the player is attacked, reduce the life value, update the value of the slider, play the injury sound effect, and trigger the death logic when the life value is less than or equal to 0.

Die() function: handle the logic when the player dies, play the death sound, trigger the death animation, and disable the moving component.

insert image description here


enemy health

using UnityEngine;
using UnityEngine.AI;
using System.Collections;

public class EnemyHealth : MonoBehaviour
{
    
    
	// 初始血量
	public int startingHealth = 50;
	// 当前血量
	public int currentHealth;
	// 敌人音频源
	AudioSource enemyAudioSource;
	public AudioClip enermyclip;
	bool isdie;
	
	Animator	 anim;

	// 初始化
	void Start()
	{
    
    
		currentHealth = startingHealth;
		enemyAudioSource = GetComponent<AudioSource>();
		anim=GetComponent<Animator>();
		
	}

	// 更新方法,每帧调用一次
	void Update()
	{
    
    
        
	}

	// 受伤方法
	public void OnAttack(int damage)
	{
    
    
		// 减少血量
		currentHealth -= damage;
		// 播放音效
		enemyAudioSource.Play();
		if (currentHealth<0&&!isdie)
		{
    
    
			Dead();
		}
	}
	
	void Dead(){
    
    
		isdie =true;
		anim.SetTrigger("dead");
		gameObject.GetComponent<NavMeshAgent>().enabled = false;
		gameObject.GetComponent<EnemyMovement>().enabled = false;
		enemyAudioSource.clip=enermyclip;
		enemyAudioSource.Play();
		Destroy(this.gameObject,1.1f);	
		ScoreManager.score+=10;
	}
}

Start() function: Initialize the enemy's blood volume, audio source and animation components.

OnAttack(int damage) function: handle the logic when the enemy is attacked, reduce the blood volume, play sound effects, and execute the death logic when the blood volume is zero.

Dead() function: handle the logic when the enemy dies, trigger the death animation, disable the navigation agent and enemy movement components, play the death sound effect, destroy the enemy game object after a certain period of time, and increase the score.


score display

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class ScoreManager : MonoBehaviour
{
    
    
	public static int score;
	Text text;

	void Start()
	{
    
    
		text = GetComponent<Text>();
	}

	void Update()
	{
    
    
		text.text = "SCORE: " + score;
	}
}


monster spawner

using UnityEngine;
using System.Collections;

public class GameOverManager : MonoBehaviour {
    
    
	public Playerhealth playerHealth;
	Animator anim;
	public GameObject PLAYER;

	// Use this for initialization
	void Start () {
    
    
		anim = GetComponent<Animator>();
		playerHealth=PLAYER.GetComponent<Playerhealth>();
	}

	// Update is called once per frame
	void Update () {
    
    
		if(playerHealth.currentHealth <= 0) {
    
    
			anim.SetTrigger("GameOver");
		}
	}
}

Add multiple scripts to the object and put in different prefabs.

insert image description here
insert image description here


game over animation

insert image description here
insert image description here






Guess you like

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