using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using DG.Tweening; using Sirenix.OdinInspector; /// /// 玩家类,控制玩家相关的东西 /// public class MyPlayer : MonoBehaviour, Bommer.I_CanBeBoomedObj { // _____ _ _ _ // | __ \ | | | (_) // | |__) | _| |__ | |_ ___ // | ___/ | | | '_ \| | |/ __| // | | | |_| | |_) | | | (__ // |_| \__,_|_.__/|_|_|\___| [Header("玩家平时地面移动的速度")][FoldoutGroup("属性")] public float speed = 10f; [Header("玩家跳跃力度的大小")][FoldoutGroup("属性")] 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("属性")][Header("生命值上限")] public float HP; /// /// 被击飞后的飞行方向的调整值 /// [Header("被攻击后击飞的力度调整值")][FoldoutGroup("其他",false,0)] public Vector2 hitToflyParameter; /// /// 攻击方式的倍率列表 /// [DictionaryDrawerSettings()][Header("攻击方式的倍率列表")][ShowInInspector][FoldoutGroup("其他",false,0)] public static Dictionary atkMethodMagnification; /// /// 记录此时自己是否被爱欲品缠抱 /// [Header("被缠抱了吗?")][SerializeField][ReadOnly][FoldoutGroup("状态")] public bool isCatching = false; /// /// 正抓着玩家的爱欲品 /// [HideInInspector] public AiYuPin catingAiYuPin; /// /// 玩家此时捕捉着的可交互物体 /// [Header("玩家此时捕捉着的可交互物体")][FoldoutGroup("状态")][ReadOnly] public Interactive catching; /// /// 当前身上有多少特殊硬币,用来塞钱的那种 /// [FoldoutGroup("状态")][Header("当前身上有多少特殊硬币,用来塞钱的那种")] public int specialMoneyCount = 0; // _____ _ _ // | __ \ (_) | | // | |__) | __ ___ ____ _| |_ ___ // | ___/ '__| \ \ / / _` | __/ _ \ // | | | | | |\ V / (_| | || __/ // |_| |_| |_| \_/ \__,_|\__\___| private Rigidbody2D m_rigidbody;//自身刚体组件 [SerializeField][ReadOnly][FoldoutGroup("状态")] private int inputDir;//当前输入方向,-1左,1右,0静止 [SerializeField][ReadOnly][FoldoutGroup("状态")] 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("状态")] private float HPLeft; /// /// 自身动画控制器组件 /// private Animator m_Animator; /// /// 是否在跳跃状态 /// private bool isJumping; /// /// 是否在下落 /// private bool isFalling; /// /// 是否在攻击 /// private bool isAttacking; /// /// 是否在丢镰刀 /// private bool isThrowing; private VibrationManager vibrationManager; // _____ _ _ ____ _ // / ____| | | | _ \ | | // | | __ _| | | |_) | __ _ ___| | __ // | | / _` | | | _ < / _` |/ __| |/ / // | |___| (_| | | | |_) | (_| | (__| < // \_____\__,_|_|_|____/ \__,_|\___|_|\_\ 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(); vibrationManager = FindObjectOfType(); //初始化生命值 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); //丢出镰刀动画 m_Animator.SetBool("isThrowing",isThrowing); } /// /// 被爱欲品抓住时用协程触发 /// private void CatchingHarm(){ HPLeft -= FindObjectOfType().ATK; } /// /// 塞钱 /// private void GiveMoney(){ specialMoneyCount--; } /// /// 捡到钱了 /// private void IPickedACoin(){ specialMoneyCount++; } // _____ _ _ _ _ // / ____| | | (_) (_) // | | ___ | | |_ ___ _ ___ _ __ // | | / _ \| | | / __| |/ _ \| '_ \ // | |___| (_) | | | \__ \ | (_) | | | | // \_____\___/|_|_|_|___/_|\___/|_| |_| private void OnCollisionEnter2D(Collision2D collision)//当有物体碰上 { if(collision.transform.tag == "地面") {isLanding = true;//若碰撞物体标签为地面,标记自身着地 if(!isCatching)inControl = true;} } private void OnCollisionExit2D(Collision2D collision)//当有碰撞体离开 { if(collision.transform.tag == "地面" && (isJumping || !inControl)) {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 && !isAttacking)TurnAround(); if(isCatching && context.started){ catingAiYuPin.OnBreakFree(); Debug.Log("挣脱"); } } } 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; vibrationManager.ShakeScream(Vector2.up,0.5f); StartCoroutine(vibrationManager.ShakePad(0.1f,0.2f,0.2f,VibrationManager.PadShakeitem.跳跃)); } } } 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; //空挥轻微震动手柄 StartCoroutine( vibrationManager.ShakePad(0.1f,0.1f,0.2f,VibrationManager.PadShakeitem.挥动锤子) ); } } //检测到 镰刀 按键的时候触发 public void OnSickle(InputAction.CallbackContext context) { //按下就触发 CD好了 玩家处于控制状态 if(context.started && sickleCDLeft <= 0 && inControl){ //实例化一个镰刀游戏物体 Sickle sickle = Instantiate( sicklePrefab, sickleFirePoint.position, Quaternion.identity ).GetComponent(); //初始化镰刀 sickle.dir = faceDir; //开始计算镰刀CD sickleCDLeft = sickleCD; //轻微震动手柄 StartCoroutine( vibrationManager.ShakePad( 0.1f,0.1f,0.2f,VibrationManager.PadShakeitem.发射镰刀 ) ); //轻微震动屏幕 vibrationManager.ShakeScream(Vector2.right,0.2f); //改变标记表示开始播放丢镰刀动画 isThrowing = true; } } public void OnInteractive(InputAction.CallbackContext context){ if(context.performed && catching != null){ switch(catching.itemName){ case Interactive.ItemName.塞钱箱 : if( specialMoneyCount > 0 && !FindObjectOfType().hasMoney ){ catching.OnCall(); GiveMoney(); } break; case Interactive.ItemName.硬币 : IPickedACoin(); catching.OnCall(); break; } } } // ______ _ // | ____| | | // | |____ _____ _ __ | |_ // | __\ \ / / _ \ '_ \| __| // | |___\ 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; //震动屏幕和手柄 StartCoroutine(vibrationManager.ShakePad(0.8f,0.5f,0.2f,VibrationManager.PadShakeitem.被击中)); vibrationManager.ShakeScream(new Vector2(dir,1),1f); } /// /// 锤子攻击动画结尾Event调用 /// public void StopAttacking(){isAttacking = false; //解决面部朝向的问题 if(faceDir * inputDir < 0){ if(inControl && !isAttacking)TurnAround(); if(isCatching){catingAiYuPin.OnBreakFree();} } } /// /// 当玩家被爱欲品抓住后触发这个事件 /// /// 这个爱欲品的爱欲品组件 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; } //脚着地的时候触发,通过状态机调用 public void OnFootTap(){ StartCoroutine(vibrationManager.ShakePad(0f,0.02f,0.05f,VibrationManager.PadShakeitem.移动)); } //镰刀攻击结尾调用,清除镰刀攻击状态防止多次触发动画 public void OnThrowingEnd(){isThrowing = false;} // _____ _ __ // |_ _| | | / _| // | | _ __ | |_ ___ _ __| |_ __ _ ___ ___ // | | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \ // _| |_| | | | || __/ | | || (_| | (_| __/ // |_____|_| |_|\__\___|_| |_| \__,_|\___\___| public void BeBoomed(float atk, int dir){ OnBeHit(atk,dir); } public Transform ObjTransform(){return transform;} // _______ _ _____ _ // |__ __| | |/ ____| | // | | ___ ___ | | | | | __ _ ___ ___ // | |/ _ \ / _ \| | | | |/ _` / __/ __| // | | (_) | (_) | | |____| | (_| \__ \__ \ // |_|\___/ \___/|_|\_____|_|\__,_|___/___/ private class SickleClearer : MonoBehaviour { //一个工具小插件,单独写脚本实在太浪费,所以在这里写一下。 //当触发器检测到有东西进入,会试图获取它身上的镰刀脚本,如果有就说明镰刀到屏幕边缘了,把这个镰刀删除 //没有的话说明是其他物体,不作处理 void OnTriggerEnter2D(Collider2D other) { if(other.TryGetComponent(out Sickle temp)) Destroy(temp.gameObject); } } }