Unity作为游戏开发引擎,具有非常强大的功能。本系列文章作为unity游戏开发的个人学习笔记,仅供参考,请勿转载。
游戏角色创建
- 资源导入
- 添加角色动画
- 创建角色动画状态机
- 编写角色控制器脚本
资源导入
资源可以先从unity自带的商店下载导入,也可以自己制作后直接拖入项目中。
打开资源商店
可以直接在搜索框中快速搜索自己想要的资源,也可以点击在浏览器打开,筛选自己需要的种类,或者可以先把资源收藏,然后在自己的收藏夹中下载导入。
使用资源商店
也可以点击自己的头像,点击我的资源选择自己以前的资源导入。
导入资源
选择自己需要的资源导入
将资源拖入指定目录
调整资源路径
在资源目录中选中对应的精灵表资源
选中要使用的精灵表
选择Sprite模式为多个,然后点击编辑,将精灵表按size切片,最后选择压缩格式为无。
编辑精灵表
添加角色动画
可以先调整自己资源图片的尺寸,修改单位像素数为适合自己项目的,然后点击应用
调整比例
选择待机动画精灵表资源,将该资源拖入场景中
拖入动画资源
在我们用来指定存放动画的路径中创建动画
创建动画
在检查器中修改对象层级
image.png
然后就可以在场景中看到拖入的角色
拖入角色动画
点击播放预览,可以看到动画效果
角色动画预览
同理,创建其他动作的动画
角色动作演示
然后在动画资源夹下删除多余的动画控制器
删除控制器
将场景中多余的动画也删除,只保留待机动画
删除多余的动作,只保留idle待机动画
将该对象以及动画控制器重命名为Player,并设置标签
重命名位Player
在检查器中将标签设置为Player
添加碰撞体组件
添加2d胶囊碰撞器
调整碰撞器大小和位置尽量接近角色
绿色椭圆代表角色的碰撞体
继续添加2D刚体组件,用来实现对角色的操控,并且锁定Z轴防止其旋转
继续添加2D刚体
禁用Z轴旋转
创建角色动画状态机
重命名Idle的动画控制器为Player
选择基础动作的动画的控制器为主要控制器
在控制器中添加若干空状态,并命名为对应的动作,并设置相应的动画
创建空状态
重命名并设置动作动画
设置完成
设置状态变量,来决定动画状态的转换
在这里添加新的状态变量参数
新建状态,用来控制对应动画的转换逻辑,更多的变量能操控更多的动画,或者用来监视角色的某些状态数值
关联不同状态来实现动画状态转换的逻辑
新建状态转化关联
点击选中该关联
在检查器中点击加号创建新的约束,speed大于0.01。表示在速度大于0.01时,角色动画会由idel转化为run
同理,创建由run转化为idel的关联
在speed小于0.01的时候,动画将会由run转化为idel
跳跃状态可由任意状态转化来
通过isGround来判定是否是跳跃状态
编写角色控制器脚本
创建新脚本
新建C#脚本,并重命名为PlayerScript
使用vs来编辑脚本
双击打开脚本编辑器(需要在安装unity时选择安装vs开发工具模块)
简单地编写一些角色的基本控制代码
代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
public class PlayerScript : MonoBehaviour
{
//开放参数给外部的编辑器
[SerializeField] float maxSpeed = 10f;
[SerializeField] float jumpSpeed = 10f;
[SerializeField] LayerMask whatIsGround;//设置地面层
[SerializeField] float groundRadius = 0.5f;//脚底检测半径
[SerializeField] int maxJumpCount = 1;//落地前最多跳跃次数
Transform groundCheck;//判断是否与地面接触的空物体
bool grounded = false;//是否在地面上
Animator anim;//动画控制器
Rigidbody2D body;//角色身体
bool facingRight = true;//角色朝向
bool jump = false;//是否按跳跃键
int jumpCount = 0;//当前跳跃次数
private void Awake()
{
//初始化部分变量
groundCheck = transform.Find("GroundCheck");
anim = GetComponent<Animator>();
body = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
grounded = false;
Collider2D[] colliders = Physics2D.OverlapCircleAll(groundCheck.position, groundRadius, whatIsGround);
foreach (Collider2D collider in colliders)
{
//遍历接触的面,判断是否在地面上
if (collider.gameObject != gameObject)
{
grounded = true;
jumpCount = 0;
/*if (body.velocity.y == 0)//落地后(垂直方向速度为0),清空跳跃计数
{
jumpCount = 0;
anim.SetInteger("jumpCount", jumpCount);
}*/
}
}
if (!grounded && jumpCount == 0)
{
jumpCount = 1;
}
//修改动画控制器变量
anim.SetInteger("jumpCount", jumpCount);
anim.SetBool("isGround", grounded);
anim.SetFloat("vSpeed", body.velocity.y);
//获取水平方向运动和跳跃操作
float h = Input.GetAxis("Horizontal");//水平移动 1:向右;-1:向左;
if (!jump)
{
jump = Input.GetButtonDown("Jump");
}
Move(h, jump);//移动方法
jump = false;
/*var t = Task.Run(async delegate
{
await Task.Delay(1000);
jump = false;//每隔1s检测一次跳跃键
if (grounded)
{
jumpCount = 0;
anim.SetInteger("jumpCount", jumpCount);
}
});*/
}
void Move(float move, bool jumping)
{
anim.SetFloat("speed", Mathf.Abs(move));
body.velocity = new Vector2(move * maxSpeed, body.velocity.y);//移动角色
if ((move > 0 && !facingRight) || (move < 0 && facingRight))
{
//运动方向与朝向不一致时,反转朝向
Filp();
}
//在地面上跳跃时,添加跳跃力
//if (jumping && anim.GetBool("isGround"))
if (jumping)
{
if (grounded)
{
jumpCount = 1;
Jump();
}
else
{
if (jumpCount < maxJumpCount)
{
jumpCount++;
Jump();
}
}
}
}
void Jump()
{
grounded = false;
anim.SetBool("isGround", false);
anim.SetInteger("jumpCount", jumpCount);
//body.AddForce(new Vector2(0f, jumpForce));
body.velocity = new Vector2(body.velocity.x, jumpSpeed);//跳跃
}
void Filp()//反转角色朝向
{
facingRight = !facingRight;
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
}
}
将脚本添加给角色
在检查器里点击底部添加组件按钮,搜索自己刚才添加的脚本
添加脚本
给角色添加一个空对象
给该对象重命名为GroundCheck,用来作为地面碰撞检测点
将该对象的位置移动到角色底部
在层级中选中地形Grid,然后在检查器中添加图层
新建图层TileMap
将地形设置为该图层
调整角色的参数以及脚本的参数
这时运行游戏,会发现动作不流畅,这时候需要调整动作状态的过渡
在动画控制器中选中关联箭头,去掉推出时间的勾选,调整过渡渐变,直到动作流畅
然后再运行游戏演示,可以看到操作效果
操作演示
至此,一个基本的可供操作的游戏角色便创建完成了。