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函数的方法不断修正,通过不断调试即可修正运动路径。
动画状态机
放箭通过触发控制
仅供参考