#68
Unity制作RPG小游戏(0)

人物构建
创建empty game object,Animator,加入sprite,将人物素材(图像)赋予sprite,使unity能够识别。 创建另一个game object,Player,加入rigibody2D和collider2D(椭圆形collider),实现物理效果。 将Animator作为Player的子物体,即为将人物实体物理效果与人物sprite渲染分开处理。 :::note
-
关于sprite:可以理解为2D版本的Texture,sprite2D可以搭配使用rigibody2D和collider2D使用
-
关于rigibody2D:2D刚体,模拟2D物理效果(重力,摩擦力,反作用力)
-
关于collider2D:检测与其他collider2D的碰撞,与rigibody2D配合模拟物理效果,通过“is trigger”变为无物理阻挡的触发区域(用于检测物体进入/离开)。 :::
场景构建
创建square长方体,拉伸组合成一个简单场景,加上collider2D实现墙体与人物的碰撞(不加入rigibody2D,防止场景受重力影响往下掉)
移动检测
xInput = Input.GetAxisRaw("Horizontal");
body.velocity = new Vector2(xInput * moveSpeed, body.velocity.y);
上面的“body”,即为rigibody类的实体名,在函数初始化(start)的时候通过GetComponent函数获得
void Start()
{
body = GetComponent<Rigidbody2D>();
ani = GetComponentInChildren<Animator>();
}
跳跃检测
遇到问题:单纯通过键盘输入判定会导致按键冲突,在跳跃的时候无法移动,但实际上有向前跳/向后跳。
常用的方法是通过raycaster射线检测,通过OnDrawGizmos()函数调试射线检测距离
private void OnDrawGizmos()
{
Gizmos.DrawLine(
new Vector2(transform.position.x - 0.15f, transform.position.y),
new Vector3(transform.position.x - 0.15f, transform.position.y - groundCheckDistance));
Gizmos.DrawLine(
new Vector2(transform.position.x + 0.3f, transform.position.y),
new Vector3(transform.position.x + 0.3f, transform.position.y - groundCheckDistance));
}
//我这里画两条线当作两只脚对地面的检测,正常一条中线就够了。
//地面检测
[SerializeField] private float groundCheckDistance = 1.17f;
[SerializeField] private LayerMask whatIsGround;//通过SerializeField声明,可以在unity界面中指定whatIsGround对应的Layer,which is ground。去掉SerializeField就报错了,好像这个是必须的。
void Update()
{
//...code
isGrounded1 = Physics2D.Raycast(
new Vector2(transform.position.x - 0.15f,transform.position.y),
Vector2.down,
groundCheckDistance,
whatIsGround
);
isGrounded2 = Physics2D.Raycast(
new Vector2(transform.position.x + 0.3f, transform.position.y),
Vector2.down,
groundCheckDistance,
whatIsGround
);
isGrounded = isGrounded1 || isGrounded2;//有一只脚接触到地面就算grounded
//...code
}

动画创建

选择连续的素材帧,托选到Animation模块中,通过sample rate调整播放速度,左上角加号创建变量,用来判断动画是否播放。点击animator模块中的状态方块,创建连接箭头,表示人物不同动画间的转换,点击箭头可以创建转换的条件,转换的条件通常是前面创建的变量的改变。

:::note
通过settings项,调整动画的duration和exit time,如果想要动画在该播放的时候马上播放,就把duration调成0,exit time也关掉。如果动画播放不流畅连贯,取消勾选”Can Transition To Self”。
:::
动画播放
void Start()
{
body = GetComponent<Rigidbody2D>();
ani = GetComponentInChildren<Animator>();
}
这个脚本属于Player,但动画由子物体animator管理,通过GetComponentInChildren()函数获取。
动画的播放通常是某个相关变量状态的改变,这是通过代码判断的。通过上面获得对animator的操作权,即获得Animator的实体ani,如果某个判断条件成立,如检测到移动,“isMoving”改变
//移动动画判断
if (body.velocity.x != 0f) { isMoving = true; }
else isMoving = false;
ani.SetBool("isMoving", isMoving);//代码通过该函数管理Animator的变量的状态
Blend Tree
跳跃检测通常通过player的raycaster是否接触到地面判断,如果跳跃只有一个动画,可以用isGrounded作为动画的激活变量,但是这里跳跃有三个,起跳,下落和中间的过渡动画。则将三个动画融合成一个跳跃动画,再用isGrounded判断,Blend Tree由此而生。

Blend Tree用于平滑地混合多个动画片段(Animation Clips),以实现更自然的角色动画过渡。它自带一个参数Parameter,作为判断一维blend tree中不同动画之间切换的条件,把参数与player y轴上的速度绑定,通过设置Threshold定义不同速度对应的动画。
:::note
关于Threshold:
-
定义动画的“生效区间”:
当混合参数(如**
Velocity**)的值接近某个动画的Threshold时,该动画的权重(影响程度)会增大。- 例如:
fall动画的 Threshold =1jump动画的 Threshold =0.25- 如果当前参数
Velocity = -0.5,则系统会自动混合fall和jump两个动画。
- 例如:
-
动画混合的规则:
- 如果
Velocity等于某个动画的Threshold,则该动画权重为100%。 - 如果
Velocity介于两个Threshold之间,则两个动画按比例混合(如线性插值)。
- 如果
:::