using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using DG.Tweening;
using Sirenix.OdinInspector;
// _
// | |
// _ __ | | __ _ _ _ ___ _ __
// | '_ \| |/ _` | | | |/ _ \ '__|
// | |_) | | (_| | |_| | __/ |
// | .__/|_|\__,_|\__, |\___|_|
// | | __/ |
// |_| |___/
///
/// 玩家类,控制玩家相关的东西
///
public class MyPlayer : MonoBehaviour
{
// _____ _ _ _
// | __ \ | | | (_)
// | |__) | _| |__ | |_ ___
// | ___/ | | | '_ \| | |/ __|
// | | | |_| | |_) | | | (__
// |_| \__,_|_.__/|_|_|\___|
[Header("玩家平时地面移动的速度")][FoldoutGroup("Info")]
public float speed = 10f;
[Header("玩家跳跃力度的大小")][FoldoutGroup("Info")]
public float jumpForce = 10f;
[FoldoutGroup("CD")][Header("挥动锤子的CD时长")]
public float hammerCD = 1f;
[FoldoutGroup("CD")][Header("发射镰刀的CD时长")]
public float sickleCD = 10f;
[Header("镰刀游戏物体")][FoldoutGroup("预制体")]
public GameObject sicklePrefab;
public enum AtkMethod{镰刀,锤子,反弹炸弹};
///
/// 生命值上限
///
[FoldoutGroup("Info")][Header("生命值上限")]
public float HP;
///
/// 被击飞后的飞行方向的调整值
///
[Header("被攻击后击飞的力度调整值")][FoldoutGroup("其他",false,0)]
public Vector2 hitToflyParameter;
///
/// 攻击方式的倍率列表
///
[DictionaryDrawerSettings()][Header("攻击方式的倍率列表")][ShowInInspector][FoldoutGroup("其他",false,0)]
public static Dictionary atkMethodMagnification;
// _____ _ _
// | __ \ (_) | |
// | |__) | __ ___ ____ _| |_ ___
// | ___/ '__| \ \ / / _` | __/ _ \
// | | | | | |\ V / (_| | || __/
// |_| |_| |_| \_/ \__,_|\__\___|
private Rigidbody2D m_rigidbody;//自身刚体组件
[SerializeField][ReadOnly][FoldoutGroup("Info")]
private int inputDir;//当前输入方向,-1左,1右,0静止
[SerializeField][ReadOnly][FoldoutGroup("Info")]
private bool isLanding;//记录自己当前是否着地
private DOTweenAnimation wavingAnimation;//锤子挥动动画组件
private SpriteRenderer hammerSprite;//锤子的图片组件
private BoxCollider2D hammerCollider;//锤子的碰撞体
[FoldoutGroup("CD")][Header("挥动锤子的CD还剩多长时间")][SerializeField][ReadOnly]
private float hammerCDLeft = 0f;
[FoldoutGroup("CD")][Header("发射镰刀的CD还剩多长时间")][SerializeField][ReadOnly]
private float sickleCDLeft = 0f;
private int faceDir = 1;//面部朝向
private Transform sickleFirePoint;//镰刀发射点的transform
private Transform sickleClearerL;//左边的镰刀清除触发器
private Transform sickleClearerR;//右边的镰刀清除触发器
[FoldoutGroup("其他",false,1)][Header("玩家现在是否处于控制状态下(物理)")][SerializeField][ReadOnly]
private bool inControl = true;
[SerializeField][ReadOnly][ProgressBar(0,10,0.15f,0.47f,0.74f)][FoldoutGroup("Info")]
private float HPLeft;
///
/// 自身动画控制器组件
///
private Animator m_Animator;
///
/// 是否在跳跃状态
///
private bool isJumping;
///
/// 是否在下落
///
private bool isFalling;
///
/// 是否在攻击
///
private bool isAttacking;
///
/// 记录此时自己是否被爱欲品缠抱
///
[Header("被缠抱了吗?")][SerializeField][ReadOnly][FoldoutGroup("Info")]
private bool isCatching = false;
///
/// 正抓着玩家的爱欲品
///
private AiYuPin catingAiYuPin;
// _____ _ _ ____ _
// / ____| | | | _ \ | |
// | | __ _| | | |_) | __ _ ___| | __
// | | / _` | | | _ < / _` |/ __| |/ /
// | |___| (_| | | | |_) | (_| | (__| <
// \_____\__,_|_|_|____/ \__,_|\___|_|\_\
void Start()
{
Init();//初始化一些参数
}
void Update()
{
CountCD();
ChangeAnimator();
}
void FixedUpdate()
{
Move();//处理水平移动
}
// _ _ _
// | \ | | | |
// | \| | ___ _ __ _ __ ___ __ _| |
// | . ` |/ _ \| '__| '_ ` _ \ / _` | |
// | |\ | (_) | | | | | | | | (_| | |
// |_| \_|\___/|_| |_| |_| |_|\__,_|_|
//初始化函数
private void Init()
{
//找到自己身上的组件和需要的游戏物体
m_rigidbody = GetComponent();
wavingAnimation = transform.Find("锤子的旋转中心").GetComponent();
hammerSprite = transform.Find("锤子的旋转中心").Find("锤子").GetComponent();
hammerCollider = transform.Find("锤子的旋转中心").Find("锤子").GetComponent();
sickleFirePoint = transform.Find("镰刀发射点");
sickleClearerL = transform.Find("镰刀飞出消除触发器左");
sickleClearerL.gameObject.AddComponent();
sickleClearerR = transform.Find("镰刀飞出消除触发器右");
sickleClearerR.gameObject.AddComponent();
m_Animator = GetComponent();
//初始化生命值
HPLeft = HP;
//初始化攻击倍率字典
atkMethodMagnification = new Dictionary();
atkMethodMagnification.Add(AtkMethod.镰刀,1);
atkMethodMagnification.Add(AtkMethod.锤子,1);
atkMethodMagnification.Add(AtkMethod.反弹炸弹,2);
}
//移动函数,处理水平方向移动
private void Move()
{
if(inControl && !isAttacking){
//直接修改刚体速度
m_rigidbody.velocity = new Vector2(inputDir * speed,//水平方向以输入方向乘以预设速度大小
m_rigidbody.velocity.y);//垂直方向不变
}
}
//计算CD的函数,每帧调用
private void CountCD()
{
if(hammerCDLeft > 0) hammerCDLeft -= Time.deltaTime;
if(sickleCDLeft > 0) sickleCDLeft -= Time.deltaTime;
}
private void TurnAround()
{
faceDir = inputDir;
transform.localScale = new Vector3( //x乘-1以显示转身
transform.localScale.x * -1,
//y、z不变
transform.localScale.y, transform.localScale.z);
}
///
/// 被击飞的时候Call这个
///
/// 被击方向
public void BeHitToFly(int dir)
{
m_rigidbody.velocity = Vector2.zero;
m_rigidbody.velocity += new Vector2(
-1 * dir * hitToflyParameter.x,
hitToflyParameter.y
);
}
///
/// 每Update调用,处理状态机全部放这里
///
protected void ChangeAnimator()
{
//移动动画
if (inputDir == 0) m_Animator.SetBool("isWalking", false);
else m_Animator.SetBool("isWalking", true);
//跳跃动画
m_Animator.SetBool("isJumping",isJumping);
//下落动画
if(m_rigidbody.velocity.y < 0 && !isLanding){
m_Animator.SetBool("isFalling",true);
isJumping = false;
}
if(isLanding) {isFalling = false;m_Animator.SetBool("isFalling",isFalling);}
//锤子攻击动画
m_Animator.SetBool("isAttacking",isAttacking);
//记录着地
m_Animator.SetBool("isLanding",isLanding);
//被击飞动画触发
m_Animator.SetBool("isBeHitting",!inControl);
}
///
/// 被爱欲品抓住时用协程触发
///
private void CatchingHarm(){
HPLeft -= FindObjectOfType().ATK;
}
//碰撞检测代码
// _____ _ _ _ _
// / ____| | | (_) (_)
// | | ___ | | |_ ___ _ ___ _ __
// | | / _ \| | | / __| |/ _ \| '_ \
// | |___| (_) | | | \__ \ | (_) | | | |
// \_____\___/|_|_|_|___/_|\___/|_| |_|
private void OnCollisionEnter2D(Collision2D collision)//当有物体碰上
{
if(collision.transform.tag == "地面")
{isLanding = true;//若碰撞物体标签为地面,标记自身着地
if(!isCatching)inControl = true;}
}
private void OnCollisionExit2D(Collision2D collision)//当有碰撞体离开
{
if(collision.transform.tag == "地面")
{isLanding = false;}//若碰撞物体标签为地面,标记自身未着地
}
// 以下为操作监听事件
// _____ _ _____ _
// |_ _| | | / ____| | |
// | | _ __ _ __ _ _| |_| (___ _ _ ___| |_ ___ _ __ ___
// | | | '_ \| '_ \| | | | __|\___ \| | | / __| __/ _ \ '_ ` _ \
// _| |_| | | | |_) | |_| | |_ ____) | |_| \__ \ || __/ | | | | |
// |_____|_| |_| .__/ \__,_|\__|_____/ \__, |___/\__\___|_| |_| |_|
// | | __/ |
// |_| |___/
public void OnMove(InputAction.CallbackContext context)//OnMove事件
{
//决定输入方向inputDir
if(!context.ReadValue().Equals(0))
inputDir = (context.ReadValue() > 0) ? 1 : -1;
else inputDir = 0;
if(faceDir * inputDir < 0){
if(inControl)TurnAround();
if(isCatching){catingAiYuPin.OnBreakFree();}
}
}
public void OnJump(InputAction.CallbackContext context)//OnJump事件
{
//当按下跳跃键
if(context.performed)
{
if(isLanding && inControl){//如果当前着地
//给予自身刚体
m_rigidbody.velocity = new Vector2(m_rigidbody.velocity.x,//水平方向速度不变
jumpForce);//垂直方向给予预设跳跃速度
//标记自身正在跳跃
isJumping = true;
}
}
}
public void OnWave(InputAction.CallbackContext context)
{
//当执行Wave动作
if (context.performed && hammerCDLeft <= 0)
{
hammerSprite.DOFade(1, 0f);//把锤子显示,Debug用,后期请删除
hammerCollider.enabled = true;//打开锤子碰撞体
wavingAnimation.DOPlay();//播放挥动锤子动画
hammerCDLeft = hammerCD;//挥动成功,重置CD剩余时间
if(!isAttacking)isAttacking = true;
}
}
public void OnSickle(InputAction.CallbackContext context)
{
if(context.started && sickleCDLeft <= 0 && inControl)
{
Sickle sickle = Instantiate(
sicklePrefab,
sickleFirePoint.position,
Quaternion.identity).
GetComponent();
sickle.dir = faceDir;
sickleCDLeft = sickleCD;
}
}
// ______ _
// | ____| | |
// | |____ _____ _ __ | |_
// | __\ \ / / _ \ '_ \| __|
// | |___\ V / __/ | | | |_
// |______\_/ \___|_| |_|\__|
//当挥动锤子动画结束后触发
public void OnWaveEnd()
{
//为挥动动画倒带
wavingAnimation.DORewind();
//把锤子隐藏,Debug用,后期请删除
hammerSprite.DOFade(0,0f);
//关闭锤子的碰撞体
hammerCollider.enabled = false;
}
///
/// 当玩家被打则Call这个函数
///
/// 遭受的攻击力
/// 攻击来源的方向,-1左,1右
public void OnBeHit(float atk, int dir)
{
//触发一个击飞
BeHitToFly(dir);
//标记自身不受控制
inControl = false;
//掉血
HPLeft -= atk;
}
///
/// 锤子攻击动画结尾Event调用
///
public void StopAttacking(){isAttacking = false;}
///
/// 当玩家被爱欲品抓住后触发这个事件
///
/// 这个爱欲品的爱欲品组件
public void BeCatchedByAiYuPin(AiYuPin aiYuPin){
//标记自身正被抓着
isCatching = true;
//标记自身失去控制
inControl = false;
//每秒掉血,伤害量为爱欲品的攻击力
InvokeRepeating("CatchingHarm",0f,1f);
//去除刚体速度,防止滑行带来的位置偏移问题
m_rigidbody.velocity = Vector2.zero;
//记录正在抓着自己的爱欲品
catingAiYuPin = aiYuPin;
}
///
/// 完全挣脱的时候从爱欲品Call过来
///
public void BreakFreeCompletely(){
//取消被抓住的标记
isCatching = false;
//恢复移动操控
inControl = true;
//取消掉血协程
CancelInvoke("CatchingHarm");
//去掉记录着的抓住玩家的爱欲品
catingAiYuPin = null;
//消除正在攻击状态以解决Bug
isAttacking = false;
}
// _______ _ _____ _
// |__ __| | |/ ____| |
// | | ___ ___ | | | | | __ _ ___ ___
// | |/ _ \ / _ \| | | | |/ _` / __/ __|
// | | (_) | (_) | | |____| | (_| \__ \__ \
// |_|\___/ \___/|_|\_____|_|\__,_|___/___/
private class SickleClearer : MonoBehaviour
{
//一个工具小插件,单独写脚本实在太浪费,所以在这里写一下。
//当触发器检测到有东西进入,会试图获取它身上的镰刀脚本,如果有就说明镰刀到屏幕边缘了,把这个镰刀删除
//没有的话说明是其他物体,不作处理
void OnTriggerEnter2D(Collider2D other)
{
if(other.TryGetComponent(out Sickle temp))
Destroy(temp.gameObject);
}
}
}