Unity がゴースト ハンター シューティング ゲームを作成


導入

ここに画像の説明を挿入

ここに画像の説明を挿入

プレイヤーのマウスでキャラクターの方向を制御します
プレイヤーのマウスをクリックして発光の終点を制御します
プレイヤーは傷つき、画面が赤く点滅します
モンスターのスポーンポイントは 3 つあります
プレイヤーは敵を撃ち殺して取得しますポイント

主要なテクノロジー: アニメーター、スクリーン レイ検出は回転を担当し、銃口粒子効果、銃口照明、スクリーン レイ検出は発光を担当、ライン レンダラー、lerp 機能のカメラの動き、カラー lerp グラデーション


マウスをクリックした位置に向かってキャラクターが走り、回転します

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()

この関数は、スクリプトの実行開始時に呼び出されます。
アニメーション コントローラー (playerAC) と剛体コンポーネント (playerRigidbody) を取得します。
グランドレイヤーのマスク(floorMask)を設定します。
voidFixedUpdate()

この関数は、物理関連の更新のために定期的に呼び出されます。
水平軸 (h) と垂直軸 (v) の入力値を取得します。
移動するには、Move(h, v) 関数を呼び出します。
Animating(h, v) 関数を呼び出して、移動状態に応じて対応するアニメーションを再生します。
Turning() 関数を呼び出して、マウスの位置に応じてプレイヤー キャラクターを回転させます。
void アニメーション(float h, float v)

動いているかどうかを検出し、動きの状態に応じてアニメーションパラメータを設定します。
h または v が 0 に等しくない場合は、iswalking Boolean パラメーターを true に設定し、移動していることを示します。
void Move(float h, float v)

移動方向ベクトルの移動を設定します。
速度と時間間隔に正規化された移動方向ベクトルを乗算して、移動変位ベクトルを取得します。
剛体コンポーネント (playerRigidbody) を使用して、プレーヤーの位置を移動します。
ボイドターニング()

メインカメラからマウスの位置を通る光線 (cameraRay) を作成します。
衝突検出にはレイとグランド レイヤ マスク (floorMask) を使用し、衝突結果 (cameraHit) を取得します。
プレイヤー キャラクターがマウスを指すベクトル (playerToMouse) を計算します。
水平面上での回転を維持するには、ベクトルの y コンポーネントを 0 に設定します。
プレイヤー キャラクターが回転するターゲット方向を表す新しいクォータニオン (newQuaternion) を作成します。
Rigidbody コンポーネント (playerRigidbody) を使用して、プレイヤー キャラクターの回転をスムーズに補間します。

ここに画像の説明を挿入


lerp機能によりカメラがスムーズに追従します

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);
	}
}

Lerp法によりカメラの位置を対象物体の位置に滑らかに移動させます。
まず、新しいカメラ位置 pos を計算します。これは、ターゲット オブジェクトの位置に初期オフセット offset を加えたものです。
次に、Vector3.Lerp メソッドを使用して、カメラの現在位置 (transform.position) と新しい位置 pos の間で線形補間を実行し、スムーズな遷移を実現します。
補間の速度は、平滑化変数と Time.deltaTime によって制御されます。


敵のナビゲーション

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() 関数: 敵キャラクターの位置およびナビゲーション エージェントを初期化し、敵キャラクターとヒーロー キャラクターの健康コンポーネントを取得します。
Update() 関数: 敵とヒーロー キャラクターの健康状態が 0 より大きい場合は、ナビゲーション エージェントを使用して敵キャラクターをヒーロー キャラクターの位置に移動します。そうでない場合は、ナビゲーション エージェントを無効にして敵の移動を停止します。敵キャラクター。


敵の攻撃

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() 関数: プレーヤーのヘルス コンポーネントとゲーム オブジェクトを取得し、オーディオ ソースを初期化します。
Update()関数:タイマーを検出し、攻撃範囲内で攻撃ロジックを実行します。
OnTriggerEnter(Collider other)関数:プレイヤーが攻撃範囲に入ったことを検知すると、inRangeフラグをtrueに設定します。
OnTriggerExit(Collider other)関数: プレイヤーが攻撃範囲から外れたことが検出された場合、inRangeフラグをfalseに設定します。
Attack() 関数: 攻撃ロジックを実行し、タイマーをリセットし、プレイヤーが生存しているかどうかを確認してから、プレイヤーを攻撃します。


敵に弾を撃ち込む

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() 関数: 銃の音のオーディオ ソース、銃の光源、レイ レンダラー、およびパーティクル システムを初期化します。

Update() 関数: 「Fire1」キーが押されたときにタイマーを更新し、射撃ロジックをトリガーします。

shoot() 関数: 射撃ロジックを処理し、銃の効果音を再生し、銃の光源とレイ レンダラーを有効にし、命中検出用の光線を放射します。敵がヒットした場合、敵のダメージ ロジックを処理し、レイ上にヒット ポイントを表示します。敵が攻撃を受けていない場合は、射程の終わりを光線上に表示します。

ここに画像の説明を挿入


プレイヤーの健康状態

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() 関数: プレーヤーのヘルス、オーディオ ソース、アニメーション コンポーネント、および動きコンポーネントを初期化します。

Update() 関数: 負傷した画像の色を更新し、徐々に透明に戻し、負傷フラグをリセットします。

On Attack(intdamage) 関数: プレイヤーが攻撃されたときのロジックを処理し、ライフ値を減らし、スライダーの値を更新し、怪我の効果音を再生し、ライフ値が 0 以下の場合に死亡ロジックをトリガーします。 。

Die() 関数: プレイヤーが死亡したときのロジックを処理し、死亡サウンドを再生し、死亡アニメーションをトリガーし、移動コンポーネントを無効にします。

ここに画像の説明を挿入


敵の体力

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() 関数: 敵の血液量、オーディオ ソース、アニメーション コンポーネントを初期化します。

On Attack(intdamage) 関数: 敵が攻撃されたときのロジックを処理し、血液量を減らし、効果音を再生し、血液量がゼロになったときに死亡ロジックを実行します。

Dead() 関数: 敵が死亡したときのロジックを処理し、死亡アニメーションをトリガーし、ナビゲーション エージェントと敵の移動コンポーネントを無効にし、死亡効果音を再生し、一定時間後に敵のゲーム オブジェクトを破壊し、スコアを増加します。


スコア表示

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;
	}
}


モンスタースポナー

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");
		}
	}
}

複数のスクリプトをオブジェクトに追加し、異なるプレハブを配置します。

ここに画像の説明を挿入
ここに画像の説明を挿入


ゲームオーバーアニメーション

ここに画像の説明を挿入
ここに画像の説明を挿入






おすすめ

転載: blog.csdn.net/qq_20179331/article/details/130681949