您的位置:首页 > 其它

今天开始做人物--会跑会跳的韩菱纱(如何制作第三人称人物控制)

2015-04-17 10:21 176 查看
一个游戏最直观的体验就是上手的游戏化身操作了,如何让游戏化身会跑会跳,甚至卖卖萌,虽然看起来基本,但确是游戏中最重要的,因为游戏化身与游戏内的其他原件交互,都是建立在人物化身的操控系统之下的,比如说,我们想与场景中的一个npc做交互,比如对话,或者购买物品,第一点,我们要跑(走)到npc面前,而想做到这个我们就需要对玩家化身做操控。u3d这一点做得非常好,甚至自己自带了一个玩家的控制系统,包括第一人称和第三人称两种模式,我们这里主要讨论第三人称,因为不是讲解系统提供的控制系统所以我们主要入正题,讲解UnityChan插件系统,为啥用它呢,因为开始我想用Character
System4来做,但用了之后发现,Character System4因为主要是针对摇杆控制器操作的,动作匹配也与摇杆的运动很契合,但实际用到电脑游戏中他的动作有时看起来就有些奇怪,所以最后选用了UnityChan插件系统,这个系统不仅包括一个比较完善的人物动作控制,还包括脸部运动的(表情系统--不过这个需要美术的支持,我这里没能实现面部表情,-具体想学习的话,某网站有一套免费的11课时的专门讲解UnityChan插件的视频教程,喜欢的可以自己看看,如果将来有条件,我会在后续Demo里加入表情系统)我们先看一下这个插件的运行效果






看下两个开发窗口


插件中使用的预制件,主要控制的人物预制件,unitychan上面捆绑了2个脚本,我们看下代码

//
// Mecanimのアニメーションデータが、原点で移動しない場合の Rigidbody付きコントローラ
// サンプル
// 2014/03/13 N.Kobyasahi
//
using UnityEngine;
using System.Collections;

// 必要なコンポーネントの列記
[RequireComponent(typeof (Animator))]
[RequireComponent(typeof (CapsuleCollider))]
[RequireComponent(typeof (Rigidbody))]

public class UnityChanControlScriptWithRgidBody : MonoBehaviour
{

public float animSpeed = 1.5f;				// アニメーション再生速度設定
public float lookSmoother = 3.0f;			// a smoothing setting for camera motion
public bool useCurves = true;				// Mecanimでカーブ調整を使うか設定する
// このスイッチが入っていないとカーブは使われない
public float useCurvesHeight = 0.5f;		// カーブ補正の有効高さ(地面をすり抜けやすい時には大きくする)

// 以下キャラクターコントローラ用パラメタ
// 前進速度
public float forwardSpeed = 7.0f;
// 後退速度
public float backwardSpeed = 2.0f;
// 旋回速度
public float rotateSpeed = 2.0f;
// ジャンプ威力
public float jumpPower = 3.0f;
// キャラクターコントローラ(カプセルコライダ)の参照
private CapsuleCollider col;
private Rigidbody rb;
// キャラクターコントローラ(カプセルコライダ)の移動量
private Vector3 velocity;
// CapsuleColliderで設定されているコライダのHeiht、Centerの初期値を収める変数
private float orgColHight;
private Vector3 orgVectColCenter;

private Animator anim;							// キャラにアタッチされるアニメーターへの参照
private AnimatorStateInfo currentBaseState;			// base layerで使われる、アニメーターの現在の状態の参照

private GameObject cameraObject;	// メインカメラへの参照

// アニメーター各ステートへの参照
static int idleState = Animator.StringToHash("Base Layer.Idle");
static int locoState = Animator.StringToHash("Base Layer.Locomotion");
static int jumpState = Animator.StringToHash("Base Layer.Jump");
static int restState = Animator.StringToHash("Base Layer.Rest");

// 初期化
void Start ()
{
// Animatorコンポーネントを取得する
anim = GetComponent<Animator>();
// CapsuleColliderコンポーネントを取得する(カプセル型コリジョン)
col = GetComponent<CapsuleCollider>();
rb = GetComponent<Rigidbody>();
//メインカメラを取得する
cameraObject = GameObject.FindWithTag("MainCamera");
// CapsuleColliderコンポーネントのHeight、Centerの初期値を保存する
orgColHight = col.height;
orgVectColCenter = col.center;
}

// 以下、メイン処理.リジッドボディと絡めるので、FixedUpdate内で処理を行う.
void FixedUpdate ()
{
float h = Input.GetAxis("Horizontal");				// 入力デバイスの水平軸をhで定義
float v = Input.GetAxis("Vertical");				// 入力デバイスの垂直軸をvで定義
anim.SetFloat("Speed", v);					// Animator側で設定している"Speed"パラメタにvを渡す
anim.SetFloat("Direction", h); 					// Animator側で設定している"Direction"パラメタにhを渡す
anim.speed = animSpeed;						// Animatorのモーション再生速度に animSpeedを設定する
currentBaseState = anim.GetCurrentAnimatorStateInfo(0);	// 参照用のステート変数にBase Layer (0)の現在のステートを設定する
rb.useGravity = true;//ジャンプ中に重力を切るので、それ以外は重力の影響を受けるようにする

// 以下、キャラクターの移動処理
velocity = new Vector3(0, 0, v);		// 上下のキー入力からZ軸方向の移動量を取得
// キャラクターのローカル空間での方向に変換
velocity = transform.TransformDirection(velocity);
//以下のvの閾値は、Mecanim側のトランジションと一緒に調整する
if (v > 0.1) {
velocity *= forwardSpeed;		// 移動速度を掛ける
} else if (v < -0.1) {
velocity *= backwardSpeed;	// 移動速度を掛ける
}

if (Input.GetButtonDown("Jump")) {	// スペースキーを入力したら

//アニメーションのステートがLocomotionの最中のみジャンプできる
if (currentBaseState.nameHash == locoState){
//ステート遷移中でなかったらジャンプできる
if(!anim.IsInTransition(0))
{
rb.AddForce(Vector3.up * jumpPower, ForceMode.VelocityChange);
anim.SetBool("Jump", true);		// Animatorにジャンプに切り替えるフラグを送る
}
}
}

// 上下のキー入力でキャラクターを移動させる
transform.localPosition += velocity * Time.fixedDeltaTime;

// 左右のキー入力でキャラクタをY軸で旋回させる
transform.Rotate(0, h * rotateSpeed, 0);

// 以下、Animatorの各ステート中での処理
// Locomotion中
// 現在のベースレイヤーがlocoStateの時
if (currentBaseState.nameHash == locoState){
//カーブでコライダ調整をしている時は、念のためにリセットする
if(useCurves){
resetCollider();
}
}
// JUMP中の処理
// 現在のベースレイヤーがjumpStateの時
else if(currentBaseState.nameHash == jumpState)
{
cameraObject.SendMessage("setCameraPositionJumpView");	// ジャンプ中のカメラに変更
// ステートがトランジション中でない場合
if(!anim.IsInTransition(0))
{

// 以下、カーブ調整をする場合の処理
if(useCurves){
// 以下JUMP00アニメーションについているカーブJumpHeightとGravityControl
// JumpHeight:JUMP00でのジャンプの高さ(0〜1)
// GravityControl:1⇒ジャンプ中(重力無効)、0⇒重力有効
float jumpHeight = anim.GetFloat("JumpHeight");
float gravityControl = anim.GetFloat("GravityControl");
if(gravityControl > 0)
rb.useGravity = false;	//ジャンプ中の重力の影響を切る

// レイキャストをキャラクターのセンターから落とす
Ray ray = new Ray(transform.position + Vector3.up, -Vector3.up);
RaycastHit hitInfo = new RaycastHit();
// 高さが useCurvesHeight 以上ある時のみ、コライダーの高さと中心をJUMP00アニメーションについているカーブで調整する
if (Physics.Raycast(ray, out hitInfo))
{
if (hitInfo.distance > useCurvesHeight)
{
col.height = orgColHight - jumpHeight;		// 調整されたコライダーの高さ
float adjCenterY = orgVectColCenter.y + jumpHeight;
col.center = new Vector3(0, adjCenterY, 0);	// 調整されたコライダーのセンター
}
else{
// 閾値よりも低い時には初期値に戻す(念のため)
resetCollider();
}
}
}
// Jump bool値をリセットする(ループしないようにする)
anim.SetBool("Jump", false);
}
}
// IDLE中の処理
// 現在のベースレイヤーがidleStateの時
else if (currentBaseState.nameHash == idleState)
{
//カーブでコライダ調整をしている時は、念のためにリセットする
if(useCurves){
resetCollider();
}
// スペースキーを入力したらRest状態になる
if (Input.GetButtonDown("Jump")) {
anim.SetBool("Rest", true);
}
}
// REST中の処理
// 現在のベースレイヤーがrestStateの時
else if (currentBaseState.nameHash == restState)
{
//cameraObject.SendMessage("setCameraPositionFrontView");		// カメラを正面に切り替える
// ステートが遷移中でない場合、Rest bool値をリセットする(ループしないようにする)
if(!anim.IsInTransition(0))
{
anim.SetBool("Rest", false);
}
}
}

void OnGUI()
{
GUI.Box(new Rect(Screen.width -260, 10 ,250 ,150), "Interaction");
GUI.Label(new Rect(Screen.width -245,30,250,30),"Up/Down Arrow : Go Forwald/Go Back");
GUI.Label(new Rect(Screen.width -245,50,250,30),"Left/Right Arrow : Turn Left/Turn Right");
GUI.Label(new Rect(Screen.width -245,70,250,30),"Hit Space key while Running : Jump");
GUI.Label(new Rect(Screen.width -245,90,250,30),"Hit Spase key while Stopping : Rest");
GUI.Label(new Rect(Screen.width -245,110,250,30),"Left Control : Front Camera");
GUI.Label(new Rect(Screen.width -245,130,250,30),"Alt : LookAt Camera");
}

// キャラクターのコライダーサイズのリセット関数
void resetCollider()
{
// コンポーネントのHeight、Centerの初期値を戻す
col.height = orgColHight;
col.center = orgVectColCenter;
}
}
看下UnityChanControlScriptWithRgidBody.cs这个类,UnityChan这个插件自带了日文和英文两种语言的文档,代码中注释也相当详细,代码也并不难懂,这里我大致的分析下,这段代码开头,
[RequireComponent(typeof (Animator))]
[RequireComponent(typeof (CapsuleCollider))]
[RequireComponent(typeof (Rigidbody))]


使得人物预制件需要3个系统组件来支持,作用呢,animator是u3d全新的动画系统的控制组件,CapsuleCollider是一个包裹人物预制件的碰撞体,而最后那个是刚体系统,

代码的FixedUpdate()方法中主要是anim.SetFloat("Speed", v);这种动画控制代码那么,具体代码是怎么控制的呢,我们看下animator中载入的控制器



我们可以看到控制器默认动作未Idle,而通过迁移线与其他动作相连,而左下方提供了控制动作变化的变量,我们就是通过变量的控制来达到动作的转换的,

我们以Jump变量为例,代码中if (Input.GetButtonDown("Jump")){}也就是空格按下,这时候如果符合条件,如人物正在跑动,那么anim.SetBool("Jump", true);这样动作控制就完成了,而另外一个类FaceUpdate.cs这个类非常简单

using UnityEngine;
using System.Collections;

public class FaceUpdate : MonoBehaviour
{
public AnimationClip[] animations;

Animator anim;

public float delayWeight;

void Start ()
{
anim = GetComponent<Animator> ();
}

void OnGUI ()
{
foreach (var animation in animations) {
if (GUILayout.Button (animation.name)) {
anim.CrossFade (animation.name, 0);
}
}
}

float current = 0;

void Update ()
{

if (Input.GetMouseButton (0)) {
current = 1;
} else {
current = Mathf.Lerp (current, 0, delayWeight);
}
anim.SetLayerWeight (1, current);
}
}
其实就是个由屏幕按钮控制人物表情,播放的功能,这里需要注意一点可能就是一个不太注意的细节就是



这个遮罩,如果按照这个系统做的表情播放不出来,那么建议去注意下这个,其他的因为这个代码很好理解,也没什么可说的,如果真的就不懂,网上有一套UnityChan的11集的免费视频教程,大家可以去看看,里面包括如果用maya来建立人物都写得很详细,最后我们就看看如何利用这些代码呢?首先我们在网上下载一个人物模型

我们以韩菱纱为例,注意我们使用的模型可以没有绑定动作,但必须顶点骨骼绑定完成的,否则,我们导出的fbx文件将是石膏模,我们在场景中是无法使用的,具体怎么导出,在菜单里找导出,然后选fbx文件格式就行了,当然导其他的格式也可以,但需要注意的是,要是u3d支持的3d格式,然后我们把导好的模型复制进工程文件夹,

,记得先把贴图赋一下,之后,我们点击hls0这个fbx文件我们设置生成Avatar

具体为什么设置avatar我建议不明白的小伙伴去看这篇文章配置Avatar,然后把hls0做成预制件,具体做法就是拖到

就可以了,之后我们在属性窗口中,绑定我们需要的

里面的参数需要自己按照自己的模型来调整

关于数据我们可以按照需要自己调整,比如我们可以改变JumpPower来改变化身跳跃的高度,其实这个场景中还有一个比较重要的预制件,


就是摄像机,我们依靠这个来达到相机跟谁化身效果,但,untiychan里面的两个摄像机控制方式都跟我们平时玩的3剑游戏控制方式不同,所以在我的仙剑Demo中没有用到这个预制件,等后面我会讲解我们在Demo中用到的镜头跟随方法,最后我们看下我们最终做的人物是什么样的吧,



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐