ユニティ、シューティングゲーム


導入

3D ゲーム。
プレイヤーは自由に動きます。
銃を構えて弾丸を発射。
ランダムに生成された戦車がプレイヤーを追跡します。
戦車はプレイヤーに弾丸を発射します。
HPゼロデス

ここに画像の説明を挿入


1. プレイヤー固有の関数スクリプト PlayerCharacter を作成する

float の設定: 移動速度、回転速度、弾丸発射速度、現在のヘルス値、最大ヘルス値、2 回の攻撃間の時間間隔。

ブール値を設定: 攻撃しているかどうか、死んでいるかどうか

その他のコンポーネント: キャラクター コントローラー、ヘルス スライダー、最大ヘルス カラー (緑)、最小ヘルス カラー (赤)、オーディオ ソース、アニメーター、パーティクル システムなど

public float speed;
public float turnSpeed;
public float health;
public float attackTime;
public float health;
float healthMax;

bool isAlive;
bool attacking = false;

CharacterController cc;
Animator animator;
public Slider healthSlider;                             
public Image healthFillImage;                          
public Color healthColorFull = Color.green;
public Color HealthColorNull = Color.red;

public ParticleSystem explosionParticles;
public Rigidbody shell;
public Transform muzzle;

start方法,获取动画器、角色控制器、生命值最大化、bool设置活着、更新血条滑块、死亡爆炸效果设置为不可见。
animator = GetComponentInChildren<Animator>();
        cc = GetComponent<CharacterController>();
        healthMax = health;
        isAlive = true;
        RefreshHealthHUD();
        explosionParticles.gameObject.SetActive(false);
玩家被攻击,生命值减少amount,更新血条,如果生命值小于零,死亡
 public void TakeDamage(float amount)
    {
    
    
        health -= amount;
        RefreshHealthHUD();
        if (health <= 0f && isAlive)
        {
    
    
            Death();
        }
    }
更新血条,滑块的value值更新一次,血条由100%的绿色,变成百分之(health / healthMax)的绿色。
  public void RefreshHealthHUD()
    {
    
    
        healthSlider.value = health;
        healthFillImage.color = Color.Lerp(HealthColorNull, healthColorFull, health / healthMax);
    }
死亡,角色是否活着设置为否,播放粒子特效,当粒子系统的持续时间结束后,粒子系统对象就会被销毁,设置玩家为不可见。
 public void Death()
    {
    
    
        isAlive = false;
        explosionParticles.transform.parent = null;
        explosionParticles.gameObject.SetActive(true);
        ParticleSystem.MainModule mainModule = explosionParticles.main;
        Destroy(explosionParticles.gameObject, mainModule.duration);
        gameObject.SetActive(false);

    }
角色移动,传入一个向量值,必须在活着、没有攻击才能移动。
角色控制器使用simplemove函数,移动的时候,控制“speed”动画,开始播放
 public void Move(Vector3 v)
    {
    
    
        if (!isAlive) return;
        if (attacking) return;
        Vector3 movement = v * speed;
        cc.SimpleMove(movement);
        if(animator)
        {
    
    
            animator.SetFloat("Speed", cc.velocity.magnitude);
        }
    }
人物旋转函数,玩家往哪里跑,角色人物头就转向哪里
设置目标位置、当前位置
四元数转向
使用球面插值,平滑转动
  public void Rotate(Vector3 lookDir)
    {
    
    
        var targetPos = transform.position + lookDir;
        var characterPos = transform.position;

        //去除Y轴影响
        characterPos.y = 0;
        targetPos.y = 0;
        //角色面朝目标的向量
        Vector3 faceToDir = targetPos - characterPos;
        //角色面朝目标方向的四元数
        Quaternion faceToQuat = Quaternion.LookRotation(faceToDir);
        //球面插值
        Quaternion slerp = Quaternion.Slerp(transform.rotation, faceToQuat, turnSpeed * Time.deltaTime);

        transform.rotation = slerp;
    }
开火脚本
必须活着、不正在开火才能调用
生成一个子弹刚体,玩家自身位置,枪口方向转向,设置发射速度
播放开火音效
动画器播放开火动作
延迟attachtime发射一次,设置发射频率
 public void Fire()
    {
    
    
        if (!isAlive) return;
        if (attacking) return;

        Rigidbody shellInstance = Instantiate(shell, muzzle.position, muzzle.rotation) as Rigidbody;
        shellInstance.velocity = launchForce * muzzle.forward;
        shootAudioSource.Play();

        if(animator)
        {
    
    
            animator.SetTrigger("Attack");
        }


        attacking = true;
        Invoke("RefreshAttack", attackTime);
    }

发射时间间隔脚本,时间未到,不能发射
 void RefreshAttack()
    {
    
    
        attacking = false;
    }

3. プレーヤー制御スクリプトを PlayerController にし、上記の関数メソッドを呼び出します

start方法获取角色控制器
void Start ()
    {
    
    
        character = GetComponent<PlayerCharacter>();
	}
固定帧数刷新。
鼠标左键调用点击开火函数
键盘wsad控制人物移动
人物移动的方向和人物转向的方向保持一致
void FixedUpdate()
    {
    
    
        if (Input.GetButtonDown("Fire1"))
        {
    
    
            character.Fire();
        }

        var h = Input.GetAxis("Horizontal");
        var v = Input.GetAxis("Vertical");
        character.Move(new Vector3(h, 0, v));
        var lookDir = Vector3.forward * v + Vector3.right * h;
        if (lookDir.magnitude != 0)
        {
    
    
            character.Rotate(lookDir);
        }
    }

4. ブレット スクリプト シェルを作成する

设置float参数:子弹生存时间、爆炸半径、爆炸力量、最大伤害

设置bool参数:子弹是否正在旋转

设置其他:音频源、层级、粒子系统
    public float lifeTimeMax = 2f;
    public AudioSource explosionAudioSource;
    public ParticleSystem explosionParticles;
    public float explosionRadius;
    public float explosionForce = 1000f;
    public float damageMax = 100f;
    public LayerMask damageMask;
    public bool isRotate = false;

start メソッド、トルクの追加、弾丸の回転のシミュレート

 void Start ()
    {
    
    
        if(isRotate)
        {
    
    
            GetComponent<Rigidbody>().AddTorque(transform.right * 1000);
        }
    }
触发器碰撞检测
在当前游戏对象的位置上创建一个球形的检测区域,并检测该区域内是否有与指定层级(damageMask)匹配的碰撞器(colliders)。如果有,则返回一个碰撞器数组(Collider[]),其中包含了所有与当前游戏对象在指定半径(explosionRadius)内发生碰撞的游戏对象的碰撞器。通常用于实现爆炸伤害、碰撞检测等功能。	
遍历数组,计算伤害
播放粒子特效
 private void OnTriggerEnter(Collider other)
    {
    
    
        Collider[] colliders = Physics.OverlapSphere(transform.position, explosionRadius, damageMask);

        foreach(var collider in colliders)
        {
    
    
            var targetCharacter = collider.GetComponent<PlayerCharacter>();
            if (targetCharacter)
            {
    
    
                targetCharacter.TakeDamage(CalculateDamage(collider.transform.position));
            }
        }
        explosionParticles.transform.parent = null;
	     explosionAudioSource.Play();
        explosionParticles.Play();

        ParticleSystem.MainModule mainModule = explosionParticles.main;
	    // Destroy(explosionParticles.gameObject, mainModule.duration);
        Destroy(gameObject);
    }

计算伤害,传入向量值
距离越小,伤害比例越大
设置最低伤害Mathf.Max()函数,最低伤害为2
float CalculateDamage(Vector3 targetPosition)
    {
    
    
        
        var distance = (targetPosition - transform.position).magnitude;
        //距离越小,伤害比例越大
        var damageModify = (explosionRadius - distance) / explosionRadius;
        var damage = damageModify * damageMax;
        return Mathf.Max(2f, damage);
    }

5. プレーヤーのスクリプトをマウントする

パラメータの設定、プレハブ弾の追加
ここに画像の説明を挿入


第六に、戦車のスクリプトを作成します

设置导航网格、play对象
	 NavMeshAgent agent;
    PlayerCharacter character;
    Transform targetTrans;
start函数,获取玩家实例,
导航网格寻找玩家
延迟1秒后,每隔三秒发射一次子弹
 void Start ()
    {
    
    
        character = GetComponent<PlayerCharacter>();
        agent = GetComponent<NavMeshAgent>();

        targetTrans = GameObject.FindGameObjectWithTag("Player").transform;
        
        InvokeRepeating("FireControl", 1, 3);
    }
开火控制函数,调用共同使用的fire()方法。
 void FireControl()
    {
    
    
        character.Fire();
    }

update()函数,不断追踪玩家的位置,
转向玩家
void Update ()
    {
    
    
        agent.destination = targetTrans.position;
        transform.LookAt(targetTrans);
    }

7. タンクにコンポーネントを追加する

ここに画像の説明を挿入


8. ゲームを開始してアニメーションを再生する

ここに画像の説明を挿入

キャラ移動、戦車移動

ここに画像の説明を挿入


9. ダウンロード

https://pan.baidu.com/s/1RVemZY_THhhpD0v_IcQS2w

抽出コード:tdq9





+

おすすめ

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