using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using UnityEngine; using Debug = UnityEngine.Debug; using DG.Tweening; public class Attack : MonoBehaviour { [Header("子弹预制体")] public GameObject bulletPrefab; [Header("子弹数据")] public BulletData bulletData; [Header("角色对象")] public Role role; //[Header("攻击范围")] public float attackScope; [Header("攻击类型")] public DamageType damageTyp = DamageType.noAttributeDamage; [Header("攻击CD时间")] public float attackCooldown = 1f; // 攻击冷却时间 private float lastAttackTime = 0f; // 上次攻击的时间 [HideInInspector] public List bulltes = new List(); [Header("角色动画控制器")] public Animator animator; //[Header("火焰动画控制器")] public Animator fireAni; [Header("火焰动画控制器")] public List fireAnis; [Header("子弹起始点")] public Transform BulletStartPos; [Header("攻击速度")] public float AttackSpeed = 1f; public Vector2 direction; [Header("子弹速度加成")] public float roleBulletSpeedAdd = 0f; //[Header("子弹长度")] public float scaleFactor; [Header("子弹数量")] public int BulletNumber = 1; [Header("攻击碰撞体")] public CircleCollider2D attackCollider; [Header("矩形攻击碰撞体")] public BoxCollider2D attackColliderBox; [Header("攻击范围图片")] public SpriteRenderer attackRangeSprite; [Header("攻击持续时间")] public float AttackStayTime;// [Header("攻击目标")] public GameObject Target; [Header("攻击范围显示脚本")] public CharacterClick characterClick; [Header("攻击随机角度范围")] public float Angle=30; [Header("子弹分裂个数")] public int splitNum = 2; [Header("分裂子弹伤害")] public float SplitAttack = 10; [Header("子弹围绕范围")] public float RunRange = 3f; [Header("是否造成额外伤害")] public bool haveAddDamage = false; [Header("额外伤害类型")] public DamageType AdddamageType=DamageType.magicDamage; [Header("子弹爆炸范围")] public float BoomRange = 1; public bool isAttack = true; public bool flag = false; [HideInInspector] public float timer = 0; public async void Start() { bulletData = new BulletData(); bulletData.BulletScattering = 1; //animator.SetFloat("AttackSpeed", AttackSpeed); attackCooldown = transform.parent.GetComponent().AttackCD; SetAttackRange(); // 设置攻击范围 while (isAttack) { if (attackCollider || attackColliderBox) { // 检查是否可以进行攻击(基于冷却时间) if (Time.time - lastAttackTime >= attackCooldown) { if (attackCollider) { Collider2D[] colliders = Physics2D.OverlapCircleAll(attackCollider.transform.position, attackCollider.radius); GetAllColliderInAttackRange(colliders); } else if (attackColliderBox) { // 获取碰撞体的尺寸 Vector2 boxSize = attackColliderBox.size; // 只检测右边一半,修改尺寸 boxSize.x /= 2f; // 获取碰撞体的中心位置 Vector3 colliderCenter = attackColliderBox.transform.position; // 计算右半部分的中心位置,确保中心点在矩形的右半部分 Vector3 rightCenter = new Vector3(colliderCenter.x + attackColliderBox.size.x / 4f, colliderCenter.y, colliderCenter.z); // 使用OverlapBoxAll检测右半部分区域 Collider2D[] colliders = Physics2D.OverlapBoxAll(rightCenter, boxSize, 0f); GetAllColliderInAttackRange(colliders); } lastAttackTime = Time.time; // 更新上次攻击时间 } await Task.Delay(100); // 延迟,避免过于频繁地检测 } else { return; } } } private void Update() { if (flag) { timer += Time.deltaTime; if (timer > AttackStayTime) { animator.SetInteger("State", 0); isAttack = true; timer = 0; flag = false; } } //Debug.Log(role.name+"攻击范围的图片大小"+attackRangeSprite.transform.localScale + "color" + attackRangeSprite.color+ "color.a" + attackRangeSprite.color.a + "是否显示"+ attackRangeSprite.enabled); } public void GetAllColliderInAttackRange(Collider2D[] colliders) { foreach (Collider2D collider in colliders) { Role targetRole = collider.GetComponent(); if (targetRole && targetRole.camp != role.camp) { role.animationHighlight = 1; if (animator != null) { if (bulletPrefab.GetComponent().myBulletType != BulletType.Spraying) { direction = (targetRole.transform.position - BulletStartPos.position).normalized; Target = targetRole.gameObject; animator.SetTrigger("Attack"); } else if (bulletPrefab.GetComponent().myBulletType == BulletType.Spraying|| bulletPrefab.GetComponent().myBulletType==BulletType.XuLi) { animator.SetInteger("State", 1); flag = true; } lastAttackTime = Time.time; // 更新上次攻击时间 } break; // 只攻击一个目标 } else { if (animator != null) { //animator.SetInteger("State", 0); } else { role.animationHighlight = 0; } } } } public void Pointattack() { if (bulletPrefab == null) { Debug.LogError("子弹预制体为空"); return; } for (int i = 0; i < BulletNumber; i++) { // 改变子弹方向,根据角色自身的攻击范围来计算 GameObject BulletGamobj = GameObject.Instantiate(bulletPrefab, this.transform.root); BulletGamobj.GetComponent().role = role; BulletGamobj.GetComponent().attackObj = this; BulletGamobj.GetComponent().bulletData.BulletSpeed *= (1 + roleBulletSpeedAdd); BulletGamobj.GetComponent().Target = Target; BulletGamobj.transform.up = direction; BulletGamobj.transform.position = BulletStartPos.position; bulltes.Add(BulletGamobj); } } public void Fireattack() { if (bulletPrefab == null) { Debug.LogError("子弹预制体为空"); return; } // 检查子弹类型是否为 Spraying if (bulletPrefab.GetComponent().myBulletType == BulletType.Spraying) { // 根据 BulletNumber 生成不同数量和旋转角度的子弹 switch (BulletNumber) { case 1: // 生成一个不旋转的子弹 GenerateBullet(0f, BulletStartPos.position, new Vector2(0, 0)); break; case 3: // 生成三个子弹:一个不旋转,一个向上旋转30度,一个向下旋转30度 GenerateBullet(-35f, BulletStartPos.position, new Vector2(0, -0.25f)); GenerateBullet(0f, BulletStartPos.position, new Vector2(0, 0)); GenerateBullet(35f, BulletStartPos.position, new Vector2(0, 0.25f)); break; default: // 可选:处理其他 BulletNumber 值的情况 Debug.LogWarning($"BulletNumber 为 {BulletNumber} 时未定义的生成逻辑。"); break; } } } private void GenerateBullet(float angle, Vector2 startPos, Vector2 changePos) { // 实例化子弹对象并设置父物体为 transform.root GameObject bulletGameObj = GameObject.Instantiate(bulletPrefab, transform.root); // 获取子弹的原始宽度 float originalWidth = bulletGameObj.GetComponentInChildren().bounds.size.x; // 保存原始位置,以便在攻击范围变化时恢复 Vector2 originalPosition = bulletGameObj.transform.position; // 设置子弹的缩放 if (role.AttackRange / 2 > 1) { float offsetX = 0; bulletGameObj.transform.localScale = new Vector2(role.AttackRange / 2, role.AttackRange / 3); // 计算新的子弹宽度 float newWidth = bulletGameObj.GetComponentInChildren().bounds.size.x; //// 根据宽度变化计算偏移量 //if (newWidth > originalWidth) //{ // // 如果新宽度大于原始宽度,计算向右的偏移 // offsetX = (originalWidth * (role.AttackRange / 2)) / 4f + 0.15f; //} //else if (newWidth < originalWidth) //{ // // 如果新宽度小于原始宽度,计算向左的偏移 // offsetX = -((originalWidth * (role.AttackRange / 2)) / 4f +0.15f); //} offsetX = (newWidth - originalWidth) / 2; if (offsetX > 0) { offsetX += 0.15f; } // 调整子弹的位置,确保左边界不变 bulletGameObj.transform.position = new Vector2(originalPosition.x + offsetX, originalPosition.y); } // 添加位置微调 bulletGameObj.transform.position = new Vector2(bulletGameObj.transform.position.x + 1.75f, bulletGameObj.transform.position.y + 0.2f); // 获取动画组件(如果需要的话) fireAnis.Add(bulletGameObj.GetComponentInChildren()); // 设置子弹的初始属性 bulletGameObj.GetComponent().role = role; bulletGameObj.GetComponent().attackObj = this; // 计算子弹相对于旋转中心的偏移 Vector2 direction = bulletGameObj.transform.position - (Vector3)startPos; // 旋转偏移 direction = Quaternion.Euler(0, 0, angle) * direction; // 更新子弹的位置 bulletGameObj.transform.position = startPos + direction; // 设置子弹的旋转角度 bulletGameObj.transform.rotation = Quaternion.Euler(0, 0, angle); // 根据变化调整位置(例如“changePos”可能需要与原始位置结合使用) bulletGameObj.transform.position = bulletGameObj.transform.position + (Vector3)changePos; // 将生成的子弹添加到子弹列表中 bulltes.Add(bulletGameObj); } public void EndFire() { foreach (Animator ani in fireAnis) { ani.SetInteger("State", 1); } fireAnis.Clear(); //Debug.Log("停止火焰"); } private void OnDisable() { bulltes.Clear(); } public void SetAttackRange() { if (attackCollider&& role.AttackRange !=0) { // 设置碰撞体的半径 attackCollider.radius = role.AttackRange+2f; // 计算缩放因子,使得图片的直径与碰撞体的直径匹配 characterClick.OrSizeX = (role.AttackRange+2f) * 2f / characterClick.StartSizeX; // * 2f 因为 radius 是半径,图片的尺寸通常是直径 characterClick.OrSizeY = characterClick.OrSizeX; } else if(attackColliderBox) { Vector2 boxSize = attackColliderBox.size; // 假设攻击范围决定了矩形的长宽比 // attackRange * 2 可以增加攻击范围的矩形尺寸,调整比例或常数以适应你的需要 boxSize.x = role.AttackRange* 2f + 2; // 设置矩形宽度 //boxSize.y = role.AttackRange/3; // 设置矩形高度 // 更新矩形碰撞体的尺寸 attackColliderBox.size = boxSize; characterClick.OrSizeX = boxSize.x / characterClick.StartSizeX; // * 2f 因为 radius 是半径,图片的尺寸通常是直径 characterClick.OrSizeY = boxSize.y * 2 / characterClick.StartSizeY; float offSetX = (characterClick.StartSizeX - characterClick.OrSizeX) / 2; if (role.AttackRange==3) { offSetX += 0.6f; } attackRangeSprite.transform.position = new Vector2(attackRangeSprite.transform.position.x - offSetX, attackRangeSprite.transform.position.y); //characterClick.OrSizeY = 1; Debug.Log("修改图片宽度"); } } public void RandPointattack()//在一个角度随机发射子弹 仓鼠攻击方式 { if (bulletPrefab == null) { Debug.LogError("子弹预制体为空"); return; } for (int i = 0; i < BulletNumber; i++) { // 改变子弹方向, 根据角色自身的攻击范围来计算 GameObject BulletGamobj = GameObject.Instantiate(bulletPrefab, this.transform.root); BulletGamobj.GetComponent().role = role; BulletGamobj.GetComponent().attackObj = this; BulletGamobj.GetComponent().bulletData.BulletSpeed *= (1 + roleBulletSpeedAdd); BulletGamobj.GetComponent().Target = Target; // 计算一个随机偏移角度,在-15度到+15度之间 float randomAngle = Random.Range(-Angle/2, Angle/2); Debug.Log("土角度"+Angle); // 将原始方向转换为角度 float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; // 加上随机偏移角度 angle += randomAngle; // 将角度转换回方向 direction = new Vector2(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad)); // 设置子弹的方向 BulletGamobj.transform.up = direction; // 设置子弹的起始位置 BulletGamobj.transform.position = BulletStartPos.position; // 将子弹添加到列表中 bulltes.Add(BulletGamobj); } } public void ShanXingAttack() // 扇形散射 { if (bulletPrefab == null) { Debug.LogError("子弹预制体为空"); return; } float halfAngle = Angle / 2f; // 半个散射角度范围 float angleStep = Angle / (BulletNumber - 1); // 每个子弹之间的角度间隔 for (int i = 0; i < BulletNumber; i++) { // 创建子弹实例 GameObject BulletGamobj = GameObject.Instantiate(bulletPrefab, this.transform.root); Bullet bulletScript = BulletGamobj.GetComponent(); // 设置子弹的基本信息 bulletScript.role = role; bulletScript.attackObj = this; bulletScript.bulletData.BulletSpeed *= (1 + roleBulletSpeedAdd); // 根据角色的加成调整子弹速度 bulletScript.Target = Target; // 计算当前子弹的发射角度 float currentAngle = -halfAngle + angleStep * i; // 当前子弹的偏移角度 // 使用偏移角度调整子弹的发射方向 // 只在z轴上进行旋转(2D场景) if (BulletNumber==1) { BulletGamobj.transform.up = direction; } else { Vector3 scatterDirection = Quaternion.Euler(0, 0, currentAngle) * direction; // 只旋转z轴 // 设置子弹的方向和位置 BulletGamobj.transform.up = scatterDirection; } BulletGamobj.transform.position = BulletStartPos.position; // 将子弹加入子弹列表 bulltes.Add(BulletGamobj); } } private int lastBulletNumber = 0; // 记录上一次的 BulletNumber private float lastbulletLengthAdd = 0; // 记录上一次的 BulletNumber public float bulletLengthAdd = 0f; // 子弹的长度属性 public void RunRangeattack() // 生成在周围 { if (bulletPrefab == null) { // Debug.LogError("子弹预制体为空"); return; } // 只有在 BulletNumber 变化时,才重新生成子弹 if (BulletNumber != lastBulletNumber||lastbulletLengthAdd!=bulletLengthAdd) // 检查 BulletNumber 和 bulletLength 是否变化 { // 销毁现有的所有子弹 if (bulltes.Count > 0) { foreach (var bullet in bulltes) { Destroy(bullet); // 销毁子弹对象 } bulltes.Clear(); // 清空子弹列表 } // 计算子弹发射的圆周角度间隔 float angleStep = 360f / BulletNumber; // 计算每个子弹之间的角度间隔 // 生成新的子弹 for (int i = 0; i < BulletNumber; i++) { // 创建子弹实例 GameObject BulletGamobj = GameObject.Instantiate(bulletPrefab, this.transform.root); // 获取Bullet组件 RunRangeBullet bulletScript = BulletGamobj.GetComponent(); // 设置子弹的基本信息 bulletScript.role = role; bulletScript.attackObj = this; bulletScript.bulletData.BulletSpeed *= (1 + roleBulletSpeedAdd); // 根据角色的加成调整子弹速度 bulletScript.Target = Target; // 将新子弹加入子弹列表 bulltes.Add(BulletGamobj); // 计算当前子弹的发射角度(基于子弹的索引) float currentAngle = angleStep * i; // 当前子弹的发射角度 // 计算子弹的发射位置,使用极坐标来计算圆周上的位置 float x = Mathf.Cos(Mathf.Deg2Rad * currentAngle) * RunRange; float y = Mathf.Sin(Mathf.Deg2Rad * currentAngle) * RunRange; Vector3 position = new Vector3(x, y, 0) + BulletStartPos.position; // 加上起始位置 // 计算子弹的发射方向,使用极坐标转换为单位向量 Vector3 scatterDirection = new Vector3(Mathf.Cos(Mathf.Deg2Rad * currentAngle), Mathf.Sin(Mathf.Deg2Rad * currentAngle), 0); // 设置子弹的朝向和位置 BulletGamobj.transform.up = scatterDirection; // 让子弹的"up"方向指向计算出的角度 BulletGamobj.transform.position = position; // 更新子弹的位置 if (lastbulletLengthAdd != bulletLengthAdd) { // 根据 bulletLength 设置子弹的长度 BulletGamobj.transform.localScale = new Vector3(BulletGamobj.transform.localScale.x + bulletLengthAdd, BulletGamobj.transform.localScale.y, BulletGamobj.transform.localScale.z); } } // 更新记录的 BulletNumber 和 bulletLength lastBulletNumber = BulletNumber; lastbulletLengthAdd = bulletLengthAdd; } } }