骑马系统
人物在马上的脚本
csharp
using MalbersAnimations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThirdPersonRidingHorse : MonoBehaviour
{
[Header("骑马参数")]
public GameObject horse;
public bool isOnHorse;
//void OnInteract()
//{
// var thirdPersonMove = GetComponent<ThirdPersonMove>();
// thirdPersonMove.enabled = false;
// var pos = horse.transform.Find("Pos_UpToHorse");
//}
CharacterController characterController;
Animator animator;
ThirdPersonMove thirdPersonMove;
private void Awake()
{
characterController = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
thirdPersonMove = GetComponent<ThirdPersonMove>();
}
private void Update()
{
if (isOnHorse)
{
var axisX = Input.GetAxis("Horizontal");
var axisY = Input.GetAxis("Vertical");
animator.SetFloat("AxisX", axisX);
animator.SetFloat("AxisY", axisY);
}
Ride();
}
void Ride()
{
//上马
if (!isOnHorse)
{
if (Input.GetKeyDown(KeyCode.F))
{
isOnHorse = true;
transform.rotation = horse.transform.rotation;
transform.position = horse.transform.position;
//将角色放到马上
var playerPoint = horse.transform.Find("PlayerPoint");
transform.SetParent(playerPoint);
transform.localPosition = Vector3.zero;
//在马上禁用角色的characterController和move
characterController.enabled = false;
thirdPersonMove.enabled = false;
//开启马的输入控制脚本
horse.GetComponent<MalbersInput>().enabled = true;
//切换马上动作状态,即权重从0到1
animator.SetLayerWeight(2, 1f);
}
}
//下马
else
{
if (Input.GetKeyDown(KeyCode.F))
{
isOnHorse = false;
if (horse != null)
{
//删除马之前设置角色位置
transform.SetParent(null);
transform.position = horse.transform.position;
transform.rotation = horse.transform.rotation;
//下马后恢复角色的characterController和move
characterController.enabled = true;
thirdPersonMove.enabled = true;
//关闭马的输入控制脚本
horse.GetComponent<MalbersInput>().enabled = false;
//关闭马上动作层
animator.SetLayerWeight(2, 0f);
}
}
}
}
}
马的部分------插件:Horse Animset Pro Riding System 4.0.1.unitypackage

状态机设置
先学习怎么做场景交互
以常见的开宝箱交互为例:
1)先建一个可开盖宝箱的模型


2)在Box的子级中建立一个空的GameObject,当作角色开始播放交互动画的位置

3)在Box的animation窗口中建立动画------Box的开盖动画


4)这里需要把开盖动画的Loop Time给取消勾选

5)来到Timeline窗口,新建一个Box的Timeline,把Box的开盖动画和角色交互的动画拖进去

注:角色动画是mixamo里找的

角色的Track在k帧的时候选上 角色的animator,在k完之后就记得要取消勾选animator

也要记得修改该动画的名字,后面脚本会用到

为了保证开盖动画在人物动画播完后仍然还在播,点开开盖动画的Animation Track,设置为continue

6)把人物移到和PlayerStandPosition同一个位置,追求完美可以k一下开盖动画和角色动画的匹配度,并加上过渡动画(这里我就懒得弄了,因为只是学习怎么做动画交互系统)
7)为Box加上Tag-Box

8)为Box加上Trigger碰撞体

9)取消勾选Play On Awake,不然还没触发就开始播动画了


OK,交互动画匹配好了,下面写脚本控制角色到达一个Box周围的Trigger碰撞体区域,按下交互的Input按键才触发动画
脚本逻辑:
在碰撞体区域按下按键->开始找tag为Box的GameObject,找到的对象就是Box->在Box的子级中找名为PlayerStandPosition的对象->更新角色位置、朝向->在Box的playerableAsset中找到PlayerTrack,播放相应的BoxTimeline
脚本如下:
PlayerOpenBox.cs
csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.InputSystem;
public class PlayerOpenBox : MonoBehaviour
{
bool isPlaying = false;
IEnumerator OnInteract()
{
if (list.Count > 0 && isPlaying == false)
{
isPlaying = true;
var thirdPersonMove = GetComponent<ThirdPersonMove>();
thirdPersonMove.enabled = false;
var thirdPersonJump = GetComponent<ThirdPersonJump>();
thirdPersonJump.enabled = false;
var thirdPersonRoll = GetComponent<ThirdPersonRoll>();
thirdPersonRoll.enabled = false;
var director = list[0];
list.RemoveAt(0);
var pos = director.transform.Find("PlayerStandPosition");
transform.position = pos.position;
//Debug.Log(pos.position);
transform.rotation = pos.rotation;
var animator = GetComponent<Animator>();
foreach (var output in director.playableAsset.outputs)
{
if (output.streamName == "PlayerTrack")
{
director.SetGenericBinding(output.sourceObject, animator);
break;
}
}
director.Play();
while(director.state == PlayState.Playing)
{
yield return null;
}
thirdPersonMove.enabled = true;
thirdPersonJump.enabled = true;
thirdPersonRoll.enabled = true;
isPlaying = false;
}
}
List<PlayableDirector> list = new List<PlayableDirector>();
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Box")
{
var director = other.gameObject.GetComponent<PlayableDirector>();
if (director != null && !list.Contains(director))
{
list.Add(director);
}
//Debug.Log(transform.position);
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Box")
{
var director = other.gameObject.GetComponent<PlayableDirector>();
if (director != null && list.Contains(director))
{
list.Remove(director);
}
}
}
}
脚本挂在角色身上
效果如下:
