Roman ca9a746b76 任务:搭建基本的系统
1.编写以撒逻辑
(1.继承于Enemy
(2.编写OnSave(男童)事件,当有男童被解救,会触发以撒的这个事件,后续逻辑等待讨论
(3.具有冲撞和闪电两种攻击方式,通过类似地藏的方式轮回随机决定攻击方式
(4.编写冲撞攻击逻辑
((*.创建鬼魂脚本
((*.创建鬼魂预制体,需要内含触发器
((1.当执行,以玩家为中心向周围一圈固定距离随机方向的某处召唤鬼魂,并记录下此时自身到玩家的方向
((2.等待一小段时间,令鬼魂以记录方向冲撞出去,利用Tweener动画营造一种先抖一下然后猛地创过来的感觉
((3.动画结束后,鬼魂逐渐消隐
((4.消隐结束后,删除游戏物体
((5.冲撞过程中具有攻击判定,若创到玩家,触发玩家的受击事件,同时获取主人的攻击力传给玩家
(3.编写闪电攻击逻辑
((1.当执行,在玩家头顶一定距离处生成鬼魂
((2.淡入显示鬼魂,一小段时间后,命令鬼魂发动落雷攻击
((3.发动时,激活场景内的巨型落雷,同时更改落雷的x位置到鬼魂的x,子物体具有触发器,(每帧)检测到玩家在内则对玩家造成伤害
((4.在极短的时间后关闭落雷同时开始淡出鬼魂
((5.淡出结束后删除游戏物体

2.编写男童逻辑
(1.继承于Interactive
(2.编写解救男童逻辑
((*.修改Interactive基类,新增OnCallCancel事件,当交互键抬起时触发一次
((*.新增男童状态的枚举类型,包含:wait、saving、OK三个状态
((*:新增一个变量记录男童状态
((1.重写OnCall事件,当OnCall,修改状态至saving
((2.Update回调中,若处于saving状态,则开始减少CDLeft,同时判断CDLeft是否耗尽,若耗尽,触发OnSave
((3.编写OnSave函数,修改状态至OK,通知owner自己已经OnSave
((4.重写OnCallCancel事件,当触发,判定状态,若处于saving状态,则修改状态至wait,恢复CDLeft
((*.使得玩家救人的时候无法移动,而当交互键抬起,重新获得移动能力
((*.修改可交互基类,当玩家交互过程中丢失catching,触发可交互物体的中断,同时告知玩家交互中断,触发中断事件
((5.解救结束后,通知玩家解救结束

至此,以撒的Boss逻辑还差首尾部分
加速吧
2021-12-17 01:27:10 +08:00

219 lines
7.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using Sirenix.OdinInspector;
/// <summary>
/// 撞钟类,控制地藏头上的钟
/// </summary>
public class Bell : MonoBehaviour
{
// _____ _ _ _
// | __ \ | | | (_)
// | |__) | _| |__ | |_ ___
// | ___/ | | | '_ \| | |/ __|
// | | | |_| | |_) | | | (__
// |_| \__,_|_.__/|_|_|\___|
/// <summary>
/// 攻击前置动作钟上浮多少距离
/// </summary>
[Header("攻击前置动作钟上浮多少距离")]
public float upDistance;
/// <summary>
/// 攻击将会持续多长时间
/// </summary>
[Header("攻击将会持续多长时间")]
public float atkTime;
/// <summary>
/// 主人也就是地藏Boss
/// </summary>
[HideInInspector]
public DiZang owner;
/// <summary>
/// 钟飞上去将要花费多少时间(降下来也是这个值)
/// </summary>
[Header("钟飞上去将要花费多少时间(降下来也是这个值)")]
public float upTime;
/// <summary>
/// 干扰多长时间能造成伤害和击飞?
/// </summary>
[Header("干扰多长时间能造成伤害和击飞?")]
public float annoyingToHitTime;
// _____ _ _
// | __ \ (_) | |
// | |__) | __ ___ ____ _| |_ ___
// | ___/ '__| \ \ / / _` | __/ _ \
// | | | | | |\ V / (_| | || __/
// |_| |_| |_| \_/ \__,_|\__\___|
/// <summary>
/// 当前正在攻击吗
/// </summary>
[SerializeField][Button][ReadOnly][Header("当前正在攻击吗(不包括钟上下过程))")]
private bool isAtking = false;
private MyPlayer player;
/// <summary>
/// 浮动动画,用来重启浮动动画解决Tween的一些局限性问题
/// </summary>
private Tweener floatTweener;
private float annoyingToHitTimeLeft;
/// <summary>
/// 此时是否在干扰玩家
/// </summary>
[SerializeField]
private bool isAnnoyingPlayer;
/// <summary>
/// 钟的初始位置
/// </summary>
private Vector3 startPositon;
// _____ _ _ ____ _
// / ____| | | | _ \ | |
// | | __ _| | | |_) | __ _ ___| | __
// | | / _` | | | _ < / _` |/ __| |/ /
// | |___| (_| | | | |_) | (_| | (__| <
// \_____\__,_|_|_|____/ \__,_|\___|_|\_\
void Start(){
annoyingToHitTimeLeft = annoyingToHitTime;
startPositon = transform.position;
//启动浮动动画
RestartFloat();
}
void Update(){
//如果钟正在攻击
if(isAtking){
if(!player.isAnnoying){
player.OnInAnnoying();
}
//创建一条从钟射向玩家的射线
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);
}
//如果射线击中玩家并且玩家未处于被攻击状态,说明刚被击中,触发玩家的被干扰事件
if(hit2D.collider.TryGetComponent<MyPlayer>(out MyPlayer trash) ){
// player.OnInAnnoying();
isAnnoyingPlayer = true;
}
//如果没有击中玩家,但是玩家处于被攻击状态,说明玩家脱离了攻击,触发玩家解除干扰事件
else if(!hit2D.collider.TryGetComponent<MyPlayer>(out MyPlayer trash1)){
//player.OnOutAnnoying();
isAnnoyingPlayer = false;
annoyingToHitTimeLeft = annoyingToHitTime;
}
}
if(isAnnoyingPlayer){
annoyingToHitTimeLeft -= Time.deltaTime;
if(annoyingToHitTimeLeft <= 0){
//告诉玩家,你被攻击了
player.OnBeHit(owner.ATK,
((transform.position.x -
player.transform.position.x)
> 0) ? 1 : -1);//通过自身位置和玩家位置的比较来返回玩家本次的受击方向
//恢复CD
annoyingToHitTimeLeft = annoyingToHitTime;
}
}
}
// _ _ _
// | \ | | | |
// | \| | ___ _ __ _ __ ___ __ _| |
// | . ` |/ _ \| '__| '_ ` _ \ / _` | |
// | |\ | (_) | | | | | | | | (_| | |
// |_| \_|\___/|_| |_| |_| |_|\__,_|_|
/// <summary>
/// 介于Tweener的特性经常需要重新创建钟浮动的动画
/// </summary>
private void RestartFloat(){
if(floatTweener != null){
floatTweener.Kill();
}
Tweener tweener = transform.DOShakePosition(5f,0.3f,1,90,false,false);
tweener.SetLoops(-1);
tweener.SetEase(Ease.InQuad);
floatTweener = tweener;
}
// ______ _
// | ____| | |
// | |____ _____ _ __ | |_
// | __\ \ / / _ \ '_ \| __|
// | |___\ V / __/ | | | |_
// |______\_/ \___|_| |_|\__|
/// <summary>
/// 从主人那里得到攻击指令后触发
/// </summary>
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);
}
/// <summary>
/// 上浮动画结束的时候触发
/// </summary>
/// <returns></returns>
private IEnumerator WaitAndTurnDownThebutton(){
//等待攻击时长结束
yield return new WaitForSeconds(atkTime);
//标记攻击结束
isAtking = false;
//触发自身攻击结束功能
ATKEnd();
}
/// <summary>
/// 攻击结束的时候触发
/// </summary>
private void ATKEnd(){
//如果玩家仍处于被干扰状态,解除干扰
if(player.isAnnoying) player.OnOutAnnoying();
annoyingToHitTimeLeft = annoyingToHitTime;
isAnnoyingPlayer = false;
//创建动画让钟回去
Tweener tweener =
//transform.DOMoveY(transform.position.y - upDistance,upTime);
transform.DOMove(startPositon,upTime);
//创建和添加结束事件
TweenCallback action = () => {
//重启浮动动画
RestartFloat();
//告诉主人,攻击结束,开始下一个轮回
owner.ATKEnd();
};
tweener.OnComplete(action);
}
}