0906
This commit is contained in:
1 parent
5cd7a93c4a
commit
1476a089cb
108 files changed
+32073
-117261
No files matched your search
@@ -1,5 +1,3 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class CameraFollow : MonoBehaviour
|
||||
@@ -8,15 +6,17 @@ public class CameraFollow : MonoBehaviour
|
||||
public Vector3 offset; // 摄像机相对于角色的偏移量
|
||||
public float smoothSpeed = 0.125f; // 摄像机移动的平滑速度
|
||||
|
||||
void LateUpdate()
|
||||
private void LateUpdate()
|
||||
{
|
||||
// // 计算摄像机应该到达的目标位置
|
||||
// Vector3 desiredPosition = target.position + offset;
|
||||
// // 使用Lerp方法平滑移动摄像机到目标位置
|
||||
// Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
|
||||
// transform.position = smoothedPosition;
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// // 让摄像机始终看向角色
|
||||
// transform.LookAt(target);
|
||||
Vector3 desiredPosition = target.position + offset;
|
||||
transform.position = Vector3.Lerp(
|
||||
transform.position,
|
||||
desiredPosition,
|
||||
smoothSpeed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MainCharacterCombat : MonoBehaviour
|
||||
{
|
||||
[Header("自动攻击")]
|
||||
[Min(0f)]
|
||||
public float attackRange = 8f;
|
||||
|
||||
[Min(0f)]
|
||||
public float attackPower = 50f;
|
||||
|
||||
[Min(0f)]
|
||||
public float attackInterval = 2f;
|
||||
|
||||
[Header("模型朝向修正")]
|
||||
public float modelFacingOffset = 0f;
|
||||
|
||||
[Header("动画根运动")]
|
||||
public bool useRootMotion = false;
|
||||
|
||||
[Header("法术球")]
|
||||
public GameObject projectilePrefab;
|
||||
public Transform attackPos;
|
||||
|
||||
[Header("召唤单位")]
|
||||
public GameObject humanSoldierPrefab;
|
||||
public GameObject archerPrefab;
|
||||
public float summonDistance = 1.5f;
|
||||
public float summonSideOffset = 0.8f;
|
||||
public float summonSearchStep = 0.8f;
|
||||
public int summonSearchCount = 5;
|
||||
public float summonDepthSearchStep = 1f;
|
||||
public int summonDepthSearchCount = 2;
|
||||
public float summonAnimationTimeout = 2.5f;
|
||||
|
||||
[Min(0f)]
|
||||
public float projectileSpeed = 12f;
|
||||
|
||||
[Min(0f)]
|
||||
public float projectileLifetime = 5f;
|
||||
|
||||
private Animator animator;
|
||||
private MainCharacterDebugMovement movement;
|
||||
private GameObject target;
|
||||
private float attackCooldown;
|
||||
private float attackElapsed;
|
||||
private bool attacking;
|
||||
private bool attackEffectTriggered;
|
||||
private GameObject pendingSummonPrefab;
|
||||
private float summonElapsed;
|
||||
private bool summonSpawned;
|
||||
private bool summoning;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
movement = GetComponent<MainCharacterDebugMovement>();
|
||||
|
||||
if (animator != null)
|
||||
{
|
||||
animator.applyRootMotion = useRootMotion;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (attackCooldown > 0f)
|
||||
{
|
||||
attackCooldown -= Time.deltaTime;
|
||||
}
|
||||
|
||||
HandleSummonInput();
|
||||
if (summoning)
|
||||
{
|
||||
summonElapsed += Time.deltaTime;
|
||||
CheckSummonFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
if (attacking)
|
||||
{
|
||||
attackElapsed += Time.deltaTime;
|
||||
CheckAttackFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
if (movement == null || movement.IsMoving || animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
target = FindNearestEnemy();
|
||||
if (target == null || attackCooldown > 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FaceTarget(target);
|
||||
SetAttackAnimationSpeed();
|
||||
animator.SetInteger("speed", 0);
|
||||
animator.ResetTrigger("attack");
|
||||
animator.SetTrigger("attack");
|
||||
attacking = true;
|
||||
attackElapsed = 0f;
|
||||
attackEffectTriggered = false;
|
||||
}
|
||||
|
||||
public void OnAttackEffect()
|
||||
{
|
||||
if (attackEffectTriggered || !attacking || target == null || !target.activeInHierarchy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
attackEffectTriggered = true;
|
||||
FireProjectile(target);
|
||||
}
|
||||
|
||||
private void HandleSummonInput()
|
||||
{
|
||||
if (summoning || animator == null || movement == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Alpha1) || Input.GetKeyDown(KeyCode.Alpha2))
|
||||
{
|
||||
movement.StopMovement();
|
||||
if (attacking)
|
||||
{
|
||||
FinishAttack();
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Alpha1))
|
||||
{
|
||||
BeginSummon(humanSoldierPrefab);
|
||||
}
|
||||
else if (Input.GetKeyDown(KeyCode.Alpha2))
|
||||
{
|
||||
BeginSummon(archerPrefab);
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginSummon(GameObject prefab)
|
||||
{
|
||||
if (prefab == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pendingSummonPrefab = prefab;
|
||||
summonElapsed = 0f;
|
||||
summonSpawned = false;
|
||||
summoning = true;
|
||||
animator.speed = 1f;
|
||||
animator.SetInteger("speed", 0);
|
||||
animator.ResetTrigger("skill");
|
||||
animator.SetTrigger("skill");
|
||||
}
|
||||
|
||||
public void OnSkillHit1()
|
||||
{
|
||||
if (!summoning || summonSpawned || pendingSummonPrefab == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 direction = transform.forward;
|
||||
direction.y = 0f;
|
||||
direction.Normalize();
|
||||
|
||||
Vector3 spawnPosition;
|
||||
if (!TryFindSummonPosition(direction, out spawnPosition))
|
||||
{
|
||||
Debug.LogWarning("主角附近没有可用的召唤位置,本次召唤取消");
|
||||
FinishSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject summoned = Instantiate(
|
||||
pendingSummonPrefab,
|
||||
spawnPosition,
|
||||
Quaternion.LookRotation(direction, Vector3.up));
|
||||
summoned.tag = "Friend";
|
||||
summonSpawned = true;
|
||||
pendingSummonPrefab = null;
|
||||
Debug.Log("主角召唤单位:" + summoned.name + " position=" + spawnPosition);
|
||||
}
|
||||
|
||||
private bool TryFindSummonPosition(Vector3 direction, out Vector3 position)
|
||||
{
|
||||
Vector3 side = Vector3.Cross(Vector3.up, direction).normalized;
|
||||
Vector3[] directions = { direction, -direction };
|
||||
|
||||
foreach (Vector3 forward in directions)
|
||||
{
|
||||
for (int depthIndex = 0; depthIndex <= summonDepthSearchCount; depthIndex++)
|
||||
{
|
||||
float depthDistance = summonDistance + depthIndex * summonDepthSearchStep;
|
||||
Vector3 center = transform.position + forward * depthDistance;
|
||||
|
||||
for (int sideIndex = 0; sideIndex <= summonSearchCount; sideIndex++)
|
||||
{
|
||||
if (sideIndex == 0 && TryUseSummonCandidate(center, out position))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
float sideDistance = summonSideOffset + (sideIndex - 1) * summonSearchStep;
|
||||
if (sideIndex > 0)
|
||||
{
|
||||
if (TryUseSummonCandidate(center + side * sideDistance, out position)
|
||||
|| TryUseSummonCandidate(center - side * sideDistance, out position))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
position = transform.position;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryUseSummonCandidate(Vector3 candidate, out Vector3 position)
|
||||
{
|
||||
candidate.y = transform.position.y;
|
||||
if (IsInsideMovementBounds(candidate) && IsSummonPositionFree(candidate))
|
||||
{
|
||||
position = candidate;
|
||||
return true;
|
||||
}
|
||||
|
||||
position = transform.position;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsSummonPositionFree(Vector3 position)
|
||||
{
|
||||
const float radius = 0.55f;
|
||||
const float height = 2f;
|
||||
Vector3 center = position + Vector3.up * (height * 0.5f);
|
||||
Collider[] hits = Physics.OverlapCapsule(
|
||||
center - Vector3.up * (height * 0.5f - radius),
|
||||
center + Vector3.up * (height * 0.5f - radius),
|
||||
radius);
|
||||
|
||||
foreach (Collider hit in hits)
|
||||
{
|
||||
if (hit == null || hit.transform.root == transform.root)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hit.gameObject.name == "BattlePlatform" || hit.transform.root.name == "BattlePlatform")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hit.GetComponentInParent<MainCharacterDebugMovement>() != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsInsideMovementBounds(Vector3 position)
|
||||
{
|
||||
return movement == null || (position.x >= movement.xLimits.x && position.x <= movement.xLimits.y
|
||||
&& position.z >= movement.zLimits.x && position.z <= movement.zLimits.y);
|
||||
}
|
||||
|
||||
private void CheckSummonFinished()
|
||||
{
|
||||
if (summonElapsed >= summonAnimationTimeout)
|
||||
{
|
||||
Debug.LogWarning("主角召唤动画超时,已解除召唤状态");
|
||||
FinishSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
AnimatorClipInfo[] clips = animator.GetCurrentAnimatorClipInfo(0);
|
||||
foreach (AnimatorClipInfo clipInfo in clips)
|
||||
{
|
||||
string clipName = clipInfo.clip.name.ToLowerInvariant();
|
||||
if ((clipName.Contains("skill") || clipName.Contains("召唤"))
|
||||
&& animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1f)
|
||||
{
|
||||
FinishSummon();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FinishSummon()
|
||||
{
|
||||
summoning = false;
|
||||
summonSpawned = false;
|
||||
pendingSummonPrefab = null;
|
||||
summonElapsed = 0f;
|
||||
animator.speed = 1f;
|
||||
animator.SetInteger("speed", 0);
|
||||
}
|
||||
|
||||
private void CheckAttackFinished()
|
||||
{
|
||||
if (attackElapsed >= 2.4f)
|
||||
{
|
||||
FinishAttack();
|
||||
return;
|
||||
}
|
||||
|
||||
AnimatorClipInfo[] clips = animator.GetCurrentAnimatorClipInfo(0);
|
||||
bool playingAttack = false;
|
||||
foreach (AnimatorClipInfo clipInfo in clips)
|
||||
{
|
||||
string clipName = clipInfo.clip.name.ToLowerInvariant();
|
||||
if (clipName.Contains("attack") || clipName.Contains("攻击") || clipName.Contains("普攻"))
|
||||
{
|
||||
playingAttack = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!playingAttack)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1f)
|
||||
{
|
||||
FinishAttack();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAttackAnimationSpeed()
|
||||
{
|
||||
float clipDuration = GetAttackAnimationDuration();
|
||||
if (clipDuration > 0f && attackInterval > 0f)
|
||||
{
|
||||
animator.speed = clipDuration / attackInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
animator.speed = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
private float GetAttackAnimationDuration()
|
||||
{
|
||||
if (animator == null || animator.runtimeAnimatorController == null)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
var overrideController = animator.runtimeAnimatorController as AnimatorOverrideController;
|
||||
if (overrideController != null)
|
||||
{
|
||||
var overrides = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
||||
overrideController.GetOverrides(overrides);
|
||||
foreach (var pair in overrides)
|
||||
{
|
||||
if (IsAttackAnimation(pair.Key))
|
||||
{
|
||||
return pair.Value != null ? pair.Value.length : pair.Key.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var clip in animator.runtimeAnimatorController.animationClips)
|
||||
{
|
||||
if (IsAttackAnimation(clip))
|
||||
{
|
||||
return clip.length;
|
||||
}
|
||||
}
|
||||
|
||||
return 0f;
|
||||
}
|
||||
|
||||
private bool IsAttackAnimation(AnimationClip clip)
|
||||
{
|
||||
if (clip == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string clipName = clip.name.ToLowerInvariant();
|
||||
return clipName.Contains("attack")
|
||||
|| clipName.Contains("攻击")
|
||||
|| clipName.Contains("普攻");
|
||||
}
|
||||
|
||||
private void FinishAttack()
|
||||
{
|
||||
attacking = false;
|
||||
animator.speed = 1f;
|
||||
animator.SetInteger("speed", 0);
|
||||
}
|
||||
|
||||
private GameObject FindNearestEnemy()
|
||||
{
|
||||
GameObject nearest = null;
|
||||
float nearestDistance = attackRange * attackRange;
|
||||
|
||||
foreach (GameObject enemy in GameObject.FindGameObjectsWithTag("Enemy"))
|
||||
{
|
||||
if (enemy == null || enemy.transform.root == transform.root)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UnitBase enemyUnit = enemy.GetComponentInParent<UnitBase>();
|
||||
if (enemyUnit == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float distance = (enemy.transform.position - transform.position).sqrMagnitude;
|
||||
if (distance < nearestDistance)
|
||||
{
|
||||
nearest = enemy;
|
||||
nearestDistance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
private void FaceTarget(GameObject enemy)
|
||||
{
|
||||
Vector3 direction = enemy.transform.position - transform.position;
|
||||
direction.y = 0f;
|
||||
if (direction.sqrMagnitude > 0.001f)
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.LookRotation(direction, Vector3.up);
|
||||
transform.rotation = Quaternion.Euler(
|
||||
0f,
|
||||
targetRotation.eulerAngles.y + modelFacingOffset,
|
||||
0f);
|
||||
}
|
||||
}
|
||||
|
||||
private void FireProjectile(GameObject enemy)
|
||||
{
|
||||
if (projectilePrefab == null || attackPos == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject projectileObject = Instantiate(
|
||||
projectilePrefab,
|
||||
attackPos.position,
|
||||
attackPos.rotation);
|
||||
|
||||
Projectile projectile = projectileObject.GetComponent<Projectile>();
|
||||
if (projectile != null)
|
||||
{
|
||||
projectile.Initialize(
|
||||
enemy,
|
||||
attackPower,
|
||||
gameObject,
|
||||
projectileSpeed,
|
||||
projectileLifetime,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: WnkYtX+rAnnBKkBE7kheG2GT1inlULO90F2pbqBnDq5NsA1E9BUDHjY=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,120 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class MainCharacterDebugMovement : MonoBehaviour
|
||||
{
|
||||
[Header("电脑调试移动")]
|
||||
[Min(0f)]
|
||||
public float moveSpeed = 4f;
|
||||
|
||||
[Min(0f)]
|
||||
public float clickStopDistance = 0.08f;
|
||||
|
||||
[Header("移动范围")]
|
||||
public bool limitToBattlePlatform = true;
|
||||
public Vector2 xLimits = new Vector2(-7.5f, 7.5f);
|
||||
public Vector2 zLimits = new Vector2(-14f, 14f);
|
||||
|
||||
private Animator animator;
|
||||
private Vector3 clickTarget;
|
||||
private bool hasClickTarget;
|
||||
|
||||
public bool IsMoving =>
|
||||
hasClickTarget ||
|
||||
new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")).sqrMagnitude > 0.001f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
clickTarget = transform.position;
|
||||
SetWalking(false);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
HandleClickTarget();
|
||||
|
||||
Vector3 keyboardInput = new Vector3(
|
||||
Input.GetAxisRaw("Horizontal"),
|
||||
0f,
|
||||
Input.GetAxisRaw("Vertical"));
|
||||
|
||||
if (keyboardInput.sqrMagnitude > 0.001f)
|
||||
{
|
||||
hasClickTarget = false;
|
||||
Move(keyboardInput.normalized);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasClickTarget)
|
||||
{
|
||||
SetWalking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 toTarget = clickTarget - transform.position;
|
||||
toTarget.y = 0f;
|
||||
|
||||
if (toTarget.magnitude <= clickStopDistance)
|
||||
{
|
||||
hasClickTarget = false;
|
||||
SetWalking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Move(toTarget.normalized);
|
||||
}
|
||||
|
||||
private void HandleClickTarget()
|
||||
{
|
||||
if (!Input.GetMouseButtonDown(0) || Camera.main == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||||
if (!Physics.Raycast(ray, out RaycastHit hit))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
clickTarget = hit.point;
|
||||
clickTarget.y = transform.position.y;
|
||||
hasClickTarget = true;
|
||||
}
|
||||
|
||||
public void StopMovement()
|
||||
{
|
||||
hasClickTarget = false;
|
||||
SetWalking(false);
|
||||
}
|
||||
|
||||
private void Move(Vector3 direction)
|
||||
{
|
||||
direction.y = 0f;
|
||||
if (direction.sqrMagnitude <= 0.001f)
|
||||
{
|
||||
SetWalking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SetWalking(true);
|
||||
transform.position += direction * moveSpeed * Time.deltaTime;
|
||||
if (limitToBattlePlatform)
|
||||
{
|
||||
Vector3 position = transform.position;
|
||||
position.x = Mathf.Clamp(position.x, xLimits.x, xLimits.y);
|
||||
position.z = Mathf.Clamp(position.z, zLimits.x, zLimits.y);
|
||||
transform.position = position;
|
||||
}
|
||||
|
||||
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
|
||||
}
|
||||
|
||||
private void SetWalking(bool walking)
|
||||
{
|
||||
if (animator != null)
|
||||
{
|
||||
animator.SetInteger("speed", walking ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: DHMctiyoUnrORLV18FW6uvy2W4XUZc7eP9cxqqF66lJHMKIBMdqNSf4=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -28,6 +28,13 @@ public class Projectile : MonoBehaviour
|
||||
initialized = true;
|
||||
hasHit = false;
|
||||
|
||||
// The projectile uses its own raycast hit check. Disable the collider so
|
||||
// it cannot be destroyed or disturbed by the owner's launch socket.
|
||||
foreach (var collider in GetComponentsInChildren<Collider>(true))
|
||||
{
|
||||
collider.enabled = false;
|
||||
}
|
||||
|
||||
if (lifetime > 0f)
|
||||
{
|
||||
Destroy(gameObject, lifetime);
|
||||
@@ -107,14 +114,14 @@ public class Projectile : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
WorldHealthBar healthBar = hitObject.GetComponentInParent<WorldHealthBar>();
|
||||
if (healthBar == null)
|
||||
UnitBase targetUnit = hitObject.GetComponentInParent<UnitBase>();
|
||||
if (targetUnit == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hasHit = true;
|
||||
healthBar.TakeDamage(damage);
|
||||
targetUnit.ReceiveDamage(damage, owner);
|
||||
if (registerEnergyOnHit && owner != null)
|
||||
{
|
||||
UnitBase unit = owner.GetComponent<UnitBase>();
|
||||
|
||||
@@ -7,7 +7,10 @@ public class ShieldGuardSkill : UnitSkill
|
||||
public float shieldDurability = 220f;
|
||||
|
||||
[Min(0.1f)]
|
||||
public float shieldDuration = 6f;
|
||||
public float shieldDuration = 4f;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
public float damageReduction = 0.35f;
|
||||
|
||||
public Vector3 shieldLocalPosition = new Vector3(0f, 1f, 0.7f);
|
||||
|
||||
@@ -23,6 +26,21 @@ public class ShieldGuardSkill : UnitSkill
|
||||
shield.Refresh(shieldDurability, shieldDuration, shieldLocalPosition, shieldSize);
|
||||
}
|
||||
|
||||
public override float ModifyIncomingDamage(float damage, GameObject attacker)
|
||||
{
|
||||
if (shield == null || !shield.IsActive)
|
||||
{
|
||||
return damage;
|
||||
}
|
||||
|
||||
if (shield.TryBlock(attacker, damage))
|
||||
{
|
||||
return damage * (1f - damageReduction);
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
private void EnsureShield()
|
||||
{
|
||||
if (shield != null)
|
||||
|
||||
@@ -223,6 +223,33 @@ public class UnitBase : MonoBehaviour
|
||||
EnsureStatusEffectController().ApplyStun(duration);
|
||||
}
|
||||
|
||||
public float ModifyIncomingDamage(float damage, GameObject attacker)
|
||||
{
|
||||
if (damage <= 0f)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
if (unitSkill == null)
|
||||
{
|
||||
return damage;
|
||||
}
|
||||
|
||||
return unitSkill.ModifyIncomingDamage(damage, attacker);
|
||||
}
|
||||
|
||||
public bool ReceiveDamage(float damage, GameObject attacker = null)
|
||||
{
|
||||
WorldHealthBar healthBar = GetComponent<WorldHealthBar>();
|
||||
if (healthBar == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
healthBar.TakeDamage(ModifyIncomingDamage(damage, attacker));
|
||||
return true;
|
||||
}
|
||||
|
||||
//根据自身Tag找到敌对Tag
|
||||
private string GetOpponentTag()
|
||||
{
|
||||
@@ -516,13 +543,12 @@ public class UnitBase : MonoBehaviour
|
||||
|
||||
private void ApplyDirectDamage(GameObject opponent)
|
||||
{
|
||||
WorldHealthBar healthBar = opponent.GetComponentInParent<WorldHealthBar>();
|
||||
if (healthBar == null)
|
||||
UnitBase targetUnit = opponent.GetComponentInParent<UnitBase>();
|
||||
if (targetUnit == null || !targetUnit.ReceiveDamage(attackPower, gameObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
healthBar.TakeDamage(attackPower);
|
||||
RegisterAttackHit();
|
||||
}
|
||||
|
||||
@@ -533,13 +559,12 @@ public class UnitBase : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
WorldHealthBar healthBar = target.GetComponentInParent<WorldHealthBar>();
|
||||
if (healthBar == null)
|
||||
UnitBase targetUnit = target.GetComponentInParent<UnitBase>();
|
||||
if (targetUnit == null || !targetUnit.ReceiveDamage(attackPower * Mathf.Max(0f, damageMultiplier), gameObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
healthBar.TakeDamage(attackPower * Mathf.Max(0f, damageMultiplier));
|
||||
if (registerEnergy)
|
||||
{
|
||||
RegisterAttackHit();
|
||||
@@ -578,13 +603,19 @@ public class UnitBase : MonoBehaviour
|
||||
continue;
|
||||
}
|
||||
|
||||
WorldHealthBar healthBar = opponent.GetComponentInParent<WorldHealthBar>();
|
||||
UnitBase targetUnit = opponent.GetComponentInParent<UnitBase>();
|
||||
if (targetUnit == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
WorldHealthBar healthBar = targetUnit.GetComponent<WorldHealthBar>();
|
||||
if (healthBar == null || !hitHealthBars.Add(healthBar))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
healthBar.TakeDamage(damage);
|
||||
targetUnit.ReceiveDamage(damage, gameObject);
|
||||
}
|
||||
|
||||
if (registerEnergy)
|
||||
|
||||
@@ -10,4 +10,9 @@ public abstract class UnitSkill : MonoBehaviour
|
||||
}
|
||||
|
||||
public abstract void ReleaseSkill();
|
||||
|
||||
public virtual float ModifyIncomingDamage(float damage, GameObject attacker)
|
||||
{
|
||||
return damage;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user