From 5bff5da7130af8e209b42fa803bfd67fc475991e Mon Sep 17 00:00:00 2001 From: Roman <1325980292@qq.com> Date: Fri, 10 Dec 2021 00:23:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=EF=BC=9A=E6=90=AD=E5=BB=BA?= =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E7=9A=84=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.修改爱欲品类,解决多个附身的问题 (1.已有变量标记玩家是否正被抓着 (*.当玩家被爱欲品抓住,让玩家记住这个爱欲品,用来后面被多个缠上时清空它的挣脱次数 (2.当爱欲品创到玩家,检查目前是否已经被附身,若是,使用父类的touched函数,也就是普通小怪的,用来创飞玩家,同时,清空当前附身着的爱欲品的挣脱次数 (3.修改爱欲品附身时的跟踪方式,原先为一次定位后不再更改,但如果遇到多只爱欲品的情况,则可能被击飞,此时附身中的爱欲品不会跟踪。修改至攻击中每帧重新定位。 2.编写地藏的敲钟攻击逻辑 (1.钟上浮Tween动画 (2.Tween动画结束事件,开启开关,同时StartContinue,等待一定时间后关闭开关,用来触发攻击结束事件 (3.开关打开时,每帧向玩家发射射线,若能击中玩家,受伤方式等待讨论确认。若不能,则无事可做。 3.整理脚本结构,编写注释、摘要和分层 至此,地藏的敲钟攻击逻辑基本完成 --- Assets/Scenes/DiZangStageTest.unity | 16 ++- Assets/Scripts/AiYuPin.cs | 55 +++++++--- Assets/Scripts/Bell.cs | 153 ++++++++++++++++++++++++++++ Assets/Scripts/DiZang.cs | 122 ++++++++++++++-------- Assets/Scripts/MyPlayer.cs | 25 +++-- 5 files changed, 298 insertions(+), 73 deletions(-) diff --git a/Assets/Scenes/DiZangStageTest.unity b/Assets/Scenes/DiZangStageTest.unity index 649dc28..a0bc79c 100644 --- a/Assets/Scenes/DiZangStageTest.unity +++ b/Assets/Scenes/DiZangStageTest.unity @@ -333,7 +333,7 @@ GameObject: - component: {fileID: 552131608} - component: {fileID: 552131610} - component: {fileID: 552131611} - m_Layer: 0 + m_Layer: 2 m_Name: "\u5730\u85CF" m_TagString: Untagged m_Icon: {fileID: 0} @@ -425,7 +425,7 @@ MonoBehaviour: canBeHit: 1 state: 0 HPLeft: 0 - timeBetweenAttacks: 1 + timeBetweenAttacks: 5 aiYuPinBuildLimit: 0 aiYuPin: {fileID: 7746389308535175434, guid: 6d2fc6e5da22cf748b7c6730494b0460, type: 3} throwingPointGroupUp: @@ -434,7 +434,7 @@ MonoBehaviour: throwingPointGroupDown: - {fileID: 28312535} - {fileID: 2059592404} - CallAiYuPinEndTime: 0 + CallAiYuPinEndTime: 5 --- !u!61 &552131611 BoxCollider2D: m_ObjectHideFlags: 0 @@ -776,6 +776,7 @@ MonoBehaviour: inControl: 1 HPLeft: 0 isCatching: 0 + catingAiYuPin: {fileID: 0} --- !u!50 &761593106 Rigidbody2D: serializedVersion: 4 @@ -1509,7 +1510,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1226109627} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0.037863016, y: -1.6225317, z: -10} + m_LocalPosition: {x: 0.037861586, y: -1.6225245, z: -10} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} @@ -2511,6 +2512,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: eb1ead91b6d7c9949b86dadd3704ba8d, type: 3} m_Name: m_EditorClassIdentifier: + upDistance: 2 + atkTime: 5 + owner: {fileID: 0} + upTime: 2 + isAtking: 0 --- !u!1 &1954591986 GameObject: m_ObjectHideFlags: 0 @@ -2834,7 +2840,7 @@ GameObject: m_Component: - component: {fileID: 2132302663} - component: {fileID: 2132302662} - m_Layer: 0 + m_Layer: 2 m_Name: "\u76F8\u673A\u79FB\u52A8\u8303\u56F4" m_TagString: Untagged m_Icon: {fileID: 0} diff --git a/Assets/Scripts/AiYuPin.cs b/Assets/Scripts/AiYuPin.cs index cd232b5..3b093a0 100644 --- a/Assets/Scripts/AiYuPin.cs +++ b/Assets/Scripts/AiYuPin.cs @@ -43,6 +43,10 @@ public class AiYuPin : NormalEnemy /// //虽说是目标,但爱欲品只会抓玩家吧。直接初始化成玩家了 protected Transform target; + /// + /// 记录当前自己是否抓着玩家 + /// + private bool isCatching = false; // _____ _ _ ____ _ // / ____| | | | _ \ | | @@ -53,6 +57,12 @@ public class AiYuPin : NormalEnemy void Update(){ //如果在Seek状态,则Seek if(state == State.seek) Seek(target); + if(isCatching){ + //将自身位置和玩家位置同步,但是需要一个附身offset二维向量 + //因为玩家的图片不在游戏物体的中心 + transform.position = target.position + catchOffset; + } + } // _ _ _ @@ -114,21 +124,34 @@ public class AiYuPin : NormalEnemy /// protected override void OnTouchThePlayer(MyPlayer player) { - //通知玩家,你被爱欲品附身了 - player.BeCatchedByAiYuPin(this); - //暂停Path动画 - doTweenPath.DOPause(); - //改变自身状态为ATK - state = State.atk; - //关闭自身碰撞体,因为要贴在玩家身上 - GetComponent().enabled = false; - //将自身位置和玩家位置同步,但是需要一个附身offset二维向量 - //因为玩家的图片不在游戏物体的中心 - transform.position = target.position + catchOffset; - //暂时清空重力系数 - m_rigidbody.gravityScale = 0; - //清除一下刚体速度,不然怪物可能被创飞 - m_rigidbody.velocity = Vector2.zero; + //如果玩家没有被抓住,才执行抓住 + if(!player.isCatching){ + //通知玩家,你被爱欲品附身了 + player.BeCatchedByAiYuPin(this); + //暂停Path动画 + doTweenPath.DOPause(); + //改变自身状态为ATK + state = State.atk; + //关闭自身碰撞体,因为要贴在玩家身上 + GetComponent().enabled = false; + //将自身位置和玩家位置同步,但是需要一个附身offset二维向量 + //因为玩家的图片不在游戏物体的中心 + transform.position = target.position + catchOffset; + //暂时清空重力系数 + m_rigidbody.gravityScale = 0; + //清除一下刚体速度,不然怪物可能被创飞 + m_rigidbody.velocity = Vector2.zero; + //清除角动量,不然可能会转起来 + m_rigidbody.angularVelocity = 0; + //标记自身正抓着玩家 + isCatching = true; + } + //如果玩家正被抓着,则执行父类——普通小怪的Touch,即击飞玩家 + else{ + base.OnTouchThePlayer(player); + //同时,清空当前附身着的爱欲品的挣脱次数 + player.catingAiYuPin.breakFreeCountLeft = breakFreeCount; + } } /// @@ -157,6 +180,8 @@ public class AiYuPin : NormalEnemy m_rigidbody.gravityScale = 1; //随机一个死亡面部朝向 deadDir = (Random.Range(-1f,1f) > 0) ? 1: -1; + //标记自身不再抓着玩家 + isCatching = false; //触发死亡事件 OnDead(); //给一个击飞 diff --git a/Assets/Scripts/Bell.cs b/Assets/Scripts/Bell.cs index 09852e3..ae6ccb9 100644 --- a/Assets/Scripts/Bell.cs +++ b/Assets/Scripts/Bell.cs @@ -2,15 +2,168 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; +using Sirenix.OdinInspector; /// /// 撞钟类,控制地藏头上的钟 /// public class Bell : MonoBehaviour { + // _____ _ _ _ + // | __ \ | | | (_) + // | |__) | _| |__ | |_ ___ + // | ___/ | | | '_ \| | |/ __| + // | | | |_| | |_) | | | (__ + // |_| \__,_|_.__/|_|_|\___| + + /// + /// 攻击前置动作钟上浮多少距离 + /// + [Header("攻击前置动作钟上浮多少距离")] + public float upDistance; + /// + /// 攻击将会持续多长时间 + /// + [Header("攻击将会持续多长时间")] + public float atkTime; + /// + /// 主人,也就是地藏Boss + /// + [HideInInspector] + public DiZang owner; + /// + /// 钟飞上去将要花费多少时间(降下来也是这个值) + /// + [Header("钟飞上去将要花费多少时间(降下来也是这个值)")] + public float upTime; + + // _____ _ _ + // | __ \ (_) | | + // | |__) | __ ___ ____ _| |_ ___ + // | ___/ '__| \ \ / / _` | __/ _ \ + // | | | | | |\ V / (_| | || __/ + // |_| |_| |_| \_/ \__,_|\__\___| + + /// + /// 当前正在攻击吗 + /// + [SerializeField][Button][ReadOnly][Header("当前正在攻击吗(不包括钟上下过程))")] + private bool isAtking = false; + private MyPlayer player; + /// + /// 浮动动画,用来重启浮动动画解决Tween的一些局限性问题 + /// + private Tweener floatTweener; + + // _____ _ _ ____ _ + // / ____| | | | _ \ | | + // | | __ _| | | |_) | __ _ ___| | __ + // | | / _` | | | _ < / _` |/ __| |/ / + // | |___| (_| | | | |_) | (_| | (__| < + // \_____\__,_|_|_|____/ \__,_|\___|_|\_\ + void Start(){ + //启动浮动动画 + RestartFloat(); + } + + void Update(){ + //如果钟正在攻击 + if(isAtking){ + //创建一条从钟射向玩家的射线 + Ray2D ray = new Ray2D( + (Vector2)transform.position, + (Vector2)( player.transform.position - transform.position) + ); + Debug.DrawRay(ray.origin,ray.direction * 1500,Color.red); + //获取射线的碰撞结果 + RaycastHit2D hit2D; + hit2D = Physics2D.Raycast(ray.origin,ray.direction); + if(hit2D){ + Debug.Log(hit2D.collider.name); + } + } + } + + + // _ _ _ + // | \ | | | | + // | \| | ___ _ __ _ __ ___ __ _| | + // | . ` |/ _ \| '__| '_ ` _ \ / _` | | + // | |\ | (_) | | | | | | | | (_| | | + // |_| \_|\___/|_| |_| |_| |_|\__,_|_| + + /// + /// 介于Tweener的特性,经常需要重新创建钟浮动的动画 + /// + private void RestartFloat(){ + if(floatTweener != null){ + floatTweener.Kill(); + } Tweener tweener = transform.DOShakePosition(5f,0.3f,1,150,false,false); tweener.SetLoops(-1); tweener.SetEase(Ease.InQuad); + floatTweener = tweener; } + + // ______ _ + // | ____| | | + // | |____ _____ _ __ | |_ + // | __\ \ / / _ \ '_ \| __| + // | |___\ V / __/ | | | |_ + // |______\_/ \___|_| |_|\__| + + /// + /// 从主人那里得到攻击指令后触发 + /// + public void ATK(MyPlayer player){ + //指定一下攻击目标 + this.player = player; + //创建和执行上浮动画 + Tweener tweener = transform.DOLocalMoveY( + transform.position.y + upDistance, + upTime + ); + //创建并加入上浮动画结束事件 + TweenCallback action = () => { + //标记自己开始攻击 + isAtking = true; + //重启浮动动画 + RestartFloat(); + //等待攻击结束 + StartCoroutine(WaitAndTurnDownThebutton()); + }; + tweener.OnComplete(action); + } + + /// + /// 上浮动画结束的时候触发 + /// + /// + private IEnumerator WaitAndTurnDownThebutton(){ + //等待攻击时长结束 + yield return new WaitForSeconds(atkTime); + //标记攻击结束 + isAtking = false; + //触发自身攻击结束功能 + ATKEnd(); + } + + /// + /// 攻击结束的时候触发 + /// + private void ATKEnd(){ + //创建动画让钟回去 + Tweener tweener = + transform.DOMoveY(transform.position.y - upDistance,upTime); + //创建和添加结束事件 + TweenCallback action = () => { + //重启浮动动画 + RestartFloat(); + //告诉主人,攻击结束,开始下一个轮回 + owner.ATKEnd(); + }; + tweener.OnComplete(action); + } + } diff --git a/Assets/Scripts/DiZang.cs b/Assets/Scripts/DiZang.cs index bba0c57..e9db6ec 100644 --- a/Assets/Scripts/DiZang.cs +++ b/Assets/Scripts/DiZang.cs @@ -21,59 +21,77 @@ public class DiZang : Enemy [Header("攻击之间的间隔时间")][FoldoutGroup("地藏")] public float timeBetweenAttacks; /// - /// 塞钱箱 + /// 到底在上面还是下面生成爱欲品的玩家位置Y轴的界限 /// + [Header("到底在上面还是下面生成爱欲品的玩家位置Y轴的界限")][FoldoutGroup("地藏")] + public float aiYuPinBuildLimit; + [Header("爱欲品怪物预制体")][FoldoutGroup("地藏")] + public GameObject aiYuPin; + /// + /// 场景上方的落怪点组,用来召唤爱欲品 + /// + [Header("场景上方的落怪点组")][ListDrawerSettings][FoldoutGroup("地藏")] + public List throwingPointGroupUp; + /// + /// 场景下方的落怪点组,用来召唤爱欲品 + /// + [Header("场景下方的落怪点组")][ListDrawerSettings][FoldoutGroup("地藏")] + public List throwingPointGroupDown; + /// + /// 使用召唤爱欲品后有多少时间的后摇 + /// + [Header("使用召唤爱欲品后有多少时间的后摇")][FoldoutGroup("地藏")] + public float CallAiYuPinEndTime; + + + // _____ _ _ + // | __ \ (_) | | + // | |__) | __ ___ ____ _| |_ ___ + // | ___/ '__| \ \ / / _` | __/ _ \ + // | | | | | |\ V / (_| | || __/ + // |_| |_| |_| \_/ \__,_|\__\___| + private MoneyBox moneyBox; private delegate IEnumerator Action(); private enum PlayerState{上半,下半}; private MyPlayer player; /// - /// 到底在上面还是下面生成爱欲品的玩家位置Y轴的界限 - /// - [Header("到底在上面还是下面生成爱欲品的玩家位置Y轴的界限")] - public float aiYuPinBuildLimit; - /// - /// 爱欲品小怪的预制体,召唤功能会用到 - /// - [Header("爱欲品怪物预制体")][FoldoutGroup("地藏")] - public GameObject aiYuPin; - /// - /// 场景上方的落怪点,用来召唤爱欲品 - /// - [Header("场景上方的落怪点组")][ListDrawerSettings][FoldoutGroup("地藏")] - public List throwingPointGroupUp; - /// - /// 场景下方的落怪点,用来召唤爱欲品 - /// - [Header("场景下方的落怪点组")][ListDrawerSettings][FoldoutGroup("地藏")] - public List throwingPointGroupDown; - /// /// 本次使用的落怪点位置组 /// + [Header("本次使用的落怪点位置组")][ListDrawerSettings][FoldoutGroup("地藏")] + [SerializeField][ListDrawerSettings][ReadOnly] private List throwingPointGroupUse; - /// - /// 使用召唤爱欲品后有多少时间的后摇 - /// - public float CallAiYuPinEndTime; - private delegate void NullAction(); + private Bell myBell; - - private void Init(){ - moneyBox = FindObjectOfType(); - player = FindObjectOfType(); - } - - protected override void OnFindThePlayer(Transform target){ - if(state == State.wander){ - state = State.atk; - StartCoroutine("ATK"); - } - } + // _____ _ _ ____ _ + // / ____| | | | _ \ | | + // | | __ _| | | |_) | __ _ ___| | __ + // | | / _` | | | _ < / _` |/ __| |/ / + // | |___| (_| | | | |_) | (_| | (__| < + // \_____\__,_|_|_|____/ \__,_|\___|_|\_\ void Start(){ Init(); } + // _ _ _ + // | \ | | | | + // | \| | ___ _ __ _ __ ___ __ _| | + // | . ` |/ _ \| '__| '_ ` _ \ / _` | | + // | |\ | (_) | | | | | | | | (_| | | + // |_| \_|\___/|_| |_| |_| |_|\__,_|_| + private void Init(){ + //找到组件和物体 + moneyBox = FindObjectOfType(); + player = FindObjectOfType(); + myBell = transform.GetChild(0).GetComponent(); + //告诉钟自己是主人 + myBell.owner = this; + } + + /// + /// 执行一次攻击 + /// private new IEnumerator ATK(){ //等待攻击间隔 yield return new WaitForSeconds(timeBetweenAttacks); @@ -83,7 +101,7 @@ public class DiZang : Enemy else{ //否则,随机执行召唤或者敲钟 Action action = - ((Random.Range(-1f,0f) > 0) ? (Action)RingTheBell : (Action)CallAiYuPin); + ((Random.Range(-1f,1f) > 0) ? (Action)RingTheBell : (Action)CallAiYuPin); StartCoroutine(action()); } } @@ -92,7 +110,7 @@ public class DiZang : Enemy /// 召唤爱欲品的时候Call这个 /// private IEnumerator CallAiYuPin(){ - yield return new WaitForEndOfFrame(); + Debug.Log("正在使用:召唤"); //确定玩家在上半边还是下半边 PlayerState playerState = ((player.transform.position.y > aiYuPinBuildLimit) ? PlayerState.上半: PlayerState.下半); @@ -140,8 +158,9 @@ public class DiZang : Enemy /// 敲钟的时候Call这个 /// private IEnumerator RingTheBell(){ + Debug.Log("正在使用:敲钟"); yield return new WaitForEndOfFrame(); - Debug.Log("地藏正在敲钟"); + myBell.ATK(player); } /// @@ -149,8 +168,25 @@ public class DiZang : Enemy /// private IEnumerator TakeTheMoney(){ yield return new WaitForEndOfFrame(); - Debug.Log("地藏正在拿钱"); + Debug.Log("正在使用:拿钱"); + } - private void ATKEnd(){StartCoroutine(ATK());} + // ______ _ + // | ____| | | + // | |____ _____ _ __ | |_ + // | __\ \ / / _ \ '_ \| __| + // | |___\ V / __/ | | | |_ + // |______\_/ \___|_| |_|\__| + protected override void OnFindThePlayer(Transform target){ + if(state == State.wander){ + state = State.atk; + StartCoroutine(ATK()); + } + } + + /// + /// 攻击结束的时候触发,重新开始新一轮攻击 + /// + public void ATKEnd(){StartCoroutine(ATK());} } diff --git a/Assets/Scripts/MyPlayer.cs b/Assets/Scripts/MyPlayer.cs index 503dadf..20b30c8 100644 --- a/Assets/Scripts/MyPlayer.cs +++ b/Assets/Scripts/MyPlayer.cs @@ -43,6 +43,16 @@ public class MyPlayer : MonoBehaviour /// [DictionaryDrawerSettings()][Header("攻击方式的倍率列表")][ShowInInspector][FoldoutGroup("其他",false,0)] public static Dictionary atkMethodMagnification; + /// + /// 记录此时自己是否被爱欲品缠抱 + /// + [Header("被缠抱了吗?")][SerializeField][ReadOnly][FoldoutGroup("Info")] + public bool isCatching = false; + /// + /// 正抓着玩家的爱欲品 + /// + [HideInInspector] + public AiYuPin catingAiYuPin; // _____ _ _ // | __ \ (_) | | @@ -87,15 +97,7 @@ public class MyPlayer : MonoBehaviour /// 是否在攻击 /// private bool isAttacking; - /// - /// 记录此时自己是否被爱欲品缠抱 - /// - [Header("被缠抱了吗?")][SerializeField][ReadOnly][FoldoutGroup("Info")] - private bool isCatching = false; - /// - /// 正抓着玩家的爱欲品 - /// - private AiYuPin catingAiYuPin; + // _____ _ _ ____ _ @@ -260,7 +262,10 @@ public class MyPlayer : MonoBehaviour if(faceDir * inputDir < 0){ if(inControl && !isAttacking)TurnAround(); - if(isCatching){catingAiYuPin.OnBreakFree();} + if(isCatching && context.started){ + catingAiYuPin.OnBreakFree(); + Debug.Log("挣脱"); + } } }