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("挣脱");
+ }
}
}