6. 开始游戏,生成主角用摇杆控制移动
Hi I'm Shendi
这节开始制作游戏交互部分,在此之前先更改一下背景方块生成速度
Background代码更改
在之前使用的 InvokeRepeating
函数来生成方块,这种方式是固定一定时间创建方块,每次打开游戏时随机的时间就固定了,所以就造成了有时打开游戏,方块生成快,有时打开,方块生成慢
于是改用协程来实现
/** 单例 */
public static Background _instance;
private void Awake()
{
_instance = this;
}
// Start is called before the first frame update
void Start()
{
StartCoroutine(CreateRanBox());
}
/** 创建方块,三秒后销毁 */
IEnumerator CreateRanBox()
{
while (true)
{
// 等待随机时间
yield return new WaitForSeconds(Random.Range(0.5f, 1.5f));
// 创建方块
if (State.isBackgroundPlay) {
var obj = State.CreateRanBox();
obj.transform.parent = transform;
obj.transform.localPosition = Vector2.zero;
Rigidbody rigidbody = obj.AddComponent<Rigidbody>();
rigidbody.velocity = Vector3.down * Random.Range(0.1f, 2f);
Destroy(obj, 2f);
}
else
{
break;
}
}
}
以上可以改可以不改,只是一个小插曲,Awake在对象被初始化时执行,执行的顺序会在Start函数之前
上面使用了死循环,在 State.isBackgroundPlay
为false时会跳出死循环
后面做开始游戏时会停止背景,游戏结束要重新执行背景,所以使用单例将对象提供出去
如果使用之前那种方法,后面控制背景的开关只需要设置 State.isBackgroundPlay
即可
开始游戏按钮操作
第一步当然是要编写点击开始游戏按钮事件的处理操作
增加点击事件
打开之前新建的脚本 Main
,在里面新增一个函数命名为 StartGame
,代表启动游戏
public class Main : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
/** 开始游戏点击 */
public void StartGame()
{
Debug.Log("click");
}
}
这个脚本在之前是添加到了主摄像机上
在Unity内点击开始游戏按钮,在右边找到Button组件,展开,找到 鼠标单击
,点击小圆圈,选择主摄像机
点击右边的No Function,选择 Main - StartGame ()
这样点击按钮时就会触发 Main 脚本内的 StartGame 函数了,运行点击一下,会发现函数执行了
思路
从目前的角度出发,点击开始游戏按钮后应
- 初始化一些数值等
- 停止背景的播放
- 隐藏主页,显示游戏页面
- 创建角色到游戏界面
- ...
停止背景播放
之前我们使用了一个变量来做这个功能,将变量状态改变即可
// 停止背景播放
State.isBackgroundPlay = false;
运行,点击开始游戏按钮,即可看到没有方块往下掉落了
隐藏主页,显示游戏页面
首先创建一个空对象,将主页的一些内容都放到空对象内
再创建一个空对象,作为游戏内容的父对象,命名例如 PageMain,PageGame
然后在 Main
脚本内创建两个公开变量
public class Main : MonoBehaviour
{
public GameObject pageMain;
public GameObject pageGame;
}
保存后可以在Unity的摄像机内的Main组件处看到 pageMain 和 pageGame 的框框,在层级面板将PageMain和PageGame分别拖入到对应的框框(或者点击框框右边的圆圈直接选择)
接下来编写代码,使用游戏对象的SetActive函数来控制显示隐藏,隐藏 pageMain,显示 pageGame 即可
/** 开始游戏点击 */
public void StartGame()
{
// 停止背景播放
State.isBackgroundPlay = false;
// 隐藏main显示game
pageMain.SetActive(false);
pageGame.SetActive(true);
}
在层级面板点击对象,右边检查器有个勾选框,取消勾选则可以默认就隐藏
通常还会记录游戏的状态,例如是否开始游戏,是否暂停游戏,于是在 State 中添加两个属性
/** 游戏是否开始 */
public static bool isGameStart = false;
/** 游戏是否暂停 */
public static bool isGamePause = false;
在 StartGame 中将 isGameStart 置为 true 即可
实例化主角
将主角的预制体同之前小方块一样,在State类中加载
/** 角色 */
public static GameObject player = Resources.Load<GameObject>("Prefabs/Player");
除此之外,可以把角色实例化和销毁的部分封装成函数放到State中
#region 角色部分
/** 角色实例 */
public static GameObject playerInstance;
#endregion
/** 角色初始化,初始化完成后 playerInstance 将为实例化的角色 */
public static GameObject PlayerInit()
{
playerInstance = GameObject.Instantiate(player);
return playerInstance;
}
/** 角色销毁 */
public static void PlayerDestory()
{
if (playerInstance != null)
{
GameObject.Destroy(playerInstance);
playerInstance = null;
}
}
在开始游戏按钮处理处增加调用即可实例化主角
// 实例化主角
State.PlayerInit().transform.parent = pageGame.transform;
运行游戏,点击开始游戏按钮,可以看到角色在左下角生成了
让角色动起来
摇杆的制作
UI分为两部分
- 摇杆的背景(最外层的圈圈)
- 摇杆中心可拖动的圆点
在 PageGame 处创建 UI - 图像,然后在创建的图像下继续创建一个图像
点击最外层的图像,点击右边源图像右边的圆圈,发现有一个圆圈的图片,选择使用
更改一下颜色透明度和大小,将其拖动到左下角(按Shift+鼠标拖拽大小可以等比缩放)
然后在层级面板选择图像下的图像,同样设置一样的源图像,调整一下大小和颜色,效果如下
层级面板如下
摇杆的脚本
创建一个脚本名为 Rocker,将脚本拖到层级面板的Rocker上,然后编写代码
首先,将以下两个using语句添加到脚本头部:
using UnityEngine.UI;
using UnityEngine.EventSystems;
这两个命名空间中包含摇杆中用到的UI元素和事件系统。
然后,在类定义前添加以下代码:
public class Rocker: MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
这个代码意味着该脚本实现IDragHandler、IPointerUpHandler、IPointerDownHandler接口,其中IDragHandler接口处理拖放事件,IPointerUpHandler接口处理放手事件,IPointerDownHandler接口处理按下事件。
接着,在类定义内添加以下成员变量:
public Image rockerImg;
public Image rockerCenterImg;
在 Start 中初始化变量
void Start()
{
rockerImg = GetComponent<Image>();
rockerCenterImg = transform.GetChild(0).GetComponent<Image>();
}
接下来处理 OnPointerDown
按下事件,想实现的效果是默认摇杆应该是隐藏的,等在哪点击就在哪出现,隐藏可以直接在Unity中取消勾选即可
但是会发现上面三个事件只有在点击摇杆元素时才会触发
于是需要改动一下,新增一个UI图片元素,作为拖拽区域
拖拽区域即在这一块点击时可以触发摇杆操作
将颜色设为透明,然后调整想要的区域大小
将Rocker上的脚本拖到RockerPanel,接下来继续编写代码
Start的改动
void Start()
{
rockerImg = transform.GetChild(0).GetComponent<Image>();
rockerCenterImg = transform.GetChild(0).GetChild(0).GetComponent<Image>();
}
当按下时,显示摇杆,并记录和初始化位置
/** 摇杆第一次点击的位置 */
private Vector2 firstPos;
// 处理按下事件
public void OnPointerDown(PointerEventData eventData)
{
// eventData.position是按下的位置
rockerImg.transform.position = eventData.position;
firstPos = eventData.position;
OnDrag(eventData);
rockerImg.gameObject.SetActive(true);
}
其中的 OnDrag 是拖拽时触发的函数,调用是为了初始化摇杆中心的小点位置
当抬起(按下后松手)时,隐藏摇杆
// 处理按下后放手事件
public void OnPointerUp(PointerEventData eventData)
{
rockerImg.gameObject.SetActive(false);
rockerCenterImg.transform.position = Vector2.zero;
}
剩下的就是拖拽了,因为我们的脚本绑在拖拽区域上,所以要以摇杆的位置为中心
将拿到的位置要去掉按下的位置就可以了,然后将位置归一化,最后限制小圆点的位置不超出外层圆圈位置
// 处理拖放事件
public void OnDrag(PointerEventData eventData)
{
Vector2 position = Vector2.zero;
// 当前位置为点击位置减去初始位置
var curPos = new Vector2(eventData.position.x - firstPos.x, eventData.position.y - firstPos.y);
curPos = (curPos.magnitude > 1) ? curPos.normalized : curPos;
// 限制能移动的区域
rockerCenterImg.rectTransform.anchoredPosition = new Vector2(curPos.x * (rockerImg.rectTransform.sizeDelta.x / 3), curPos.y * (rockerImg.rectTransform.sizeDelta.y) / 3);
}
在这里还需要将当前位置保存起来或提供出去,并且在抬起时重置
// 当前摇杆拖拽位置
public static Vector2 curPos;
public void OnDrag(PointerEventData eventData) {
// ...
Rocker.curPos = curPos;
}
public void OnPointerUp(PointerEventData eventData) {
// ...
Rocker.curPos = Vector2.zero;
}
角色的脚本
打开Player脚本,在代码中通过摇杆脚本提高的位置来更改角色的位置
分析一下位置信息,根据之前的策划,角色默认可以移动两方块/秒,那么就是1/s,使用固定的调用函数 FixedUpdate,一秒执行五十次,那么每次移动 1/50=0.02
将这些信息放到 State 中:
/** 小方块的大小 */
public static float boxSize = box.GetComponent<Renderer>().bounds.size.x;
在 Player
脚本中记录角色速度
/** 每次的角色速度,两个小方块大小,每秒执行50次 */
public float playerSpeed;
private void Awake()
{
playerSpeed = State.boxSize * 2 / 50;
}
每次执行判断摇杆是否有操作,有则判断移动方向,摇杆往上代表跳跃(y>0.7)
首先做左右部分,x负数为左,正数为右
void FixedUpdate()
{
var curPos = Rocker.curPos;
if (curPos.magnitude != 0)
{
if (curPos.x < 0)
{
transform.position = new Vector3(transform.position.x - playerSpeed, transform.position.y);
}
else if (curPos.x > 0)
{
transform.position = new Vector3(transform.position.x + playerSpeed, transform.position.y);
}
}
}
运行后,开始游戏,即可控制角色左右移动了
本文链接:https://sdpro.top/blog/html/article/1065.html
♥ 赞助 ♥
尽管去做,或许最终的结果不尽人意,但你不付出,他不付出,那怎会进步呢?