using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/* 弓对象 */
public class ArmBow : MonoBehaviour
{
[SerializeField] AnimationPlayer AP_arm;
[SerializeField] AnimationPlayer AP_bow;
[SerializeField] public GameObject arrow;
[SerializeField] public GameObject bullet;
[SerializeField] GameObject armObj;
[SerializeField] GameObject bowObj;
[Header("弓箭飞行时候的参数设置")]
[Tooltip("弓箭飞行部分速度影响曲线")]
[SerializeField]
public AnimationCurve customCurveArrow = new AnimationCurve(
new Keyframe(0f, 0f),
new Keyframe(0.7f, 0.6f),
new Keyframe(1f, 1f)
);
[Tooltip("相机飞行曲线")]
[SerializeField]
public AnimationCurve customCurveCamera = new AnimationCurve(
new Keyframe(0f, 0f),
new Keyframe(0.7f, 0.6f),
new Keyframe(1f, 1f)
);
// 0.5 = 慢一半,2 = 加速两倍
[Tooltip("弓箭飞行速度")]
[SerializeField]
public float slowFactor = 0.3f;
///
/// 相机相对箭的偏移量
/// x = 左右偏移(负数表示往左,正数往右)
/// y = 高度偏移(正数表示高于箭,固定高度时候,和目标y值叠加)
/// z = 前后偏移(负数表示在箭的后面,正数表示在箭的前面)
///
[Tooltip("相机相对箭的偏移量(Y 是目标靶叠加值 目标Y + Y = 相机高度)")]
[SerializeField]
public Vector3 offsetFromArrow = new Vector3(0, 0.75f, -2.5f);
[Tooltip("没有射中目标靶的时候,给定一个跟随差值")]
[SerializeField]
public Vector3 offsetFromArrowTemp = new Vector3(0, 0.75f, -2.5f);
[Tooltip("相机与目标之间的最小停止距离")]
[SerializeField]
public float stopDistanceToTarget = 4f; // 相机与目标之间的最小停止距离(XZ 平面)
BowCamera _bowCamera;
BowCamera bowCamera {
get {
if (!_bowCamera) _bowCamera = GetComponentInParent();
return _bowCamera;
}
}
//有效射击目标集合,可以理解为射中集合中的目标才能得分
public HashSet validTargets = new HashSet();
//本地坐标z
public const float localPosZ = -0.1f;
//射箭姿态记录索引倒退数,根据射击难度制造误差
[NonSerialized] public int shootBackTime = 0;
[NonSerialized] public float shootOffsetAngleScale = 0;
//禁止准备的外部接口
[NonSerialized] public bool banReady = false;
//禁止射击的外部接口
[NonSerialized] public bool banShoot = false;
//禁止逻辑,只用于同步状态和渲染,目前用于联机
[NonSerialized] public bool banLogic = false;
//过去几帧的镜头值记录
Quaternion[] cameraRotations = new Quaternion[6];
int cameraRotationHasRecordCount = 0;
#region logic state
[NonSerialized] public int phase = -1; //当前阶段
void UpdatePhase() {
if (phase == -1) return;
if (phase == 0) { //拉弓前的准备
if (arm_ani_index_cur != 0) {
AP_arm.play(arm_ani_index_cur = 0, WrapMode.Once);
AP_arm.completeCallback = onComplete;
}
if (bow_ani_index_cur != 0) {
AP_bow.play(bow_ani_index_cur = 0, WrapMode.Once);
}
} else if (phase == 1) { //拉弓过程
if (arm_ani_index_cur != 2) {
AP_arm.play(arm_ani_index_cur = 2, WrapMode.Once);
AP_arm.completeCallback = onComplete;
}
if (bow_ani_index_cur != 2) {
AP_bow.play(bow_ani_index_cur = 2, WrapMode.Once);
}
this.bowCamera.updateFollowPullBow();
} else if (phase == 2) { //拉完完成,等待发射
if (arm_ani_index_cur != 2) {
AP_arm.play(arm_ani_index_cur = 2, WrapMode.Once);
AP_arm.completeCallback = onComplete;
}
if (bow_ani_index_cur != 2) {
AP_bow.play(bow_ani_index_cur = 2, WrapMode.Once);
}
} else if (phase == 3) { //射出后
if (arm_ani_index_cur != 3) {
AP_arm.play(arm_ani_index_cur = 3, WrapMode.Once);
AP_arm.completeCallback = onComplete;
}
if (bow_ani_index_cur != 3) {
AP_bow.play(bow_ani_index_cur = 3, WrapMode.Once);
}
}
if (!IsCanShoot()) {
this.bowCamera.updateGiveUpPullBow();
}
}
void onComplete(AnimationPlayerCompleteResult res) {
if (res.index == 0 && !banLogic) {
this.phase = 1;
}
else if (res.index == 2 && !banLogic) {
this.phase = 2;
GameMgr.ins.gameMode.ResumeTimeCounting(this);
}
}
public bool IsCanShoot() {
return phase == 2;
}
#endregion
#region display state
int arm_ani_index_cur = -1;
int bow_ani_index_cur = -1;
#endregion
private static ArmBow _ins;
public static ArmBow ins {
get {
if (!_ins) {
_ins = GameObject.FindObjectOfType();
}
return _ins;
}
}
void Awake()
{
_ins = this;
this.transform.localPosition = new Vector3(0.0865f, -1.692f, -0.1f);
//initdata
Vector3 localPos = transform.localPosition; localPos.z = localPosZ; transform.localPosition = localPos;
int currentShootLevel = UserSettings.ins.shootLevel;
shootBackTime = new int[]{0, 2, 5}[currentShootLevel];
shootOffsetAngleScale = new float[]{0, 10f, 10f}[currentShootLevel];
//不同模式下设置速度,用于调整射击间隔
if (GlobalData.MyDeviceMode == DeviceMode.Gun)
{
AP_arm.speed = 20;
AP_bow.speed = 20;
}
//根据 hideInfraredBowAndArrow 判断是否显示隐藏
if (PlayerPrefs.HasKey("hideInfraredBowAndArrow") && PlayerPrefs.GetInt("hideInfraredBowAndArrow") != 0) {
armObj.SetActive(false);
bowObj.SetActive(false);
//解除默认 hide 状态
PlayerPrefs.SetInt("hideInfraredBowAndArrow", 2);
}
else {
//枪模式下隐藏手臂等
if (GlobalData.MyDeviceMode == DeviceMode.Gun)
{
armObj.SetActive(false);
bowObj.SetActive(false);
AP_arm.speed = 10;
}
else {
armObj.SetActive(UserSettings.ins.openBowAndArrow);
bowObj.SetActive(UserSettings.ins.openBowAndArrow);
}
}
}
void Start()
{
this.readyShoot();
}
void OnDestroy()
{
if (_ins == this) _ins = null;
}
void OnEnable()
{
AudioMgr.GetAudioSource(this.gameObject).clip = null;
}
void Update()
{
UpdatePhase();
#if UNITY_EDITOR
if (Input.GetKeyDown(KeyCode.Q)) this.ADS_fire(true);
#endif
}
void FixedUpdate()
{
// 记录一些旋转角---start
if (this.bowCamera) {
for (int i = cameraRotations.Length - 1; i > 0 ; i--) {
cameraRotations[i] = cameraRotations[i - 1];
}
cameraRotations[0] = this.bowCamera.transform.rotation;
cameraRotationHasRecordCount++;
}
// 记录一些旋转角---end
}
public void readyShoot() {
if (banLogic) return;
this.bowCamera.SetCameraFieldOfViewRecord(this.bowCamera.defaultCameraFieldOfView);
if (banReady) return;
GameMgr.ins.gameMode.PauseTimeCounting(this);
GameMgr.ins.gameMode.onBowReady();
this.phase = 0;
}
public void ADS_fire(bool bAddCount = false) {
if (!IsCanShoot() || banShoot || GameMgr.ins.gamePause || banLogic || GameMgr.ins.gameOver) return;
//枪模式连接的情况下需要判断子弹
if (Billboard.ins && Billboard.ins.isBulletStatus)
{
if (Billboard.ins.bulletManager.bulletZero()) return;
//发射消耗子弹
Billboard.ins.bulletManager.FireBullet();
}
GameMgr.ins.gameMode.onBowShoot();
//记录射箭
if(bAddCount)GameMgr.ins.userGameAnalyse.onShootEvent();
this.phase = 3;
shoot();
}
void shoot() {
#region
Quaternion absolute_rotation = this.bowCamera.transform.rotation;
Quaternion final_rotation = this.bowCamera.transform.rotation;
if (cameraRotationHasRecordCount >= cameraRotations.Length) {
absolute_rotation = cameraRotations[5];
final_rotation = cameraRotations[5 - this.shootBackTime];
}
#endregion
Quaternion oldCameraRotation = BowCamera.ins.transform.rotation;
BowCamera.ins.transform.rotation = absolute_rotation;
RaycastHit absoluteRay = CrossHair.ins.GetRaycastHit();
BowCamera.ins.transform.rotation = oldCameraRotation;
Vector3 shootOutPosition = this.bowCamera.transform.position;
Vector3 arrowEuler = absolute_rotation.eulerAngles;
arrowEuler.z = 0; //绝对角可能是从原始九轴记录数组里取出来的,它的z可能不是0
GameObject arrowCopy = Instantiate(GlobalData.MyDeviceMode == DeviceMode.Archery? arrow : bullet, shootOutPosition, Quaternion.Euler(arrowEuler));
arrowCopy.SetActive(true);
Vector3 s1 = arrowCopy.transform.localScale;
Vector3 s2 = bowCamera.transform.localScale;
arrowCopy.transform.localScale = new Vector3(s1.x * s2.x, s1.y * s2.y, s1.z * s2.z);
Arrow arrowComp = arrowCopy.AddComponent();
arrowComp.armBow = this;
arrowComp.shootOutPosition = shootOutPosition;
arrowComp.absoluteRay = absoluteRay;
arrowComp.offsetAngle = GameDebug.ins ?
GameDebug.ins.GetOffsetAngle() :
Quaternion.Angle(absolute_rotation, final_rotation);
arrowComp.finalAngleAfterOffset = final_rotation.eulerAngles;
if (GlobalData.MyDeviceMode == DeviceMode.Gun) {
//枪的速度,设置800
Arrow.speed = 400;
AudioMgr.ins.PlayGunShoot(AudioMgr.GetAudioSource(arrowCopy));
} else {
if (ShootCheck.ins && !GameMgr.debugInEditor && !BowCamera.isTouchMode)
{
Arrow.speed = GameMgr.RealSizeToGameSize(ShootCheck.ins.shootSpeed);
}
AudioMgr.ins.PlayShoot(AudioMgr.GetAudioSource(arrowCopy));
}
GameEventCenter.ins.onBowArrowShootOut?.Invoke(this, arrowComp);
}
public void Hide()
{
this.transform.localScale = Vector3.zero;
}
public void Show()
{
this.transform.localScale = new Vector3(1, 1, 1);
}
}