zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Unity笔记-29-ARPG游戏项目-06-弓箭

游戏项目笔记 Unity 06 29
2023-09-11 14:22:30 时间

Unity笔记-29-ARPG游戏项目-06-弓箭

基本要求说明

点按R键,进入弓箭视角,点按鼠标左键进行射击,射击距离,伤害以及削韧效果根据蓄力时间而定,每次拉弓到射击的持续时间会不断蓄力,射击距离伤害,削韧效果具有上限,一直蓄力不会无限制的增加距离,伤害,削韧效果;

弓箭视角下的移动不会改变人物朝向,人物朝向一直朝向前方,通过再次点按R,跳跃,翻滚等操作可以退出弓箭视角,受到攻击造成硬直时也会退出弓箭视角

进入弓箭视角时,屏幕中央会出现射击符号,退出则消失,同时人物的动作朝向应当指向射击符号的位置

处于受击硬直,空中,攀爬时无法进入弓箭视角

展示图如下:

在这里插入图片描述

基本思路

点按R时,装备弓箭,并播放拉弓动画,再次点按放箭,播放放箭动画,暂时不配置弓箭拉绳的弯曲动画,可能比较奇怪,暂时以实现功能为主。箭的运动需要通过箭的脚本控制,由于这里我们将人物模型放在的屏幕的右边,因此如果不去修正箭的运动的话,只是让箭沿着朝向进行抛物线运动,它是不会飞向屏幕中央的,实际体验下很难射中目标,因此,还需要通过代码修正运动路径。

代码

仅说明箭的运动路径修正代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Attribute;

public class Arrow : MonoBehaviour
{
    [HideInInspector]
    public float beginV;
    [Header("坠落加速度")]
    public float fallA;
    [Header("朝向修正插值")]
    public float forFixT;
    [Header("延迟修正时间")]
    public float delayFixtime;
    [Header("仰角修正")]
    public float angle_Fix;
    [HideInInspector]
    public float specialDamageUp = 0;
    public float damage = 0;

    [HideInInspector]
    public RoleSynthesizedAttribute roleAttribute;
    private Rigidbody rigidbody=null;
    private bool fire=false;
    private float angle=180;
    private Vector3 goalDir;
    private float timer=0;
    private void FixedUpdate()
    {
        if (fire)
        {
            timer += Time.fixedDeltaTime;
            StartCoroutine(Disappear());
            Rotate_OriFix();
            Rotate_ForFix();
            rigidbody.velocity = transform.up.normalized * beginV + new Vector3(0, -fallA * timer, 0);
        }
    }
    private void Rotate_OriFix()
    {
        Quaternion relative = Quaternion.LookRotation(new Vector3(rigidbody.velocity.x, rigidbody.velocity.y, rigidbody.velocity.z))*Quaternion.Euler(90,0,0);
        transform.rotation = Quaternion.Lerp(transform.rotation, relative, 50*Time.fixedDeltaTime);
    }
    private void Rotate_ForFix()
    {
        if (timer < delayFixtime)
        {
            return;
        }
        Vector3 currentDir = Vector3.ProjectOnPlane(transform.up, Vector3.up);
        angle = Vector3.Angle(currentDir, goalDir);
        if (angle > 0.1f)
        {
            //transform.Rotate(0, angle*forFixT * Time.deltaTime* forFixSpeed, 0,Space.World);
            transform.eulerAngles += new Vector3(0, angle * forFixT,0);
            rigidbody.velocity = transform.up.normalized * beginV+ new Vector3(0, -fallA * timer, 0);
        }
    }
///发射
    public void Fire()
    {
        goalDir = Vector3.ProjectOnPlane(-ThirdPersonCamera.instance.myCurrentDir, Vector3.up);
        rigidbody = GetComponent<Rigidbody>();
        transform.eulerAngles -= new Vector3(angle_Fix,0,0);
        rigidbody.velocity = transform.up.normalized * beginV;
        fire = true;
    }
    private void OnCollisionEnter(Collision collision)
    {
        if (!fire) return;
        if (collision.gameObject.CompareTag(GameConst.PLAYER)) return;
        if (collision.gameObject.CompareTag(GameConst.ENEMY)&&fire)
        {
            damage = DamageCalculations(collision.transform.GetComponent<Enemy>().enemyAttribute);
            damage *= beginV / 10;
            collision.transform.GetComponent<Enemy>().Damage(damage, Mathf.Pow(beginV/5,3)*1.7f);
            Destroy(this.gameObject);
        }
        fire = false;
        rigidbody.useGravity = true;
    }
  ///伤害计算
    public float DamageCalculations(RoleSynthesizedAttribute enemyAttribute, bool real = false)
    {
        float damage;
        if (!real)
        {
            damage = roleAttribute.attack * Crit() * (1 + roleAttribute.extraDamageUp+specialDamageUp) * (1 - enemyAttribute.hurtReduction) * (roleAttribute.defensive / (roleAttribute.defensive + enemyAttribute.defensive));
        }
        else
        {
            damage = roleAttribute.attack * Crit() * (1 + roleAttribute.extraDamageUp);
        }
        return damage;
    }
  ///暴击计算
    public float Crit()
    {
        float crit = Random.Range(0, 100) / 100f;
        if (crit > roleAttribute.crit)
        {
            return 1;
        }
        else
        {
            return 1 + roleAttribute.critDamage;
        }
    }
    IEnumerator Disappear()
    {
        yield return new WaitForSeconds(10);
        Destroy(this.gameObject);
    }
}

箭还未发射时,箭对象没有碰撞体也没有刚体,如果这时候就给到这些组件,在人物移动时,箭就不会跟随人物移动。

执行放箭执行前,首先赋予箭碰撞体和刚体,并关闭重力,通过代码去赋予Y轴加速度,并赋予与朝向方向相同的初速度,发射后,通过计算摄像机朝向与箭朝向的角度,不断修正箭的角度与摄像机朝向相同,但不是瞬间,通过类似Lerp函数的方法不断修正,通过不断调试即可修正运动路径。

动画状态机

在这里插入图片描述

放箭通过触发控制

仅供参考