切换主武器
This commit is contained in:
@@ -18,7 +18,7 @@ namespace Cielonos.MainGame
|
||||
float angularSpeed, float angularAcceleration, Vector3 initialDirection, bool stopWhenHit) : base(attackArea, stopWhenHit)
|
||||
{
|
||||
this.target = target;
|
||||
this.targetTransform = target.transform;
|
||||
this.targetTransform = target != null ? target.transform : null;
|
||||
this.angularSpeed = angularSpeed;
|
||||
this.angularAcceleration = angularAcceleration;
|
||||
this.moveSpeed = moveSpeed;
|
||||
@@ -30,6 +30,11 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
if (target == null || target.statusSm.isDead)
|
||||
{
|
||||
moveSpeed += moveAcceleration * Time.deltaTime;
|
||||
moveSpeed = Mathf.Max(moveSpeed, 0f);
|
||||
unscaledVelocity = projectile.forward * moveSpeed;
|
||||
scaledVelocity = unscaledVelocity * timeScaleCoefficient; //attackArea.creator.selfTimeModule
|
||||
projectile.position += scaledVelocity * Time.deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using UnityEngine;
|
||||
@@ -5,6 +6,7 @@ using UnityEngine.Serialization;
|
||||
|
||||
namespace Cielonos.MainGame.FunctionalAnimation
|
||||
{
|
||||
[Serializable]
|
||||
public class ChangeCollisionLayers : FuncAnimPayloadBase
|
||||
{
|
||||
[Tooltip("是否在排除这些碰撞层,若为否则表示添加(通常是加回,恢复)这些碰撞层")]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.FunctionalAnimation
|
||||
{
|
||||
[Serializable]
|
||||
public class InvokeAnimScFunction : FuncAnimPayloadBase
|
||||
{
|
||||
public string functionKey = "FunctionKey";
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.FunctionalAnimation
|
||||
{
|
||||
[Serializable]
|
||||
public class PlaySoundFX : FuncAnimPayloadBase
|
||||
{
|
||||
public string soundKey = "SoundKey";
|
||||
|
||||
@@ -8,6 +8,7 @@ using UnityEngine.Serialization;
|
||||
|
||||
namespace Cielonos.MainGame.FunctionalAnimation
|
||||
{
|
||||
[Serializable]
|
||||
public class SetBreakthroughResistance : FuncAnimPayloadBase
|
||||
{
|
||||
[InfoBox("设置角色的突破抗性状态,同时开启或关闭轮廓线效果。\n角色会被突破类型相同或更高的攻击打断,不会被低于该突破类型的攻击打断。")]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
@@ -5,6 +6,7 @@ using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.FunctionalAnimation
|
||||
{
|
||||
[Serializable]
|
||||
public class SetRootAdsorptionAdjustment : FuncAnimPayloadBase<bool>
|
||||
{
|
||||
[InfoBox("这个payload只能在运行时由代码调用,不能直接放在动画事件里使用")]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using Sirenix.OdinInspector;
|
||||
@@ -6,6 +7,7 @@ using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.FunctionalAnimation
|
||||
{
|
||||
[Serializable]
|
||||
public class SetStatus : FuncAnimPayloadBase
|
||||
{
|
||||
[Tooltip("要添加或移除的状态列表")]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.FunctionalAnimation
|
||||
{
|
||||
[Serializable]
|
||||
public class SpawnVFX : FuncAnimPayloadBase
|
||||
{
|
||||
public string vfxKey = "VFXKey";
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.FunctionalAnimation
|
||||
{
|
||||
[Serializable]
|
||||
public class SwitchFuncAnim : FuncAnimPayloadBase
|
||||
{
|
||||
public string animationName;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using SickscoreGames.HUDNavigationSystem;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSFramework.General;
|
||||
using SLSFramework.WwiseAssistance;
|
||||
@@ -50,6 +51,9 @@ namespace Cielonos.MainGame.Characters
|
||||
public ReactionSubcontroller reactionSc;
|
||||
public FeedbackSubcontroller feedbackSc;
|
||||
|
||||
[TitleGroup("Navigation")]
|
||||
public HUDNavigationElement navigationElement;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
InitializeSubcontrollers();
|
||||
|
||||
@@ -1,23 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using Cielonos.MainGame.Inventory;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
public class BodyPartsSubcontroller : SubcontrollerBase<CharacterBase>
|
||||
public partial class BodyPartsSubcontroller : SubcontrollerBase<CharacterBase>
|
||||
{
|
||||
[FormerlySerializedAs("centerPoint")] [Title("Main Parts")]
|
||||
[Title("Main Parts")]
|
||||
public Transform flexibleCenterPoint;
|
||||
public Transform staticCenterPoint;
|
||||
public Transform cameraLockingPoint;
|
||||
public Transform footPoint;
|
||||
public Transform head;
|
||||
public Transform leftHand;
|
||||
public Transform rightHand;
|
||||
public Transform back;
|
||||
public Transform hips;
|
||||
public Transform leftFoot;
|
||||
public Transform rightFoot;
|
||||
|
||||
[Title("Custom Parts")]
|
||||
public Dictionary<string, Transform> customBodyParts;
|
||||
}
|
||||
|
||||
public partial class BodyPartsSubcontroller
|
||||
{
|
||||
public Transform GetPart(ViewObjectData.AttachBodyPartType partType)
|
||||
{
|
||||
return partType switch
|
||||
{
|
||||
ViewObjectData.AttachBodyPartType.RightHand => rightHand,
|
||||
ViewObjectData.AttachBodyPartType.LeftHand => leftHand,
|
||||
ViewObjectData.AttachBodyPartType.Head => head,
|
||||
ViewObjectData.AttachBodyPartType.FlexibleCenterPoint => flexibleCenterPoint,
|
||||
ViewObjectData.AttachBodyPartType.Back => back,
|
||||
ViewObjectData.AttachBodyPartType.Hips => hips,
|
||||
ViewObjectData.AttachBodyPartType.RightFoot => rightFoot,
|
||||
ViewObjectData.AttachBodyPartType.LeftFoot => leftFoot,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public Transform GetPart(string partName)
|
||||
{
|
||||
return customBodyParts.GetValueOrDefault(partName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace Cielonos.MainGame.Characters
|
||||
|
||||
if (owner is Player player)
|
||||
{
|
||||
dashRotation.y = player.viewSc.isLockingTarget
|
||||
dashRotation.y = player.viewSc.lockTargetModule.isUsingLockTargetCamera
|
||||
? player.viewSc.cameraRotationSm.cinemachineEndLockYaw + angle
|
||||
: player.viewSc.cameraRotationSm.cinemachineTargetYaw + angle;
|
||||
}
|
||||
|
||||
@@ -230,19 +230,19 @@ namespace Cielonos.MainGame.Characters
|
||||
}
|
||||
};
|
||||
|
||||
inputActions.Player.SwitchMainWeapon.performed += ctx =>
|
||||
inputActions.Player.SwitchPreviousMainWeapon.performed += ctx =>
|
||||
{
|
||||
if (ctx.performed && isCursorLocked.Value)
|
||||
{
|
||||
operation.SwitchMainWeapon(ctx.ReadValue<float>());
|
||||
operation.SwitchMainWeapon(-1);
|
||||
}
|
||||
};
|
||||
|
||||
inputActions.Player.FastSwitchMainWeapon.performed += ctx =>
|
||||
inputActions.Player.SwitchNextMainWeapon.performed += ctx =>
|
||||
{
|
||||
if (ctx.performed && isCursorLocked.Value)
|
||||
{
|
||||
operation.FastSwitchMainWeapon();
|
||||
operation.SwitchMainWeapon(1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using Cielonos.MainGame.Inventory;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
public class PlayerBackpack
|
||||
{
|
||||
public List<MainWeaponBase> mainWeapons = new List<MainWeaponBase>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2c6ef7e33fccdf41848bc44e0432c59
|
||||
@@ -13,11 +13,24 @@ namespace Cielonos.MainGame.Characters
|
||||
public PlayerEquipmentSubmodule(PlayerInventorySubcontroller owner) : base(owner)
|
||||
{
|
||||
preparedMainWeapons = new List<MainWeaponBase>();
|
||||
foreach (MainWeaponBase mainWeapon in owner.backpack.mainWeapons)
|
||||
{
|
||||
ObtainMainWeapon(mainWeapon);
|
||||
}
|
||||
EquipMainWeapon(preparedMainWeapons[0]);
|
||||
}
|
||||
|
||||
public void ObtainMainWeapon(MainWeaponBase newWeapon)
|
||||
{
|
||||
if (!preparedMainWeapons.Contains(newWeapon))
|
||||
{
|
||||
preparedMainWeapons.Add(newWeapon);
|
||||
newWeapon.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
public void EquipMainWeapon(MainWeaponBase newWeapon)
|
||||
{
|
||||
newWeapon.Initialize();
|
||||
currentMainWeapon = newWeapon;
|
||||
currentMainWeapon.OnEquipped();
|
||||
currentMainWeapon.RegisterFullBodyFuncAnims();
|
||||
@@ -27,8 +40,23 @@ namespace Cielonos.MainGame.Characters
|
||||
|
||||
public void RemoveMainWeapon()
|
||||
{
|
||||
Debug.Log("Unequipping main weapon: " + currentMainWeapon);
|
||||
currentMainWeapon.OnUnequipped();
|
||||
currentMainWeapon = null;
|
||||
}
|
||||
|
||||
public void DiscardMainWeapon(MainWeaponBase weaponToDiscard)
|
||||
{
|
||||
if (preparedMainWeapons.Contains(weaponToDiscard))
|
||||
{
|
||||
if (currentMainWeapon == weaponToDiscard)
|
||||
{
|
||||
RemoveMainWeapon();
|
||||
}
|
||||
|
||||
preparedMainWeapons.Remove(weaponToDiscard);
|
||||
Object.Destroy(weaponToDiscard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Cielonos.MainGame.Inventory;
|
||||
using Cielonos.MainGame.Inventory;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
@@ -8,15 +8,14 @@ namespace Cielonos.MainGame.Characters
|
||||
public Player player => owner;
|
||||
private PlayerInputSubcontroller inputSc => player.inputSc;
|
||||
private PlayerOperationSubcontroller operationSc => player.operationSc;
|
||||
public MainWeaponBase testMainWeapon;
|
||||
public PlayerBackpack backpack;
|
||||
public PlayerEquipmentSubmodule equipmentSm;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
RegisterOperations();
|
||||
equipmentSm = new PlayerEquipmentSubmodule(this);
|
||||
equipmentSm.EquipMainWeapon(testMainWeapon);
|
||||
equipmentSm ??= new PlayerEquipmentSubmodule(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +37,8 @@ namespace Cielonos.MainGame.Characters
|
||||
operationSc.OnMainWeaponQuaternaryPress += MainWeaponSpecialBPress;
|
||||
operationSc.OnMainWeaponQuaternaryRelease += MainWeaponSpecialBRelease;
|
||||
|
||||
operationSc.OnSwitchMainWeapon += SwitchMainWeapon;
|
||||
|
||||
/*
|
||||
operationSc.OnSwitchMainWeapon += delegate(float dir) { SwitchMainWeapon(dir > 0 ? 1 : -1); };
|
||||
operationSc.OnUseSupportEquipment0Press += delegate { SupportEquipmentPress(0); };
|
||||
@@ -73,6 +74,15 @@ namespace Cielonos.MainGame.Characters
|
||||
|
||||
public partial class PlayerInventorySubcontroller
|
||||
{
|
||||
private void SwitchMainWeapon(int direction)
|
||||
{
|
||||
int currentIndex = equipmentSm.preparedMainWeapons.IndexOf(currentMainWeapon);
|
||||
equipmentSm.RemoveMainWeapon();
|
||||
int newIndex = (currentIndex + direction + equipmentSm.preparedMainWeapons.Count) % equipmentSm.preparedMainWeapons.Count;
|
||||
Debug.Log($"Switching main weapon from index {currentIndex} to {newIndex}");
|
||||
equipmentSm.EquipMainWeapon(equipmentSm.preparedMainWeapons[newIndex]);
|
||||
}
|
||||
|
||||
public void MainWeaponPrimaryPress()
|
||||
{
|
||||
if (currentMainWeapon != null)
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Cielonos.MainGame.Characters
|
||||
public event Action OnMainWeaponQuaternaryHold;
|
||||
public event Action OnMainWeaponQuaternaryRelease;
|
||||
|
||||
public event Action<float> OnSwitchMainWeapon;
|
||||
public event Action<int> OnSwitchMainWeapon;
|
||||
public event Action OnOpenMainWeaponRoulette;
|
||||
public event Action OnCloseMainWeaponRoulette;
|
||||
public event Action OnFastSwitchMainWeapon;
|
||||
@@ -95,7 +95,7 @@ namespace Cielonos.MainGame.Characters
|
||||
public void MainWeaponQuaternaryHold() => OnMainWeaponQuaternaryHold?.Invoke();
|
||||
public void MainWeaponSpecialBRelease() => OnMainWeaponQuaternaryRelease?.Invoke();
|
||||
|
||||
public void SwitchMainWeapon(float direction) => OnSwitchMainWeapon?.Invoke(direction);
|
||||
public void SwitchMainWeapon(int direction) => OnSwitchMainWeapon?.Invoke(direction);
|
||||
|
||||
public void OpenMainWeaponRoulette() => OnOpenMainWeaponRoulette?.Invoke();
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using DG.Tweening;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
using Ease = DG.Tweening.Ease;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
@@ -18,7 +20,6 @@ namespace Cielonos.MainGame.Characters
|
||||
public float cinemachineTargetPitch;
|
||||
public float topClamp = 70.0f;
|
||||
public float bottomClamp = -30.0f;
|
||||
public float cameraAngleOverride = 0.0f;
|
||||
public bool lockCameraPosition = false;
|
||||
|
||||
[Title("Combat Recenter Settings")]
|
||||
@@ -61,13 +62,16 @@ namespace Cielonos.MainGame.Characters
|
||||
|
||||
cinemachineTargetYaw = MathExtensions.ClampAngle(cinemachineTargetYaw, float.MinValue, float.MaxValue);
|
||||
cinemachineTargetPitch = MathExtensions.ClampAngle(cinemachineTargetPitch, bottomClamp, topClamp);
|
||||
|
||||
viewSc.cameraRoot.rotation = Quaternion.Euler(
|
||||
cinemachineTargetPitch + cameraAngleOverride /*- viewSc.muzzleLiftModule.currentMuzzlePositionY*/, cinemachineTargetYaw, 0.0f);
|
||||
|
||||
if (viewSc.isLockingTarget)
|
||||
|
||||
|
||||
if (viewSc.lockTargetModule.isUsingLockTargetCamera)
|
||||
{
|
||||
cinemachineEndLockYaw = viewSc.lockOnCamera.transform.eulerAngles.y;
|
||||
cinemachineEndLockYaw = viewSc.lockingTargetCamera.transform.eulerAngles.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewSc.cameraRoot.rotation = Quaternion.Euler(
|
||||
cinemachineTargetPitch /*- viewSc.muzzleLiftModule.currentMuzzlePositionY*/, cinemachineTargetYaw, 0.0f);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -108,23 +112,34 @@ namespace Cielonos.MainGame.Characters
|
||||
recenterTimer = duration;
|
||||
isRecentering = true;
|
||||
}
|
||||
|
||||
private bool tt;
|
||||
|
||||
// 将此方法添加到你控制相机旋转的脚本中 (例如 PlayerCameraController)
|
||||
public void SyncRotationWithCamera(Camera camera = null)
|
||||
/// <summary>
|
||||
/// 同步相机旋转到当前摄像机朝向
|
||||
/// </summary>
|
||||
public void SyncRotationWithCamera()
|
||||
{
|
||||
camera ??= viewSc.playerCamera;
|
||||
// 确保获取的是当前正在起作用的锁定相机的旋转
|
||||
var camera = viewSc.currentCamera;
|
||||
Vector3 currentEuler = camera.transform.eulerAngles;
|
||||
cinemachineTargetYaw = currentEuler.y;
|
||||
float currentPitch = currentEuler.x;
|
||||
if (currentPitch > 180)
|
||||
{
|
||||
currentPitch -= 360;
|
||||
}
|
||||
cinemachineTargetPitch = currentPitch - cameraAngleOverride;
|
||||
|
||||
float yaw = currentEuler.y;
|
||||
float pitch = currentEuler.x;
|
||||
|
||||
// --- 核心修复:处理欧拉角跨度问题 ---
|
||||
// 如果 pitch > 180 (例如 355), 则转为负数 ( -5 )
|
||||
if (pitch > 180) pitch -= 360;
|
||||
|
||||
isRecentering = false;
|
||||
// 强制执行一次旋转更新,防止下一帧才生效导致的微小跳动 (可选)
|
||||
// viewSc.cameraRoot.rotation = Quaternion.Euler(
|
||||
// cinemachineTargetPitch + cameraAngleOverride, cinemachineTargetYaw, 0.0f);
|
||||
|
||||
// 更新目标值
|
||||
cinemachineTargetYaw = yaw;
|
||||
cinemachineTargetPitch = pitch;
|
||||
|
||||
// --- 立即应用旋转 ---
|
||||
// 强制立即更新一次 cameraRoot,防止等待下一帧 Update 产生的跳变
|
||||
viewSc.cameraRoot.rotation = Quaternion.Euler(cinemachineTargetPitch, cinemachineTargetYaw, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbc378284638d9549945b8c5090f5a1b
|
||||
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using DG.Tweening;
|
||||
using SickscoreGames.HUDNavigationSystem;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using SLSFramework.General;
|
||||
using Ease = DG.Tweening.Ease;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
public partial class LockTargetSubmodule : SubmoduleBase<PlayerViewSubcontroller>
|
||||
{
|
||||
private Player player => owner.player;
|
||||
private PlayerViewSubcontroller viewSc => owner;
|
||||
private PlayerInputSubcontroller inputSc => player.inputSc;
|
||||
private HUDNavigationSystem navigationSystem => HUDNavigationSystem.Instance;
|
||||
private HUDNavigationCanvas navigationCanvas => HUDNavigationCanvas.Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 通常ACT类武器锁定目标时自动旋转摄像机,即使用LockTargetCamera
|
||||
/// TPS类远程武器不自动旋转,仅在目标上显示锁定标记,不切换摄像机
|
||||
/// </summary>
|
||||
public bool isAutoRotate;
|
||||
/// <summary>
|
||||
/// 是否正在锁定目标
|
||||
/// </summary>
|
||||
public bool isLocking;
|
||||
/// <summary>
|
||||
/// 是否正在使用锁定目标摄像机
|
||||
/// </summary>
|
||||
public bool isUsingLockTargetCamera => isLocking && isAutoRotate;
|
||||
public bool isDuringSwitch;
|
||||
public CharacterBase lockTarget;
|
||||
public Transform targetPoint;
|
||||
private Tweener iconTween;
|
||||
|
||||
public LockTargetSubmodule(PlayerViewSubcontroller owner) : base(owner)
|
||||
{
|
||||
isLocking = false;
|
||||
isAutoRotate = false;
|
||||
isDuringSwitch = false;
|
||||
lockTarget = null;
|
||||
targetPoint = null;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (isUsingLockTargetCamera && !isDuringSwitch)
|
||||
{
|
||||
viewSc.cameraRoot.LookAt(targetPoint);
|
||||
float distance = (targetPoint.position - viewSc.cameraRoot.transform.position).Flatten().magnitude;
|
||||
if (isUsingLockTargetCamera && distance < 1f)
|
||||
{
|
||||
UnlockTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class LockTargetSubmodule
|
||||
{
|
||||
public void SwitchLockState()
|
||||
{
|
||||
if (isLocking)
|
||||
{
|
||||
UnlockTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
LockTarget(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void LockTarget(bool isAutoRotate)
|
||||
{
|
||||
if(isDuringSwitch) return;
|
||||
|
||||
CharacterBase target = BattleManager.EnemySm.GetNearestEnemy(50f);
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
this.isLocking = true;
|
||||
this.isAutoRotate = isAutoRotate;
|
||||
this.lockTarget = target;
|
||||
this.isDuringSwitch = true;
|
||||
|
||||
if (isAutoRotate)
|
||||
{
|
||||
targetPoint = target.bodyPartsSc.cameraLockingPoint ?? target.bodyPartsSc.staticCenterPoint;
|
||||
viewSc.currentCamera = viewSc.lockingTargetCamera;
|
||||
viewSc.lockingTargetCamera.LookAt = targetPoint;
|
||||
viewSc.stateDrivenCamera.GetComponent<Animator>().SetBool("isLockTarget", true);
|
||||
viewSc.cameraRoot.DOLookAt(targetPoint.position, 0.5f)
|
||||
.SetEase(Ease.InOutSine)
|
||||
.OnComplete(() => { isDuringSwitch = false; })
|
||||
.Play();
|
||||
}
|
||||
else
|
||||
{
|
||||
Observable.Timer(TimeSpan.FromSeconds(0.5f)).First().Subscribe(_ =>
|
||||
{
|
||||
isDuringSwitch = false;
|
||||
});
|
||||
}
|
||||
|
||||
lockTarget.navigationElement.showIndicator = true;
|
||||
Image icon = lockTarget.navigationElement.Indicator.OnscreenIcon;
|
||||
iconTween?.Kill(true);
|
||||
iconTween = icon.GetComponent<RectTransform>().DOScale(1f, 0.5f).From(0f).SetEase(Ease.OutQuart).Play();
|
||||
}
|
||||
}
|
||||
|
||||
public void UnlockTarget()
|
||||
{
|
||||
if(isDuringSwitch) return;
|
||||
|
||||
if (isAutoRotate)
|
||||
{
|
||||
viewSc.cameraRotationSm.SyncRotationWithCamera();
|
||||
viewSc.stateDrivenCamera.GetComponent<Animator>().SetBool("isLockTarget", false);
|
||||
viewSc.stateDrivenCamera.InternalUpdateCameraState(Vector3.up, Time.deltaTime);
|
||||
viewSc.currentCamera = viewSc.freeLookCamera;
|
||||
}
|
||||
this.isLocking = false;
|
||||
this.isAutoRotate = false;
|
||||
Image icon = lockTarget.navigationElement.Indicator.OnscreenIcon;
|
||||
iconTween?.Kill(true);
|
||||
iconTween = icon.GetComponent<RectTransform>().DOScale(0f, 0.5f).SetEase(Ease.OutQuart).OnComplete(() =>
|
||||
{
|
||||
lockTarget.navigationElement.showIndicator = false;
|
||||
this.lockTarget = null;
|
||||
this.targetPoint = null;
|
||||
this.isDuringSwitch = false;
|
||||
}).Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e462ecfd74196754181689f4a89f54af
|
||||
@@ -12,99 +12,45 @@ namespace Cielonos.MainGame.Characters
|
||||
public class PlayerViewSubcontroller : SubcontrollerBase<Player>, IPlayerSubcontroller
|
||||
{
|
||||
public Player player => owner;
|
||||
|
||||
|
||||
public Camera playerCamera;
|
||||
public Transform cameraRoot;
|
||||
public CinemachineStateDrivenCamera stateDrivenCamera;
|
||||
public CinemachineCamera currentCamera;
|
||||
public CinemachineCamera freeLookCamera;
|
||||
public CinemachineCamera lockOnCamera;
|
||||
[FormerlySerializedAs("isLockedOn")] public bool isLockingTarget = false;
|
||||
public bool isLockedSetRoot;
|
||||
public CinemachineCamera lockingTargetCamera;
|
||||
public CharacterBase testEnemy;
|
||||
public Transform testEnemyTarget;
|
||||
|
||||
|
||||
public CameraRotationSubmodule cameraRotationSm;
|
||||
public OcclusionFadeSubmodule occlusionFadeSm;
|
||||
|
||||
public LockTargetSubmodule lockTargetModule;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
cameraRotationSm = new CameraRotationSubmodule(this, player.transform.eulerAngles.y);
|
||||
occlusionFadeSm = new OcclusionFadeSubmodule(this);
|
||||
lockTargetModule = new LockTargetSubmodule(this);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
testEnemyTarget = testEnemy.bodyPartsSc.staticCenterPoint;
|
||||
//SwitchToLockTarget( testEnemyTarget );
|
||||
currentCamera = freeLookCamera;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Keyboard.current.tabKey.wasPressedThisFrame)
|
||||
{
|
||||
if (!isLockingTarget)
|
||||
{
|
||||
SwitchToLockTarget( testEnemyTarget );
|
||||
}
|
||||
else
|
||||
{
|
||||
SwitchToFreeLook();
|
||||
}
|
||||
lockTargetModule.SwitchLockState();
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
cameraRotationSm.Update();
|
||||
|
||||
if (!isLockingTarget)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isLockedSetRoot) cameraRoot.LookAt(testEnemyTarget);
|
||||
float distance = (testEnemyTarget.position - cameraRoot.transform.position).Flatten().magnitude;
|
||||
if(distance < 1f) SwitchToFreeLook();
|
||||
}
|
||||
lockTargetModule.Update();
|
||||
occlusionFadeSm.Update();
|
||||
}
|
||||
|
||||
void SwitchToLockTarget(Transform target)
|
||||
{
|
||||
testEnemyTarget = target;
|
||||
isLockingTarget = true;
|
||||
isLockedSetRoot = false;
|
||||
|
||||
// --- CM3 核心操作 ---
|
||||
// 1. 设置 LookAt 目标。在 CM3 中,LookingAt 是 Target 结构体的一部分,或者直接赋值给 LookAt 属性
|
||||
lockOnCamera.Target.LookAtTarget = testEnemyTarget;
|
||||
|
||||
// 2. 提高优先级,激活锁定相机
|
||||
stateDrivenCamera.GetComponent<Animator>().SetBool("isLockTarget", true);
|
||||
cameraRoot.DOLookAt(testEnemyTarget.position, 0.5f).SetEase(Ease.InOutSine).OnComplete(()=>isLockedSetRoot = true).Play();
|
||||
|
||||
// (可选) 你可以在这里播放锁定音效或显示 UI 准星
|
||||
Debug.Log($"Locked on: {target.name}");
|
||||
}
|
||||
|
||||
void SwitchToFreeLook()
|
||||
{
|
||||
cameraRotationSm.SyncRotationWithCamera(playerCamera);
|
||||
|
||||
isLockingTarget = false;
|
||||
|
||||
// --- CM3 核心操作 ---
|
||||
// 1. 重置 LookAt 目标
|
||||
//lockOnCamera.Target.LookAtTarget = null;
|
||||
|
||||
// 2. 降低优先级,切换回自由视角相机
|
||||
stateDrivenCamera.GetComponent<Animator>().SetBool("isLockTarget", false);
|
||||
|
||||
// (可选) 你可以在这里播放解锁音效或隐藏 UI 准星
|
||||
Debug.Log("Switched to Free Look");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,14 @@ namespace Cielonos.MainGame.Inventory
|
||||
public Player player => MainGameManager.Instance.player;
|
||||
protected PlayerAnimationSubcontroller animationSc => player.animationSc;
|
||||
protected FunctionalAnimationSubmodule fullBodyFuncAnimSm => animationSc.fullBodyFuncAnimSm;
|
||||
|
||||
public ItemViewObject viewObject;
|
||||
|
||||
[Title("Data")]
|
||||
public List<FuncAnimData> fullBodyFuncAnims = new List<FuncAnimData>();
|
||||
[HideInInspector]
|
||||
private List<string> registeredFunctionNames = new List<string>();
|
||||
|
||||
[FormerlySerializedAs("objectData")]
|
||||
public ViewObjectData viewObjectData;
|
||||
public VFXData vfxData;
|
||||
public ComboData comboData;
|
||||
public AttackData attackData;
|
||||
@@ -41,10 +41,12 @@ namespace Cielonos.MainGame.Inventory
|
||||
[Title("Subcontrollers")]
|
||||
public FeedbackSubcontroller feedbackSc;
|
||||
|
||||
|
||||
[Title("View Objects")]
|
||||
public Dictionary<string, ItemViewObject> viewObjects = new Dictionary<string, ItemViewObject>();
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
functionSm.Update(player.selfTimeSm.DeltaTime);
|
||||
functionSm?.Update(player.selfTimeSm.DeltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
public partial class ItemViewObject : SerializedMonoBehaviour
|
||||
{
|
||||
public GameObject item;
|
||||
public Dictionary<string, GameObject> functionalParts;
|
||||
|
||||
public GameObject Part(string partName)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using MoreMountains.Feedbacks;
|
||||
using MoreMountains.FeedbacksForThirdParty;
|
||||
@@ -7,7 +8,6 @@ namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
public abstract partial class MainWeaponBase : ItemBase
|
||||
{
|
||||
|
||||
public BaseAnimationGroup baseAnimationGroup;
|
||||
}
|
||||
|
||||
@@ -16,17 +16,45 @@ namespace Cielonos.MainGame.Inventory
|
||||
public virtual void OnEquipped()
|
||||
{
|
||||
baseAnimationGroup.SetUp(animationSc);
|
||||
foreach (ViewObjectData.ViewObjectDataUnit unit in viewObjectData.viewObjectUnits)
|
||||
{
|
||||
Transform attachPoint = !unit.isCustomAttachPoint ?
|
||||
player.bodyPartsSc.GetPart(unit.normalAttachBodyPart) :
|
||||
player.bodyPartsSc.GetPart(unit.customAttachPartName);
|
||||
if (attachPoint != null)
|
||||
{
|
||||
ItemViewObject view = Instantiate(unit.objectPrefab, attachPoint).GetComponent<ItemViewObject>();
|
||||
if (unit.applyOffset)
|
||||
{
|
||||
view.transform.localPosition = unit.positionOffset;
|
||||
view.transform.localEulerAngles = unit.rotationOffset;
|
||||
}
|
||||
viewObjects[unit.objectName] = view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnUnequipped()
|
||||
{
|
||||
RemoveAllRegisteredFunctions();
|
||||
|
||||
foreach (ItemViewObject view in viewObjects.Values)
|
||||
{
|
||||
Destroy(view.gameObject);
|
||||
}
|
||||
viewObjects.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class MainWeaponBase
|
||||
{
|
||||
protected Transform muzzle => viewObject.functionalParts["Muzzle"].transform;
|
||||
protected override void Update()
|
||||
{
|
||||
if (player.inventorySc.equipmentSm.currentMainWeapon == this)
|
||||
{
|
||||
functionSm?.Update(player.selfTimeSm.DeltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class MainWeaponBase
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class LockTargetCamera : MonoBehaviour
|
||||
public class ContentData : MonoBehaviour
|
||||
{
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
2
Assets/Scripts/MainGame/Items/Data/ContentData.cs.meta
Normal file
2
Assets/Scripts/MainGame/Items/Data/ContentData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd6893a98c17a0e47af8bd555a67190b
|
||||
@@ -8,11 +8,11 @@ using UnityEngine;
|
||||
namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
[CreateAssetMenu(fileName = "FunctionData", menuName = "Cielonos/Items/FunctionData")]
|
||||
public class FunctionData : SerializedScriptableObject
|
||||
public partial class FunctionData : SerializedScriptableObject
|
||||
{
|
||||
[DictionaryDrawerSettings(KeyLabel = "Attack Unit", DisplayMode = DictionaryDisplayOptions.ExpandedFoldout)]
|
||||
[Searchable]
|
||||
public Dictionary<string, ItemFunctionUnit> functionUnits;
|
||||
public Dictionary<string, FunctionUnit> functionUnits = new Dictionary<string, FunctionUnit>();
|
||||
|
||||
[OnInspectorGUI("UpdateUnits")]
|
||||
public void UpdateUnits()
|
||||
@@ -23,9 +23,8 @@ namespace Cielonos.MainGame.Inventory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ItemFunctionUnit
|
||||
|
||||
public partial class FunctionData
|
||||
{
|
||||
public enum IntervalReductionType
|
||||
{
|
||||
@@ -34,26 +33,30 @@ namespace Cielonos.MainGame.Inventory
|
||||
AttackSpeed = 10
|
||||
}
|
||||
|
||||
[ReadOnly]
|
||||
public FunctionData parentData;
|
||||
[Serializable]
|
||||
public class FunctionUnit
|
||||
{
|
||||
[ReadOnly]
|
||||
public FunctionData parentData;
|
||||
|
||||
[TitleGroup("Information")]
|
||||
public bool shownInUI;
|
||||
[TitleGroup("Information")]
|
||||
public Sprite icon;
|
||||
[TitleGroup("Information")]
|
||||
public List<string> operation;
|
||||
[TitleGroup("Information")]
|
||||
public bool shownInUI;
|
||||
[TitleGroup("Information")]
|
||||
public Sprite icon;
|
||||
[TitleGroup("Information")]
|
||||
public List<string> operation;
|
||||
|
||||
[TitleGroup("Costs")]
|
||||
public float energyCost;
|
||||
[TitleGroup("Costs")]
|
||||
public int ammoCost;
|
||||
[TitleGroup("Costs")]
|
||||
public float energyCost;
|
||||
[TitleGroup("Costs")]
|
||||
public int ammoCost;
|
||||
|
||||
[TitleGroup("Interval")]
|
||||
public float interval;
|
||||
[TitleGroup("Interval")]
|
||||
public float intervalLowerLimit;
|
||||
[TitleGroup("Interval")]
|
||||
public IntervalReductionType intervalReductionType;
|
||||
[TitleGroup("Interval")]
|
||||
public float interval;
|
||||
[TitleGroup("Interval")]
|
||||
public float intervalLowerLimit;
|
||||
[TitleGroup("Interval")]
|
||||
public IntervalReductionType intervalReductionType;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Assets/Scripts/MainGame/Items/Data/ViewObjectData.cs
Normal file
48
Assets/Scripts/MainGame/Items/Data/ViewObjectData.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
[CreateAssetMenu(fileName = "ViewObjectData", menuName = "Cielonos/Items/ViewObjectData")]
|
||||
public partial class ViewObjectData : SerializedScriptableObject
|
||||
{
|
||||
[ListDrawerSettings(ShowFoldout = true)]
|
||||
public List<ViewObjectDataUnit> viewObjectUnits = new List<ViewObjectDataUnit>();
|
||||
}
|
||||
|
||||
public partial class ViewObjectData
|
||||
{
|
||||
public enum AttachBodyPartType
|
||||
{
|
||||
RightHand,
|
||||
LeftHand,
|
||||
Head,
|
||||
FlexibleCenterPoint,
|
||||
Back,
|
||||
Hips,
|
||||
RightFoot,
|
||||
LeftFoot,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ViewObjectDataUnit
|
||||
{
|
||||
public string objectName;
|
||||
public GameObject objectPrefab;
|
||||
public bool isCustomAttachPoint;
|
||||
[HideIf("isCustomAttachPoint")]
|
||||
public AttachBodyPartType normalAttachBodyPart;
|
||||
[ShowIf("isCustomAttachPoint")]
|
||||
public string customAttachPartName;
|
||||
|
||||
public bool applyOffset;
|
||||
[ShowIf("applyOffset")]
|
||||
public Vector3 positionOffset;
|
||||
[ShowIf("applyOffset")]
|
||||
public Vector3 rotationOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bfbd542596c9aa4887562352b6768c7
|
||||
@@ -23,6 +23,10 @@ namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
PlayTargetedAnimation("LightAttack" + comboSm.GetCurrentNodeName(), currentTarget, 5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayTargetedAnimation("LightAttack" + comboSm.GetCurrentNodeName(), null, 5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +41,10 @@ namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
PlayTargetedAnimation("HeavyAttack", currentTarget, 3f);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayTargetedAnimation("HeavyAttack", null, 3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +58,11 @@ namespace Cielonos.MainGame.Inventory
|
||||
private void LightAttack3() => GenerateProjectile("HeavyProjectile", currentTarget, 10f);
|
||||
private void HeavyAttack() => GenerateGroundArea("GroundArea");
|
||||
}
|
||||
|
||||
public partial class FutureWand : MainWeaponBase
|
||||
{
|
||||
private Transform muzzle => viewObjects["Wand"].functionalParts["Muzzle"].transform;
|
||||
}
|
||||
|
||||
public partial class FutureWand
|
||||
{
|
||||
|
||||
@@ -12,12 +12,16 @@ namespace Cielonos.MainGame.Inventory
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
perfectBlockedTimer -= player.selfTimeSm.DeltaTime;
|
||||
if (player.inventorySc.equipmentSm.currentMainWeapon == this)
|
||||
{
|
||||
functionSm?.Update(player.selfTimeSm.DeltaTime);
|
||||
perfectBlockedTimer -= player.selfTimeSm.DeltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEquipped()
|
||||
{
|
||||
base.OnEquipped();
|
||||
RegisterFunctionsToAnimSc(
|
||||
LightAttack0, LightAttack1, LightAttack2, LightAttack3,
|
||||
TripleAttack_0, TripleAttack_1, TripleAttack_2,
|
||||
|
||||
@@ -36,11 +36,11 @@ namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
private CharacterBase character => owner.owner.player;
|
||||
|
||||
public ItemFunctionUnit data;
|
||||
public FunctionData.FunctionUnit data;
|
||||
public float currentCooldown;
|
||||
public float maxCooldown;
|
||||
|
||||
public RuntimeFunctionUnit(FunctionSubmodule owner, ItemFunctionUnit data) : base(owner)
|
||||
public RuntimeFunctionUnit(FunctionSubmodule owner, FunctionData.FunctionUnit data) : base(owner)
|
||||
{
|
||||
this.data = data;
|
||||
maxCooldown = data.interval;
|
||||
|
||||
@@ -21,6 +21,15 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
Application.targetFrameRate = 60;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
float frame = 1.0f / Application.targetFrameRate;
|
||||
if (frame < 10f && Time.time > 5f)
|
||||
{
|
||||
//Debug.Break();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class MainGameManager
|
||||
|
||||
Reference in New Issue
Block a user