commit 9559cc8882161192a43be22670a8ff69db1ea13a Author: Roman <1325980292@qq.com> Date: Sat Aug 27 19:22:38 2022 +0800 短学期Log 任务:替换和实装美术素材 1.在教程场景布置图标和文字提示内容 DONE 2.制作GamePlay中背景元素的动画并实装 DONE 3.替换拆迁障碍物美术素材 DONE 任务:实装音乐和音效 1.为两个场景添加音乐,并且在GamePlay场景不重开音乐。 DONE 2.实装人摔地音效 DONE 3.实装人跑动音效 效果不好 DONE 4.实装人马分离音效 DONE *.补充实装人降落到马上的音效 DONE 5.实装创烂障碍物音效 DONE 6.实装圣火点燃音效 DONE 7.实装马磕磕碰碰音效 DONE 8.实装马似音效 DONE 9.实装马着地音效 DONE 10.实装马起跳音效 DONE 11.实装马蹄点地音效 效果不好 DONE 任务:实装特效 1.实装后处理 DONE 2.实装日夜更替 DONE 3.实装树叶飘落 DONE 4.实装圣火粒子 效果不好 DONE 5.实装破碎灰尘 效果不好 DONE 6.实装马蹄灰尘 DONE 7.实装红黑闪特效 DONE 任务:完善没写的零散逻辑 1.在教程场景,若人马分离障碍处没接到人,过一个转场然后复位人和马 **:仍然存在问题,当如此,人的动画失效。这个问题现在不好修,等待人的死亡动画实装后再修 已修复 DONE 2.在教程场景,点燃圣火仅有进入触发器后加载转场然后转移场景的功能,没有点燃圣火的过程,现补充其逻辑 DONE 3.开发GamePlay距离记录和重开系统 DONE 4.策划要在点燃圣火时镜头放大,体现标题感 URP相机不太好做 ABANDON 5.人的死亡动画逻辑之前没做 DONE 任务:测试并修复Bug DONE 修复Bug 1.在教程场景,可破坏障碍物的碎片的层级不对,创烂瞬间会有层级突变的问题。在GamePlay层级,也出现了这个问题。 已修复 DONE 2.现在的高障碍实在太高了,基本有80%以上的概率导致马翻,应该调低障碍物、或者调大马的跳跃力度。 DONE 3.跑步动画和跑步音效完全对不上 加快跑步动画 DONE 4.原爆破给力范围太大,会导致旧的碎片也被波及 已修复 DONE commit cab00851df5e4da70b981c564888c53d86de1f95 Author: Roman <1325980292@qq.com> Date: Sat Aug 27 02:51:21 2022 +0800 短学期Log 任务:替换和实装美术素材 1.在教程场景布置图标和文字提示内容 DONE 2.制作GamePlay中背景元素的动画并实装 DONE 3.替换拆迁障碍物美术素材 DONE 任务:实装音乐和音效 1.为两个场景添加音乐,并且在GamePlay场景不重开音乐。 DONE 2.实装人摔地音效 DONE 3.实装人跑动音效 DONE 4.实装人马分离音效 DONE 5.实装创烂障碍物音效 DOING 6.实装圣火点燃音效 7.实装马磕磕碰碰音效 8.实装马似音效 9.实装马着地音效 10.实装马起跳音效 任务:实装特效 …… 任务:完善没写的零散逻辑 1.在教程场景,若人马分离障碍处没接到人,过一个转场然后复位人和马 **:仍然存在问题,当如此,人的动画失效。这个问题现在不好修,等待人的死亡动画实装后再修 WAIT 2.在教程场景,点燃圣火仅有进入触发器后加载转场然后转移场景的功能,没有点燃圣火的过程,现补充其逻辑 DONE 3.开发GamePlay距离记录和重开系统 …… 修复Bug 1.在教程场景,可破坏障碍物的碎片的层级不对,创烂瞬间会有层级突变的问题。在GamePlay层级,也出现了这个问题。 2.现在的高障碍实在太高了,基本有80%以上的概率导致马翻,应该调低障碍物、或者调大马的跳跃力度。 commit 3f0c9dd791c66e7222d6dbb72d8b762b73f06aed Merge: e6888a7 bc74426 Author: Roman <1325980292@qq.com> Date: Fri Aug 26 18:13:00 2022 +0800 Merge branch 'Saipo' of https://e.coding.net/gensokyogroup/saima/SAIMA into Roman # Conflicts: # UserSettings/EditorUserSettings.asset # UserSettings/Layouts/CurrentMaximizeLayout.dwlt # UserSettings/Layouts/default-2021.dwlt commit e6888a748dc7188bd3c2f7ce4bceade7402f8cec Author: Roman <1325980292@qq.com> Date: Fri Aug 26 18:11:05 2022 +0800 任务:编写教程和开始场景 分析:分为五个阶段,每个阶段一屏宽。前四个阶段是教程阶段,分别仅放一种障碍(第一个无障碍)和提示,提示参照茶杯头教程关。 每个阶段间有明显间断、镜头固定,但当马通过该阶段的障碍后,镜头右移一个阶段。马不能倒退,相机左侧有空气墙。 到达最终阶段后,按流程点燃圣火进入游戏 设计: 1.搭建核心场景,放置障碍物。 DONE 2.设计教程及开始场景管理器 (1.控制相机,使马每通过一个阶段,相机运动到记录的位置 DONE (2.给相机左侧添加空气墙 DONE (3.管理器要明确记录此时玩家处于哪个阶段 DONE (4.当玩家进入点燃圣火触发器,切断操控,等待动画结束或者一些信号,触发从右向左的渐变黑幕遮挡全屏,随后转场到新场景。 DONE 至此,基本逻辑完成,需要补充大量细节、替换大量美术素材。 修复问题: 1.人马分离障碍连续出现可能导致致命问题,修复使其不能连续出现 DONE 2.GamePlay中,远处的山需要补充运动逻辑 DONE commit 5d922db6142634cdd20aa7801c0b3c1c4994360c Author: Roman <1325980292@qq.com> Date: Wed Aug 24 17:59:05 2022 +0800 任务:制作人物动画逻辑 1.当人物处于Normal时,重复播放骑在马上的动画 2.当人物被射出,播放一次跳上动画,之后停在最后一帧,等待落到平台上。 3.当人物进入Walk态,开始重复播放跑步动画。 4.当人物开始降落,触发一次跳下动画,停在最后一帧 5.当Recover结束,状态恢复为Normal,重回到骑在马上动画 DONE commit d1fe07492af5ce6ea736ef738eb3e38170a08066 Merge: 436eaf0 5e10767 Author: Roman <1325980292@qq.com> Date: Wed Aug 24 10:42:58 2022 +0800 Merge branch 'Saipo' of https://e.coding.net/gensokyogroup/saima/SAIMA into Roman # Conflicts: # UserSettings/Layouts/default-2021.dwlt commit 436eaf01046248372e887eb8276f38e021915790 Author: Roman <1325980292@qq.com> Date: Wed Aug 24 10:40:51 2022 +0800 为了拉取的提交,少量修改
907 lines
31 KiB
C#
907 lines
31 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using Sirenix.OdinInspector;
|
||
|
||
/// <summary>
|
||
/// 马类,用于接受来自玩家的指令、进行物理模拟
|
||
/// </summary>
|
||
public class Horse : MonoBehaviour
|
||
{
|
||
// _____ _ _ _
|
||
// | __ \ | | | (_)
|
||
// | |__) | _| |__ | |_ ___
|
||
// | ___/ | | | '_ \| | |/ __|
|
||
// | | | |_| | |_) | | | (__
|
||
// |_| \__,_|_.__/|_|_|\___|
|
||
|
||
[FoldoutGroup("SE")][Title("deadSE")]
|
||
public AudioClip deadSE;
|
||
|
||
[FoldoutGroup("SE")][Title("landSE")]
|
||
public AudioClip landSE;
|
||
|
||
[FoldoutGroup("SE")][Title("jumpSE")]
|
||
public AudioClip jumpSE;
|
||
|
||
private AudioSource audioSource;
|
||
|
||
|
||
/// <summary>
|
||
/// 马的前腿根部
|
||
/// </summary>
|
||
[BoxGroup("必须绑定的物体")][Header("马的前腿根部")]
|
||
public Transform frontLegRoot;
|
||
|
||
/// <summary>
|
||
/// 马的后腿根部
|
||
/// </summary>
|
||
[BoxGroup("必须绑定的物体")][Header("马的后腿根部")]
|
||
public Transform backLegRoot;
|
||
|
||
/// <summary>
|
||
/// 马伸直腿后前脚底部
|
||
/// </summary>
|
||
[BoxGroup("必须绑定的物体")][Header("马前脚伸直后的最深位置")]
|
||
public Transform frontFoot;
|
||
|
||
/// <summary>
|
||
/// 马伸直腿后后脚底部
|
||
/// </summary>
|
||
[BoxGroup("必须绑定的物体")][Header("马后脚伸直后的最深位置")]
|
||
public Transform backFoot;
|
||
|
||
/// <summary>
|
||
/// 马脚Transform
|
||
/// </summary>
|
||
[BoxGroup("必须绑定的物体")][Header("马脚Transform,必须按照左前、右前、左后、右后的顺序绑定")]
|
||
public Transform[] footsTransform;
|
||
|
||
/// <summary>
|
||
/// 头部IK控制点
|
||
/// </summary>
|
||
[BoxGroup("必须绑定的物体")][Header("头部IK控制点")]
|
||
public Transform HeadControlPoint;
|
||
|
||
/// <summary>
|
||
/// 腿做圆周运动的半径
|
||
/// </summary>
|
||
[BoxGroup("马的基本运动信息")][Header("马脚圆周运动半径")]
|
||
public float footMoveRadius;
|
||
|
||
/// <summary>
|
||
/// 四条腿分别对输入偏差多少
|
||
/// </summary>
|
||
[ListDrawerSettings] [BoxGroup("马的基本运动信息")][Header("四条腿分别对输入偏差多少")]
|
||
public Vector2[] footOffestOfInput;
|
||
|
||
/// <summary>
|
||
/// 马足力量
|
||
/// </summary>
|
||
[BoxGroup("马的基本运动信息")][Header("马足力量")]
|
||
public float footForce;
|
||
|
||
/// <summary>
|
||
/// 马蹄推动马身的力度调整值
|
||
/// </summary>
|
||
[BoxGroup("马的基本运动信息")][Header("马前进的力度")]
|
||
public float strength;
|
||
|
||
/// <summary>
|
||
/// 马蹄供力有效范围
|
||
/// </summary>
|
||
[BoxGroup("马的基本运动信息")][Header("马蹄供力有效范围")]
|
||
public float effectiveDistance;
|
||
|
||
public enum FootType { Front, Back }
|
||
|
||
/// <summary>
|
||
/// 马状态,Stand代表无输入,Move为有输入着地行走,Jump为跳跃,当两对足均并拢时进入
|
||
/// </summary>
|
||
public enum HorseState { Stand, Move, Jump, Dead}
|
||
|
||
/// <summary>
|
||
/// 单次跳跃过程中的状态量,Ready表示还没开始累计最终力,Charge表示已经开始蓄力,jump表示已经触发跳跃
|
||
/// </summary>
|
||
public enum JumpState { Ready, Charging, Jump }
|
||
|
||
/// <summary>
|
||
/// 跳跃判定阈值,只有输入的变化大于该值才会触发跳跃的蓄力
|
||
/// </summary>
|
||
[BoxGroup("马的基本运动信息")][Header("马跳跃蓄力阈值")]
|
||
public float jumpChargeThreshold;
|
||
|
||
/// <summary>
|
||
/// 马跳跃力度
|
||
/// </summary>
|
||
[BoxGroup("马的基本运动信息")][Header("马跳跃力度")]
|
||
public float jumpForce;
|
||
|
||
[BoxGroup("马的其他信息")][Header("马被相机挤死后飞出有多大的力")]
|
||
public float deadFlySpeed;
|
||
|
||
/// <summary>
|
||
/// 要统计多长时间内的输入变化以供加速?】
|
||
/// </summary>
|
||
[BoxGroup("马的基本运动信息")][Header("要统计多长时间内的输入变化以供加速?")]
|
||
public float accelerationTime;
|
||
|
||
/// <summary>
|
||
/// 加速倍率
|
||
/// </summary>
|
||
[BoxGroup("马的基本运动信息")][Header("加速倍率")]
|
||
public float accelerationRate = 1f;
|
||
|
||
/// <summary>
|
||
/// 最后一节马足的骨骼,必须按照左前、右前、左后、右后的顺序绑定
|
||
/// </summary>
|
||
[ BoxGroup("必须绑定的物体")][Header("最后一节马足的骨骼,必须按照左前、右前、左后、右后的顺序绑定")]
|
||
public Transform[] lastFoots;
|
||
|
||
[BoxGroup("马的基本运动信息")][Header("最后一节马前脚的旋转区间")]
|
||
public Vector2 lastFrontFootRotationRange;
|
||
[BoxGroup("马的基本运动信息")][Header("最后一节马后脚的旋转区间")]
|
||
public Vector2 lastBackFootRotationRange;
|
||
[BoxGroup("马的基本运动信息")][Header("马头追踪速度")]
|
||
public float headSpeed;
|
||
[BoxGroup("马的基本运动信息")][Header("马尾追踪速度")]
|
||
public float tailSpeed;
|
||
[BoxGroup("马的基本运动信息")][Header("马尾旋转范围")]
|
||
public Vector2 horseTailRotationRange;
|
||
/// <summary>
|
||
/// 马尾骨骼
|
||
/// </summary>
|
||
[BoxGroup("必须绑定的物体")][Header("马尾IK控制点")]
|
||
public Transform tailControlPoint;
|
||
|
||
|
||
|
||
|
||
|
||
// _____ _ _
|
||
// | __ \ (_) | |
|
||
// | |__) | __ ___ ____ _| |_ ___
|
||
// | ___/ '__| \ \ / / _` | __/ _ \
|
||
// | | | | | |\ V / (_| | || __/
|
||
// |_| |_| |_| \_/ \__,_|\__\___|
|
||
|
||
struct foot
|
||
{
|
||
/// <summary>
|
||
/// 腿对输入偏差多少
|
||
/// </summary>
|
||
public Vector2 footOffestOfInput;
|
||
|
||
/// <summary>
|
||
/// 马脚控制点,通过transform找到
|
||
/// </summary>
|
||
public Transform footControlPoint;
|
||
|
||
/// <summary>
|
||
/// 真实的马脚的Transform
|
||
/// </summary>
|
||
public Transform footRealTransform;
|
||
|
||
/// <summary>
|
||
/// 马脚此时目标位置,每帧计算
|
||
/// </summary>
|
||
public Vector3 footTargetPosition;
|
||
|
||
/// <summary>
|
||
/// 马蹄刚体组件
|
||
/// </summary>
|
||
public Rigidbody2D footRigidbody2D;
|
||
|
||
/// <summary>
|
||
/// 马蹄的碰撞体,但是不绑在马蹄上,而是为了物理计算绑在马身上
|
||
/// </summary>
|
||
public BoxCollider2D footBoxCollider2D;
|
||
|
||
/// <summary>
|
||
/// 马蹄前一帧的位置
|
||
/// </summary>
|
||
public Vector3 footPreviousPosition;
|
||
|
||
/// <summary>
|
||
/// 最后一节马足的骨骼Transform,需要模拟其弯曲
|
||
/// </summary>
|
||
public Transform lastFootTransform;
|
||
}
|
||
|
||
private foot[] foots;
|
||
|
||
/// <summary>
|
||
/// 马前腿长度
|
||
/// </summary>
|
||
private float frontLegLength;
|
||
|
||
/// <summary>
|
||
/// 马后腿长度
|
||
/// </summary>
|
||
private float backLegLength;
|
||
|
||
/// <summary>
|
||
/// 从前腿根骨骼到马脚运动圆心的距离,用来推算最终马脚位置
|
||
/// </summary>
|
||
private float frontRootDistanceToCenterOfCircle;
|
||
|
||
/// <summary>
|
||
/// 从后腿根骨骼到马脚运动圆心的距离,用来推算最终马脚位置
|
||
/// </summary>
|
||
private float backRootDistanceToCenterOfCircle;
|
||
|
||
/// <summary>
|
||
/// 输入的马前脚信息
|
||
/// </summary>
|
||
private Vector2 inputFrontVector;
|
||
|
||
/// <summary>
|
||
/// 上一帧马前脚信息
|
||
/// </summary>
|
||
private Vector2 pInputFrontVector;
|
||
|
||
/// <summary>
|
||
/// 输入的马后脚信息
|
||
/// </summary>
|
||
private Vector2 inputBackVector;
|
||
|
||
/// <summary>
|
||
/// 上一帧马后脚信息
|
||
/// </summary>
|
||
private Vector2 pInputBackVector;
|
||
|
||
/// <summary>
|
||
/// 前一帧的前马脚输入向量
|
||
/// </summary>
|
||
private Vector2 previousInputFrontVector;
|
||
|
||
/// <summary>
|
||
/// 前一帧的后马脚输入向量
|
||
/// </summary>
|
||
private Vector2 previousInputBackVector;
|
||
|
||
// /// <summary>
|
||
// /// 一段时间内的变化总量
|
||
// /// </summary>
|
||
// private float chargeCount = 0;
|
||
|
||
|
||
/// <summary>
|
||
/// 原重力尺度,在Start中通过随意一条腿的刚体获取
|
||
/// </summary>
|
||
private float oriGravityScale;
|
||
|
||
/// <summary>
|
||
/// 马蹄碰撞体数组
|
||
/// </summary>
|
||
private BoxCollider2D[] footBoxColliders;
|
||
|
||
/// <summary>
|
||
/// 马的刚体组件
|
||
/// </summary>
|
||
private Rigidbody2D horseRig;
|
||
|
||
/// <summary>
|
||
/// 四条腿分别对输入偏差多少,但是是原始值,不会改变,用于还原并拢的脚
|
||
/// </summary>
|
||
private Vector2[] oriFootOffestOfInput;
|
||
|
||
/// <summary>
|
||
/// 马此时的状态
|
||
/// </summary>
|
||
private HorseState horseState;
|
||
|
||
/// <summary>
|
||
/// 此时前腿并拢着吗?
|
||
/// </summary>
|
||
private bool isFrontFootMerged = false;
|
||
|
||
/// <summary>
|
||
/// 此时后腿并拢着吗?
|
||
/// </summary>
|
||
private bool isBackFootMerged = false;
|
||
|
||
/// <summary>
|
||
/// 此时的跳跃状态
|
||
/// </summary>
|
||
private JumpState jumpState = JumpState.Ready;
|
||
|
||
/// <summary>
|
||
/// 跳跃蓄力的速度
|
||
/// </summary>
|
||
private Vector2 jumpChargeVelocity;
|
||
|
||
/// <summary>
|
||
/// 死亡后的旋转中心
|
||
/// </summary>
|
||
private Transform rotateCenter;
|
||
|
||
/// <summary>
|
||
/// 保存了最近若干秒内的输入充能
|
||
/// </summary>
|
||
private Queue <float> footInputChargeQueue;
|
||
/// <summary>
|
||
/// 应有的输入加速累计队列的长度
|
||
/// </summary>
|
||
private int footInputChargeQueueLength;
|
||
|
||
/// <summary>
|
||
/// 本帧中,累计的充能值
|
||
/// </summary>
|
||
public float footInputCharge = 0;
|
||
|
||
/// <summary>
|
||
/// 马头控制点的Pos应同步于此
|
||
/// </summary>
|
||
private Transform horseHeadDelay;
|
||
|
||
/// <summary>
|
||
/// 马头的默认位置
|
||
/// </summary>
|
||
private Transform horseHeadDefault;
|
||
|
||
/// <summary>
|
||
/// 马尾的控制点的Pos应同步于此
|
||
/// </summary>
|
||
private Transform horseTailDelay;
|
||
|
||
/// <summary>
|
||
/// 马尾的默认位置
|
||
/// </summary>
|
||
private Transform horseTailDefault;
|
||
|
||
private JumpState previousJumpState = JumpState.Ready;
|
||
|
||
|
||
|
||
void Start()
|
||
{
|
||
//初始化
|
||
Init();
|
||
//找到必要的物体和组件
|
||
FindSth();
|
||
//计算必要的量
|
||
CaculateSth();
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
//更新一些数据
|
||
UpdateDataEarly();
|
||
if(horseState != HorseState.Dead)
|
||
{
|
||
//计算马脚目标位置
|
||
CaculateTargetPosition();
|
||
//让马脚朝着目标移动
|
||
MoveFoot();
|
||
//让马整体运动
|
||
MoveHorse();
|
||
//计算此时马脚在Y轴上的进程,并根据此进程对马蹄旋转插值,模拟最后一节马蹄的弯曲
|
||
CaculateLastFootRotation();
|
||
//跳跃检测和物理实现
|
||
if(horseState == HorseState.Jump) CheckJump();
|
||
//让马头控制点运动
|
||
MoveHorseHead();
|
||
//让马尾根据马刚体速度运动
|
||
MoveHorseTail();
|
||
// //防止马翻
|
||
// Debug.Log(transform.eulerAngles.z);
|
||
// if(transform.eulerAngles.z > 30 && transform.eulerAngles.z < 330)
|
||
// {
|
||
// //看是离45度还是315度更近
|
||
// if(Mathf.Abs(transform.eulerAngles.z - 30) < Mathf.Abs(transform.eulerAngles.z - 330))
|
||
// {
|
||
// transform.eulerAngles = new Vector3(0, 0, 30);
|
||
// }
|
||
// else
|
||
// {
|
||
// transform.eulerAngles = new Vector3(0, 0, 330);
|
||
// }
|
||
// }
|
||
|
||
}
|
||
//更新一些数据
|
||
UpdateDataLate();
|
||
}
|
||
|
||
void FixedUpdate() {
|
||
CaculateFootInputCharge();
|
||
}
|
||
|
||
|
||
void MoveHorseTail(){
|
||
Vector2 dir = horseTailDefault.position - horseTailDelay.position;
|
||
Vector2 horseV = horseRig.velocity;
|
||
dir = new Vector2(
|
||
dir.x * 0.05f,
|
||
dir.y * 0.05f
|
||
);
|
||
horseTailDelay.position += new Vector3(
|
||
dir.x * Time.deltaTime * tailSpeed,
|
||
dir.y * Time.deltaTime * tailSpeed,
|
||
0
|
||
);
|
||
tailControlPoint.position = horseTailDelay.position;
|
||
}
|
||
|
||
|
||
|
||
|
||
void MoveHorseHead(){
|
||
Vector2 dir = horseHeadDefault.position - horseHeadDelay.position;
|
||
Vector2 horseV = horseRig.velocity;
|
||
dir = new Vector2(
|
||
dir.x += horseV.x * 0.05f,
|
||
dir.y -= horseV.x*0.05f
|
||
);
|
||
horseHeadDelay.position += new Vector3(
|
||
dir.x * Time.deltaTime * headSpeed,
|
||
dir.y * Time.deltaTime * headSpeed,
|
||
0
|
||
);
|
||
HeadControlPoint.position = horseHeadDelay.position;
|
||
}
|
||
|
||
|
||
void CaculateLastFootRotation(){
|
||
for(int i = 0; i < 4; i++){
|
||
//用脚底深度减去马足深度,ABS。得到一个Progress
|
||
float footBottle = (i < 2) ? frontFoot.position.y : backFoot.position.y;
|
||
float footY = foots[i].footRealTransform.position.y;
|
||
float progress = Mathf.Abs(footBottle - footY) / (2*footMoveRadius);
|
||
//if(i == 1) Debug.Log("左前脚Progress:" + progress);
|
||
Vector2 lastFootRotationRange = (i < 2) ? lastFrontFootRotationRange : lastBackFootRotationRange;
|
||
//插值,让最后一节马脚弯曲
|
||
foots[i].lastFootTransform.rotation = Quaternion.Euler(
|
||
0,0,
|
||
Mathf.Lerp(
|
||
lastFootRotationRange.x,
|
||
lastFootRotationRange.y,
|
||
progress)
|
||
);
|
||
}
|
||
}
|
||
|
||
void CaculateFootInputCharge()
|
||
{
|
||
//计算上一帧和这一帧的输入的角度差
|
||
float angleDiff = Vector2.Angle(pInputFrontVector, inputFrontVector) +
|
||
Vector2.Angle(pInputBackVector, inputBackVector);
|
||
//把它存入队列
|
||
footInputChargeQueue.Enqueue(angleDiff);
|
||
//如果队列的长度超过了一定的数量,就把最前面的一个去掉
|
||
if(footInputChargeQueue.Count > footInputChargeQueueLength)
|
||
footInputChargeQueue.Dequeue();
|
||
|
||
//计算马脚的输入充能
|
||
footInputCharge = 0;
|
||
foreach(float angle in footInputChargeQueue)
|
||
footInputCharge += angle;
|
||
|
||
|
||
//估算了一下,充能最快大概是每秒3000.这里/3000 * 时间,即可得到一个大约0-1的值
|
||
footInputCharge /= (3000 * accelerationTime);
|
||
//Debug.Log("footInputCharge: " + footInputCharge);
|
||
|
||
//更新上一帧信息
|
||
pInputFrontVector = inputFrontVector;
|
||
pInputBackVector = inputBackVector;
|
||
}
|
||
|
||
public void Death(GameController.Death deathInfo)
|
||
{
|
||
//修改状态至死亡
|
||
horseState = HorseState.Dead;
|
||
//关闭马蹄的碰撞体,并给一个右上角的速度和旋转,让马的模型掉出地图
|
||
foreach(foot foot in foots){
|
||
//foot.footBoxCollider2D.enabled = false;
|
||
//马蹄刚体也需要给速度,否则会黏在地上飞不起来
|
||
foot.footRigidbody2D.velocity = Vector2.one * deadFlySpeed * 1.5f;
|
||
}
|
||
//马身体的碰撞体也要关
|
||
List<Collider2D> temp = new List<Collider2D>();
|
||
GetComponentsInChildren<Collider2D>(temp);
|
||
foreach(Collider2D box in temp)
|
||
box.enabled = false;
|
||
|
||
horseRig.velocity = Vector2.one * deadFlySpeed;
|
||
//播放音效
|
||
audioSource.clip = deadSE;
|
||
audioSource.Play();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 一次跳跃的最终触发函数
|
||
/// </summary>
|
||
private void Jump()
|
||
{
|
||
if(horseRig.velocity.y > 3f)
|
||
return;
|
||
|
||
//horseRig.velocity = Vector2.zero;
|
||
//修改状态至跳跃
|
||
jumpState = JumpState.Jump;
|
||
|
||
Vector2 jumpVelocity = jumpChargeVelocity * jumpForce * -1 * new Vector2(1.5f,1.5f);
|
||
Vector2 fix = new Vector2( (jumpChargeVelocity.x > 0 ? -1 : 1) *12f, 33.5f);
|
||
jumpVelocity = 1f * jumpVelocity + 0.8f * fix;
|
||
|
||
//屏蔽出了问题的极大值
|
||
if(jumpVelocity.magnitude > 40f) jumpVelocity *= 0.1f;
|
||
|
||
Debug.Log("Jump Velocity: " + jumpVelocity);
|
||
horseRig.velocity = jumpVelocity;
|
||
jumpChargeVelocity = Vector2.zero;
|
||
|
||
//播放音效
|
||
audioSource.clip = jumpSE;
|
||
audioSource.Play();
|
||
}
|
||
|
||
|
||
private bool canJump = true;
|
||
/// <summary>
|
||
/// 在跳跃状态时每帧执行,用于检测跳跃和实现跳跃的物理
|
||
/// </summary>
|
||
private void CheckJump()
|
||
{
|
||
//通过本帧输入向量减上一帧输入向量得到一个瞬时速度
|
||
Vector2 frontInstantaneousSpeed = inputFrontVector - previousInputFrontVector;
|
||
Vector2 backInstantaneousSpeed = inputBackVector - previousInputBackVector;
|
||
//如果任意一组的y大于0,说明在上升,不考虑它的跳跃
|
||
if(frontInstantaneousSpeed.y > 0 || backInstantaneousSpeed.y > 0) return;
|
||
else
|
||
{
|
||
//此时双腿在下降,开始检测跳跃蓄力
|
||
//首先看前后腿输入变化的瞬时速度的模长和是否大于蓄力标准
|
||
if(frontInstantaneousSpeed.magnitude + backInstantaneousSpeed.magnitude > jumpChargeThreshold)
|
||
{
|
||
//若输入的瞬时速度大于蓄力标准时,看马的跳跃状态,若处于准备态,则转移至蓄力态
|
||
if(jumpState == JumpState.Ready) jumpState = JumpState.Charging;
|
||
//若已处于蓄力态,累计力大小
|
||
if(jumpState == JumpState.Charging)
|
||
{
|
||
jumpChargeVelocity += (frontInstantaneousSpeed + backInstantaneousSpeed);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//若输入的瞬时速度小于蓄力标准时,看马的跳跃状态,若处于蓄力态,则触发跳跃
|
||
if(jumpState == JumpState.Charging && canJump){
|
||
Jump();
|
||
canJump = false;
|
||
ActionController.Instance.DelayToCall(
|
||
() => {
|
||
canJump = true;
|
||
},3f
|
||
);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 在Update之前更新一些数据
|
||
/// </summary>
|
||
private void UpdateDataEarly()
|
||
{
|
||
//判断是否两腿均并拢,若是,进入跳跃状态,否则设置为Stand状态
|
||
if(horseState != HorseState.Dead)
|
||
{
|
||
if (isFrontFootMerged && isBackFootMerged) horseState = HorseState.Jump;
|
||
else horseState = HorseState.Stand;
|
||
}
|
||
|
||
//Debug.Log("jumpState = " + jumpState);
|
||
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 使马并拢输入的双腿,
|
||
/// </summary>
|
||
public void MergeFoot(FootType type)
|
||
{
|
||
//根据输入的组类型,判断需要更改偏移值的是那一个索引下的脚
|
||
int index = type == FootType.Front ? 1 : 3;
|
||
footOffestOfInput[index] = Vector2.zero;
|
||
if(type == FootType.Front) isFrontFootMerged = true;
|
||
else isBackFootMerged = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 恢复输入的并拢的双腿至有偏移状态
|
||
/// </summary>
|
||
/// <param name="type">需要恢复的是哪一组腿</param>
|
||
public void RecoverFoot(FootType type)
|
||
{
|
||
//根据输入的组类型,判断需要更改偏移值的是那一个索引下的脚
|
||
int index = type == FootType.Front ? 1 : 3;
|
||
footOffestOfInput[index] = oriFootOffestOfInput[index];
|
||
if(type == FootType.Front) isFrontFootMerged = false;
|
||
else isBackFootMerged = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移动马身体
|
||
/// </summary>
|
||
private void MoveHorse()
|
||
{
|
||
Vector2 v = new Vector2();
|
||
|
||
for(int i = 0; i < 4; i++)
|
||
{
|
||
//仅在有输入的情况下,会考虑给速度
|
||
//看此时该脚是否有输入
|
||
bool hasInput = i < 2 ? inputFrontVector.magnitude > 0.1f : inputBackVector.magnitude > 0.1f;
|
||
if(!hasInput) continue;
|
||
//从足底向正下方发射射线,获取碰撞到的物体
|
||
RaycastHit2D hit = Physics2D.Raycast(
|
||
foots[i].footRealTransform.position,
|
||
Vector2.down,
|
||
1000f,
|
||
LayerMask.NameToLayer("foot")
|
||
);
|
||
//如果击中物体的距离已经超过了有效范围,则不贡献速度
|
||
if(hit.distance > effectiveDistance) continue;
|
||
//判断本帧中,马足位置是否低于圆心+调整值,仅低于时,需要计算影响
|
||
//根位置
|
||
Vector3 rootPosition = i < 2 ? frontLegRoot.position : backLegRoot.position;
|
||
//L
|
||
float L = i < 2 ? frontLegLength : backLegLength;
|
||
//圆心y坐标
|
||
float centerY = L - footMoveRadius;
|
||
centerY += effectiveDistance;
|
||
//仅低于时,需要计算影响
|
||
if(foots[i].footRealTransform.position.y >= centerY) continue;
|
||
//本帧位置减上帧位置
|
||
Vector3 trans = foots[i].footRealTransform.position - foots[i].footPreviousPosition;
|
||
Vector2 v_ = trans;
|
||
//把本足的影响加到速度中
|
||
v += v_;
|
||
}
|
||
|
||
//给速度乘以力量,得到最终理论速度
|
||
v *= strength * (1 + footInputCharge * accelerationRate);
|
||
//取反,因为是模拟反作用力
|
||
v*=-1;
|
||
//减弱y轴的影响,不要让马在平地上起飞
|
||
v *= new Vector2(1,0.2f);
|
||
|
||
//如果模长超过5,那必是触发了什么逆天Bug,会导致马起飞,需要避免这些错误
|
||
if(v.magnitude > 20f){
|
||
v = Vector2.zero;
|
||
Debug.Log("莫动");
|
||
}
|
||
|
||
//如果马处于跳跃状态,则不让马蹄提供速度
|
||
if(horseState == HorseState.Jump)
|
||
v = Vector2.zero;
|
||
|
||
//把速度加给马的刚体
|
||
horseRig.velocity += v;
|
||
}
|
||
|
||
private void UpdateDataLate()
|
||
{
|
||
//更新四足的上帧位置
|
||
for(int i = 0; i < 4; i++)
|
||
foots[i].footPreviousPosition = foots[i].footRealTransform.position;
|
||
|
||
//更新上帧输入
|
||
previousInputFrontVector = inputFrontVector;
|
||
previousInputBackVector = inputBackVector;
|
||
previousJumpState = jumpState;
|
||
}
|
||
|
||
void Init()
|
||
{
|
||
foots = new foot[4];
|
||
oriFootOffestOfInput = new Vector2[4];
|
||
footBoxColliders = new BoxCollider2D[4];
|
||
for(int i = 0; i < 4; i++) foots[i].footPreviousPosition = transform.position;
|
||
for(int i = 0; i < 4; i++) oriFootOffestOfInput[i] = footOffestOfInput[i];
|
||
horseState = HorseState.Stand;
|
||
footInputChargeQueue = new Queue<float>();
|
||
|
||
//初始化马背接收系统
|
||
GameObject.Find("接收人用的马背(不可改名)").AddComponent<HoseBack>();
|
||
}
|
||
|
||
private class HoseBack : MonoBehaviour{
|
||
private void OnTriggerEnter2D(Collider2D other) {
|
||
//当马背接受到人,触发人的Recover();
|
||
if(other.TryGetComponent<Person>(out Person person) && person.state == Person.PersonState.FallingOff) person.Recover();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void FindSth()
|
||
{
|
||
//把四只脚的目标点找到,0:左前 1:右前 2:左后 3:右后
|
||
foots[0].footControlPoint = transform.Find("左前脚").GetChild(0);
|
||
foots[1].footControlPoint = transform.Find("右前脚").GetChild(0);
|
||
foots[2].footControlPoint = transform.Find("左后脚").GetChild(0);
|
||
foots[3].footControlPoint = transform.Find("右后脚").GetChild(0);
|
||
|
||
//同步四只脚的输入偏差
|
||
for (int i = 0; i < 4; i++) foots[i].footOffestOfInput = footOffestOfInput[i];
|
||
|
||
//找到马蹄刚体组件
|
||
for(int i = 0; i < 4; i++) foots[i].footRigidbody2D = foots[i].footControlPoint.GetComponent<Rigidbody2D>();
|
||
|
||
//找到马蹄的真实Transform
|
||
for(int i = 0; i < 4; i++) foots[i].footRealTransform = footsTransform[i];
|
||
|
||
//找到马蹄的碰撞体
|
||
footBoxColliders = GetComponents<BoxCollider2D>();
|
||
|
||
//给foots的碰撞体赋值
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
foots[i].footBoxCollider2D = footBoxColliders[i];
|
||
footBoxColliders[i].offset = foots[i].footControlPoint.localPosition ;
|
||
}
|
||
|
||
//找到马的刚体
|
||
horseRig = GetComponent<Rigidbody2D>();
|
||
|
||
//
|
||
rotateCenter = transform.Find("马死后的旋转中心");
|
||
|
||
//
|
||
for(int i = 0; i < 4; i++){
|
||
foots[i].lastFootTransform = lastFoots[i];
|
||
}
|
||
|
||
//
|
||
horseHeadDelay = GameObject.Find("马头IK延迟(不可改名)").transform;
|
||
horseHeadDefault = transform.Find("马头默认位置(不可改名)");
|
||
|
||
//
|
||
//tailBone = transform.Find("bone_10");
|
||
horseTailDelay = GameObject.Find("马尾IK延迟(不可改名)").transform;
|
||
horseTailDefault = transform.Find("马尾默认位置(不可改名)");
|
||
|
||
//
|
||
audioSource = GetComponent<AudioSource>();
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算一些不会变的必要的量
|
||
/// </summary>
|
||
void CaculateSth()
|
||
{
|
||
//计算前后腿马腿长度
|
||
frontLegLength = Vector3.Distance(frontLegRoot.position, frontFoot.position);
|
||
backLegLength = Vector3.Distance(backLegRoot.position, backFoot.position);
|
||
//计算从腿根骨骼到马脚运动圆心的距离
|
||
frontRootDistanceToCenterOfCircle = frontLegLength - footMoveRadius;
|
||
backRootDistanceToCenterOfCircle = backLegLength - footMoveRadius;
|
||
//取得原始重力尺度
|
||
oriGravityScale = foots[0].footRigidbody2D.gravityScale;
|
||
//计算要记录多少帧的输入,用秒计算,每秒60次FixedUpdate
|
||
footInputChargeQueueLength = (int)accelerationTime * 60;
|
||
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据记录的输入向量计算马脚本帧的目标位置,保存到footTargetPoints数组中
|
||
/// </summary>
|
||
private void CaculateTargetPosition()
|
||
{
|
||
//循环4次
|
||
for(int i = 0; i < 4; i++)
|
||
{
|
||
//整体公式为:Target = 根位置 - V(0,L - r) + inputdir * offest * r
|
||
//根位置
|
||
Vector3 rootPosition = i < 2 ? frontLegRoot.position : backLegRoot.position;
|
||
//L
|
||
float L = i < 2 ? frontLegLength : backLegLength;
|
||
//中间向量
|
||
Vector3 middleVector = new Vector3(0,L - footMoveRadius,0);
|
||
//inputdir
|
||
Vector2 inputVector = i < 2 ? inputFrontVector : inputBackVector;
|
||
//inputTrans
|
||
Vector3 inputTrans = new Vector3
|
||
(
|
||
inputVector.x * ( footOffestOfInput[i].x + 1),
|
||
inputVector.y * ( footOffestOfInput[i].y + 1),
|
||
0
|
||
)
|
||
* footMoveRadius;
|
||
//最终计算
|
||
//footTargetPoints[i] = rootPosition - middleVector + inputTrans;
|
||
foots[i].footTargetPosition = rootPosition - middleVector + inputTrans;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 把马脚朝着算好的目标点移动
|
||
/// </summary>
|
||
private void MoveFoot()
|
||
{
|
||
//循环4次
|
||
for(int i = 0; i < 4; i++)
|
||
{
|
||
//看此时该脚是否有输入
|
||
bool hasInput = i < 2 ? inputFrontVector.magnitude > 0.1f : inputBackVector.magnitude > 0.1f;
|
||
//如果有输入,则把马脚朝着目标移动
|
||
Vector3 targetPosition = hasInput ?
|
||
foots[i].footTargetPosition :
|
||
foots[i].footTargetPosition - new Vector3(0,footMoveRadius + 0.5f,0);
|
||
// if(hasInput)
|
||
if(true)
|
||
{
|
||
//若无输入,则把目标定在可以使马腿伸直的地方
|
||
// Vector3 targetPosition = hasInput ?
|
||
// foots[i].footTargetPosition :
|
||
// foots[i].footTargetPosition - new Vector3(0,footMoveRadius + 0.5f,0);
|
||
//给刚体以target位置-自身位置作为力的方向
|
||
Vector2 Dir = targetPosition - foots[i].footControlPoint.position;
|
||
//如果已经很接近目标点了,则不再给速度,同时解除重力,防止出现抖动问题
|
||
if(Dir.magnitude < 0.1f)
|
||
{
|
||
foots[i].footRigidbody2D.gravityScale = 0;
|
||
foots[i].footRigidbody2D.velocity = Vector2.zero;
|
||
continue;
|
||
}
|
||
//标准化马脚移动方向
|
||
Dir.Normalize();
|
||
//最终计算应有的速度
|
||
Vector2 force = Dir * footForce * (horseRig.velocity.magnitude * 0.1f + 1);
|
||
//赋予脚的刚体以速度
|
||
foots[i].footRigidbody2D.velocity = foots[i].footRigidbody2D.velocity * 0.8f + force * 0.2f;
|
||
//foots[i].footRigidbody2D.velocity = force;
|
||
//foots[i].footRigidbody2D.AddForce(force);
|
||
}
|
||
// // 强制把马脚移到目标点
|
||
//foots[i].footControlPoint.position = foots[i].footTargetPosition;
|
||
//foots[i].footControlPoint.position = targetPosition;
|
||
// 恢复重力
|
||
foots[i].footRigidbody2D.gravityScale = oriGravityScale;
|
||
// 刷新碰撞体位置
|
||
footBoxColliders[i].offset = foots[i].footRealTransform.position - transform.position;
|
||
}
|
||
}
|
||
|
||
public void SetInputFrontVector(Vector2 input) => inputFrontVector = input;
|
||
|
||
public void SetInputBackVector(Vector2 input) => inputBackVector = input;
|
||
|
||
public bool IsHorseStillAlive() => horseState != HorseState.Dead;
|
||
|
||
|
||
[FoldoutGroup("SE")][Title("马蹄音效")]
|
||
public AudioSource[] footSEs;
|
||
//撞击地面后,修改跳跃状态
|
||
void OnCollisionEnter2D(Collision2D collision)
|
||
{
|
||
if(collision.gameObject.tag == "Ground")
|
||
{
|
||
//播放马蹄点地音效
|
||
Random.Range(0,footSEs.Length);
|
||
footSEs[Random.Range(0,footSEs.Length)].Play();
|
||
transform.Find("马蹄灰尘").GetComponent<ParticleSystem>().Play();
|
||
|
||
jumpState = JumpState.Ready;
|
||
//播放着地音效
|
||
if(previousJumpState == JumpState.Jump)
|
||
{
|
||
audioSource.clip = landSE;
|
||
audioSource.Play();
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|