unity制作qq炫舞的核心玩法


一、 介绍

QQ炫舞是由腾讯公司开发的一款音乐舞蹈网游,玩家可以在游戏中扮演自己的虚拟角色,跳舞展示自己的舞技,与其他玩家互动。游戏包括多种不同风格的舞曲,玩家可以通过完成任务或购买道具获得更多舞曲和装扮。

本文模拟qq炫舞游戏的核心玩法。

玩家输入上下左右按键、按空格结束,成功后角色播放动画,跳到下一个level,箭头数量+1。

在这里插入图片描述


二、 重点知识点和游戏逻辑

1.单例模式
2.使用“队列”数据结构
3.Arrows Holder组件
4.动画混合器
5.协程


三、 箭头脚本

生成单个箭头
绿色箭头是终点

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;   // 引入命名空间

using UnityEngine;
using UnityEngine.UI;

public class Arrow : MonoBehaviour    // 定义了一个名为 Arrow 的类,并继承自 MonoBehaviour 类
{
    public Sprite[] arrowSprites;      // 公有变量,类型为 Sprite 数组,用于存储箭头的图像资源
    Image image;                       // 私有变量,类型为 Image,用于引用箭头的 Image 组件

    [HideInInspector]
    public int arrowDir;               // 公有整型变量,用于存储箭头的朝向

    public Color finishColor;          // 公有变量,类型为 Color,定义了箭头到达终点时的颜色

    private void Awake()
    {
        image = GetComponent<Image>();     // 获取当前 GameObject 上的 Image 组件
    }

    public void Setup(int dir)              // 定义了一个公有方法,用于设置箭头的朝向以及显示箭头的图像
    {
        arrowDir = dir;                     
        image.sprite = arrowSprites[dir];   // 设置 Image 组件的 sprite 属性为 arrowSprites 数组中对应索引的 Sprite 对象
        image.SetNativeSize();              // 根据 Sprite 图像的大小调整 Image 组件的大小
    }

    public void SetFinish()                 // 定义了一个公有方法,用于将箭头的颜色更改为定义的终点颜色
    {
        image.color = finishColor;          // 更改 Image 组件的 color 属性为定义好的终点颜色
    }
}


四、 管理箭头脚本

生成一组箭头
队列加入箭头
箭头方向转换
判断箭头方向
销毁所有箭头
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ArrowManager : MonoBehaviour
{
    public static ArrowManager S;  // 单例实例
    private void Awake()
    {
        S = this;  // 初始化单例实例
    }

    public GameObject arrowPrefab;  // 箭头预制体
    public Transform arrowsHolder;  // 箭头容器
    public static bool isFinish;  // 是否完成当前波次

    Queue<Arrow> arrows = new Queue<Arrow>();  // 箭头队列
    Arrow currentArrow;  // 当前需要敲击的箭头

    public void CreateWave(int length)
    {
        arrows = new Queue<Arrow>();  // 初始化箭头队列
        isFinish = false;  // 重置是否完成当前波次的标志

        for (int i = 0; i < length; i++)
        {
            Arrow arrow = Instantiate(arrowPrefab, arrowsHolder).GetComponent<Arrow>();  // 实例化箭头预制体
            int randomDir = Random.Range(0, 4);  // 随机生成箭头方向
            arrow.Setup(randomDir);  // 初始化箭头

            arrows.Enqueue(arrow);  // 将箭头添加到队列中
        }

        currentArrow = arrows.Dequeue();  // 取出队列中的第一个箭头作为当前需要敲击的箭头
    }

    public void TypeArrow(KeyCode inputKey)
    {
        if (ConvertKeyCodeToInt(inputKey) == currentArrow.arrowDir)  // 判断是否敲击正确
        {
            //Type Correctly
            currentArrow.SetFinish();  // 标志当前箭头已被敲击正确

            if (arrows.Count > 0)  // 如果队列中还有箭头
            {
                currentArrow = arrows.Dequeue();  // 取出队列中的下一个箭头作为当前需要敲击的箭头
            }
            else  // 如果队列中没有箭头了
            {
                isFinish = true;  // 标志完成当前波次
            }
        }
        else  // 如果敲击错误
        {
            GameManager.S.FailWave();  // 通知 GameManager 波次失败
        }
    }

    public void ClearWave()
    {
        arrows = new Queue<Arrow>();  // 初始化箭头队列
        foreach(Transform arrow in arrowsHolder)  // 销毁箭头容器中的所有箭头
        {
            Destroy(arrow.gameObject);
        }
    }

    int ConvertKeyCodeToInt(KeyCode key)
    {
        int result = 0;
        switch(key)  // 将 KeyCode 转换为 int 类型的箭头方向
        {
            case KeyCode.UpArrow:
                {
                    result = 0;
                    break;
                }
            case KeyCode.DownArrow:
                {
                    result = 1;
                    break;
                }
            case KeyCode.LeftArrow:
                {
                    result = 2;
                    break;
                }
            case KeyCode.RightArrow:
                {
                    result = 3;
                    break;
                }
        }

        return result;  // 返回转换后的箭头方向
    }
}

五、 管理全局脚本

管理全局,负责控制节拍、动画控制、播放音乐、下一关生成
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager S;  // 单例实例
    private void Awake()
    {
        S = this;  // 初始化单例实例
    }

    int currentLevel = 5;  // 当前等级
    public static bool isDancing;  // 是否正在跳舞

    //
    public Animator anim;  // 动画控制器
    public int bpm;  // 每分钟节拍数
    public float startDelay;  // 延迟播放音乐的时间
    public AudioSource au;  // 音频源

    private void Start()
    {
        NextWave();  // 进入下一波
        //
        Invoke("PlaySound", startDelay);  // 延迟播放音乐
    }

    void PlaySound()
    {
        au.Play();  // 播放音乐
    }

    void NextWave()
    {
        UIManager.S.ShowOrHidePointer();  // 隐藏箭头指针
        UIManager.S.RenewLevelText(currentLevel);  // 更新等级显示

        ArrowManager.S.CreateWave(currentLevel);  // 创建新的箭头波次
        isDancing = true;  // 进入跳舞状态
    }

    public void FinishWave()
    {
        currentLevel++;  // 升级
        isDancing = false;  // 退出跳舞状态
        ArrowManager.S.ClearWave();  // 清除箭头波次

        UIManager.S.ShowOrHidePointer();  // 显示箭头指针

        //
        anim.SetFloat("Dance", Random.Range(0.01f, 1f));  // 随机设置动画参数
    }

    public void FailWave()
    {
        isDancing = false;  // 退出跳舞状态
        ArrowManager.S.ClearWave();  // 清除箭头波次

        UIManager.S.ShowOrHidePointer();  // 显示箭头指针

        //
        anim.SetFloat("Dance", -0.01f);  // 设置动画参数
    }

    public void PointerIsReset()
    {
        if (isDancing)
            FailWave();  // 失败
        else
            NextWave();  // 进入下一波
    }
}

六、 管理玩家输入脚本

玩家输入上下左右、空格。
如果输入错误、按得太快、按得太慢,重新加载当前关卡
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InputManager : MonoBehaviour
{
    public static InputManager S;  // 单例实例
    private void Awake()
    {
        S = this;  // 初始化单例实例
    }

    void Update()
    {
        if (!GameManager.isDancing)  // 如果没有在跳舞,直接返回
            return;

        if (Input.GetKeyDown(KeyCode.UpArrow))  // 如果按下了上箭头键
            ArrowManager.S.TypeArrow(KeyCode.UpArrow);  // 处理上箭头

        if (Input.GetKeyDown(KeyCode.DownArrow))  // 如果按下了下箭头键
            ArrowManager.S.TypeArrow(KeyCode.DownArrow);  // 处理下箭头

        if (Input.GetKeyDown(KeyCode.LeftArrow))  // 如果按下了左箭头键
            ArrowManager.S.TypeArrow(KeyCode.LeftArrow);  // 处理左箭头

        if (Input.GetKeyDown(KeyCode.RightArrow))  // 如果按下了右箭头键
            ArrowManager.S.TypeArrow(KeyCode.RightArrow);  // 处理右箭头

        if(Input.GetKeyDown(KeyCode.Space))  // 如果按下了空格键
        {
            if (ArrowManager.isFinish && UIManager.S.CheckPointerIsInSweetSpot())  // 如果当前波次已完成并且箭头指针在甜点区域内
                GameManager.S.FinishWave();  // 完成当前波次
            else
                GameManager.S.FailWave();  // 失败当前波次
        }
    }
}

七、 ui脚本

制作ui

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIManager : MonoBehaviour
{
    public static UIManager S;  // 单例实例
    private void Awake()
    {
        S = this;  // 初始化单例实例
    }

    public Text levelText;  // 显示等级的文本框
    public Transform pointer, sweetSpot;  // 箭头指针和甜点区域的位置
    public Transform startPos, endPos;  // 指针移动的起始位置和终止位置

    public float pointerMoveSpeed;  // 指针移动的速度

    private void Start()
    {
        // 根据bpm和节拍计算指针移动的速度
        pointerMoveSpeed = (endPos.position.x - startPos.position.x) / (60f / GameManager.S.bpm * 8f);
    }

    private void Update()
    {
        // 每帧将指针向右移动一定距离
        pointer.position += Vector3.right * pointerMoveSpeed * Time.deltaTime;

        // 如果指针移动到了终止位置,将指针重置到起始位置
        if (pointer.position.x > endPos.position.x)
            ResetPointer();
    }

    // 将指针重置到起始位置
    void ResetPointer()
    {
        pointer.position = startPos.position;
        GameManager.S.PointerIsReset();
    }

    // 显示或隐藏指针
    public void ShowOrHidePointer()
    {
        pointer.gameObject.SetActive(!pointer.gameObject.activeInHierarchy);
    }

    // 检查指针是否在甜点区域内
    public bool CheckPointerIsInSweetSpot()
    {
        return Mathf.Abs((pointer.position.x - sweetSpot.position.x)) < 25f;
    }

    // 更新等级文本
    public void RenewLevelText(int level)
    {
        levelText.text = "LEVEL " + level;
    }
}

八、 制作动画

下载动画模型

https://www.mixamo.com/#/?page=1&query=

创建混合树,随机生成数值,控制动画播放

在这里插入图片描述


九、 添加音乐节奏

添加不同的背景音乐,根据音乐调节节奏
设置滑动条滚动速度
private void Start()
{
    pointerMoveSpeed = (endPos.position.x - startPos.position.x) / (60f / GameManager.S.bpm * 8f);
}

十、 工程下载

https://wwez.lanzoul.com/ifDh20t2ef7i






  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忽然602

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值