【Unity音游制作】音符和音符对象池的创建【二】

在这里插入图片描述


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创

👨‍💻 收录于专栏:Unity基础实战

🅰️



文章目录

    • 🅰️
    • 让音符踩着音乐节奏被我们击打
    • 🎶(==1==) 音符对象池的介绍
    • 🎶(==2==) 音符对象池的创建
    • 🎶(==3==) 音符对象的位置的创建
    • 🎶(==4==) 音符对象的精灵的赋值
    • 🎶(==5==) 音符对象的在轨道的初步运行
    • 🎶(==6==) 音符特效的制作
    • 🎶(==7==) 音符预制体的逻辑
    • 🅰️


让音符踩着音乐节奏被我们击打


🎶(1 音符对象池的介绍


在Unity中,对象池是一种常用的设计模式,它的思想是提前创建一些对象并保存起来,当需要使用这些对象时,直接从对象池中取出,使用完毕后再放回对象池,而不是频繁地创建和销毁对象。
对象池在游戏中的应用非常广泛,特别是在需要频繁创建和销毁对象的情况下,使用对象池可以显著减少性能开销,提高游戏的性能和流畅度。
在Unity中,可以通过以下步骤实现对象池的思想:

    1. 创建一个对象池类,该类负责创建和管理对象池。可以使用List或Queue等数据结构来保存对象池中的对象。对象池类应该具有创建对象、获取对象和回收对象的方法。
    1. 在对象池类中,使用Unity的Instantiate方法来创建一定数量的对象,并将这些对象保存到对象池中。
    1. 在需要使用对象的地方,通过对象池类的获取对象方法获取对象。如果对象池中没有可用的对象,则可以选择创建新的对象或者等待对象池中有可用对象为止。
    1. 使用完对象后,将对象通过对象池类的回收对象方法放回对象池中,以便重复使用。

使用对象池可以避免频繁地创建和销毁对象,减少内存的分配和释放,提高游戏的性能。同时,对象池还可以控制对象的数量,防止过多的对象创建导致内存溢出。



🎶(2 音符对象池的创建


    //音符块对象池(栈)声明
    private Stack<NoteObject> noteObjectsPool = new Stack<NoteObject>();

    //从对象池中取音符对象
    public NoteObject GetNotePooling()
    {
        NoteObject note;

        if (noteObjectsPool.Count > 0)
        {
            note = noteObjectsPool.Pop();  //出栈
        }
        else
        {
            note = Instantiate(noteObject);//实例化音符预制体
        }

        //上保险(保证note自身 和其组件都为激活状态)
        note.gameObject.SetActive(true);
        note.enabled = true;
        return note;
    }

    //将音符对象放入对象池
    public  void ReturnNotePooling(NoteObject note)
    {
        if(note != null )
        {
            note.enabled = false;
            note.gameObject.SetActive(false);
            noteObjectsPool.Push(note);   //压栈
        }
    }

🎶(3 音符对象的位置的创建


构建音符的上下界(产生和消失的位置)

在这里插入图片描述


🎶(4 音符对象的精灵的赋值


在这里插入图片描述


🎶(5 音符对象的在轨道的初步运行


在这里插入图片描述

  • NoteObject (音符脚本)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SonicBloom.Koreo;
//-------------------------------
//-------功能:  音符脚本
//-------创建者:         -------
//------------------------------

public class NoteObject : MonoBehaviour
{
    //精灵渲染变量
    public SpriteRenderer spriteRenderer;
    //所有精灵图集数组
    public Sprite[] noteSprites;
    //对应的音乐插件事件
    KoreographyEvent trackedEvent;
    //是否是长音符
    public bool isLongNote;
    //是否是长音符的结尾
    public bool isLongNoteEnd;
    //音轨管理器脚本
    STrackContorller strackController;  
    //游戏管理器脚本
    RythmGameContorller gameController;

    public int hitOffset;

    void Start()
    {
        
    }

    void Update()
    {
        //一直更新音符的位置
        UpdatePosition();
    }

    /// <summary>
    /// 初始化音符的方法
    /// </summary>
    /// <param name="evt">音符插件中的事件类</param>
    /// <param name="noteNum">当前音符的索引</param>
    /// <param name="STackIndex">当前所在的音轨脚本</param>
    /// <param name="gameContorl">游戏管理器脚本</param>
    /// <param name="isLongNoteStart">是否是长音符的开始</param>
    /// <param name="isLongNoteEnd">是否是长音符的结尾</param>
    public void Initialize(KoreographyEvent evt ,int noteIndex ,STrackContorller  sTrackController,
        RythmGameContorller gameContorl ,bool isLongNoteStart ,bool isLongNoteEnd) 
    {
        //初始化
        trackedEvent = evt;
        strackController = sTrackController;
        gameController = gameContorl;
        isLongNote = isLongNoteStart;
        isLongNoteEnd = isLongNoteEnd;
        int spriteIndex= noteIndex;
        //精灵图集一共有18个前6个是短音符,中间6个是长音符,后面6个是长音符结尾
        if (isLongNote)
        {
            spriteIndex += 6;
        }
        else if (isLongNoteEnd)
        {
            spriteIndex += 12;
        }
        //精灵图的索引是从0开始的
        try
        {
            spriteRenderer.sprite = noteSprites[spriteIndex - 1];
        }
        catch
        {
            Debug.Log(spriteIndex);
        }
       
    }

    //音符Note对象返回对象池,需要重置
    public void ResetNote()
    {
        //讲两个控制者和自身的轨道事件置空即可
        trackedEvent = null;
        strackController = null;
        gameController = null;
    }

    //音符返回对象池
    private void ReturnPool()
    {
   
        //调用游戏管理器脚本呢中的入池方法
        gameController.ReturnNotePooling(this);
        //重置Note对象
        ResetNote();
    }

    //击中音符也返回对象池
    public void OnHit()
    {
        ReturnPool();
    }

    //更新音符位置的方法
    private void UpdatePosition()
    {
        Vector3 position = strackController.TargetPosition;
        //-=  (样本点的位置差值) / 采样率  <等于时间> * 字符速度
        position.z -= (gameController.DelayedSampingTime - trackedEvent.StartSample) / (float)gameController .SamplingRate *gameController .noteSpeed ;
        transform.position = position;
    }

}


🎶(6 音符特效的制作


  • 击打特效

在这里插入图片描述

  • 按下特效

在这里插入图片描述

  • “”

在这里插入图片描述

在这里插入图片描述


🎶(7 音符预制体的逻辑


  • 于音轨管理器脚本中创建(STrackContorller)
 #region 特效预制体的创建
    //创建按下特效预制体
    private void CreateDownEffect()
    {
        //获取RythmGameControl脚本中 获取特效对象的方法(按下特效)
        GameObject downEffectGo = gameContorller.GetEffectObject(gameContorller.downEffectPool, gameContorller.downEffect);     
        //该特效出生的地点 = 目标位置
        downEffectGo.transform.position = targetEffectPosition.position;
    }

    //创建击打特效预制体
    private void CreateHitEffect()
    {
        //获取RythmGameControl脚本中 获取特效对象的方法(击中特效)
        GameObject hitEffectGo = gameContorller.GetEffectObject(gameContorller.downEffectPool , gameContorller.hitEffect);
        //该特效出生的地点 = 目标位置
        hitEffectGo.transform.position = targetEffectPosition.position;
    }

    //创建击长击打特效预制体
    private void CreateHitLongEffect()
    {
        //获取RythmGameControl脚本中 获取特效对象的方法(击中特效)
        GameObject hitEffectGo = gameContorller.GetEffectObject(gameContorller.longEffectPool, gameContorller.longHitEffect);
        //该特效出生的地点 = 目标位置
        hitEffectGo.transform.position = targetEffectPosition.position;
    }
    #endregion

🅰️


⭐【Unityc#专题篇】之c#进阶篇】

⭐【Unityc#专题篇】之c#核心篇】

⭐【Unityc#专题篇】之c#基础篇】

⭐【Unity-c#专题篇】之c#入门篇】

【Unityc#专题篇】—进阶章题单实践练习

⭐【Unityc#专题篇】—基础章题单实践练习

【Unityc#专题篇】—核心章题单实践练习


你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!


在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/520364.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring进阶系列丨第七篇】Spring框架新注解分类及详解

文章目录 一、Spring新注解1.1、Configuration注解1.1.1、定义一个类1.1.2、使用Configuration注解修饰类1.1.3、作用 1.2、Bean注解1.2.1、定义bean1.2.2、在主配置类中注册bean1.2.3、测试容器中是否有该bean1.2.4、注册bean的同时可以指定bean名称1.2.5、补充内容1.2.5.1、案…

初始Java篇(JavaSE基础语法)(6)(继承和多态)(上)

Java学习篇 个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 目录 继承篇 为什么需要继承&#xff1f; 继承概念 继承的语法 父类成员访问 super关键字 子类构造方法 super和this的比较 再谈…

柯桥外语机构商务英语学习,“五星级”酒店到底是five star还是five stars?这个千万别搞错!

“五星级酒店”的英语表达 关于酒店&#xff0c;大家都知道有星级之分&#xff1b;其中&#xff0c;最高级的酒店当属“五星级”了&#xff1b; 那么问题来了&#xff0c;这个“五星级”的英语&#xff0c;究竟是“five star”&#xff0c;还是“five stars”呢&#xff1f; 其…

11_Spring-IOC/DI

文章目录 SpringIOC控制反转&#xff08;存&#xff09;DI依赖注入&#xff08;取&#xff09;Spring的优点Spring的核心技术入门案例入门案例1入门案例2 注解配置类组件注册功能&#xff08;IOC&#xff09;类直接注册配置类中注册&#xff08;JavaConfig&#xff09; 组件注入…

Premiere Pro 2024:赋予创意翅膀,让你的视频飞翔 mac/win版

Premiere Pro 2024&#xff0c;作为Adobe旗下的旗舰视频编辑软件&#xff0c;自推出以来&#xff0c;一直在视频制作领域占据着重要的地位。随着技术的不断进步和创新&#xff0c;Premiere Pro 2024为用户带来了前所未有的编辑体验&#xff0c;重新定义了视频制作的标准。 Pre…

网络原理 - HTTP / HTTPS(5)——https协议

目录 一、HTTPS是什么 为什么要进行加密 二、“加密” 是什么 三、HTTPS的工作过程 &#xff08;1&#xff09;引入对称加密 对称密钥的特点&#xff1a; &#xff08;2&#xff09;引入非对称加密 非对称加密的特点&#xff1a; &#xff08;3&#xff09;中间人攻击…

【C++】STL--vector

目录 vector的使用 vector的定义 vector iterator的使用 vector空间增长问题 vector增删查改 vector深度剖析及模拟实现 vector核心接口模拟实现 使用memcpy拷贝问题 迭代器失效问题 vector的使用 vector的定义 C中&#xff0c;vector是一个模版&#xff0c;第一个参…

PHP数据类型

华子目录 数据类型PHP的八种数据类型基本数据类型&#xff0c;4类复合数据类型&#xff0c;2类特殊数据类型&#xff0c;2类 类型转换在PHP中有两种类型转换方式其他类型转bool类型其他类型转数值类型实例 类型判断获取和设定变量类型获取gettype(变量名)设置settype(变量名,类…

蓝桥杯单片机第十四届省赛模拟考试一

一、基本要求 使用大赛组委会提供的国信长天单片机竞赛实训平台&#xff0c;完成本试题的程序设计与调试。程序编写、调试完成后&#xff0c;选手需通过考试系统提交以准考证号命名的hex文件。不符合以上文件提交要求的作品将被评为零分或者被酌情扣分。 硬件设置&#xff1a; …

数组-二维数组

本笔记为47 数组-二维数组定义方式_哔哩哔哩_bilibili的学习笔记 二维数组 定义方式 注&#xff1a; 常用第二种方式定义&#xff0c;原因&#xff1a;第二种方式更清晰列数可以省行数不可省 &#xff0c;详见上述第四种定义方式 示例&#xff1a; 二维数组 数组名 作用&am…

CSS层叠样式表学习(引入方式)

&#xff08;大家好&#xff0c;今天我们将继续来学习CSS引入方式的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&#xff09; 五、CSS的三种样式表 5.1 CSS的三种样式表 按照CSS样式书写的位置(或者引入方式)&#xff0c;CSS样式表可…

笔记-Building Apps with the ABAP RESTful Application Programming Model-Week3

Week3 Unit 1: The Enhanced Business Scenario 本节介绍了将要练习的demo的业务场景,在前两周成果的基础上,也就是只读列表,也可以说是报表APP基础上启用了事务能力,也就是CURD以及自定义业务功能的能力,从创建基本的behavior definition,然后behavior definition proj…

基于GD32的简易数字示波器(2)- 原理图设计

这期记录的是项目实战&#xff0c;做一个简易的数字示波器。 教程来源于嘉立创&#xff0c;202&#xff1a;简易数字示波器项目文档 语雀 下图为示波器的指标 具有选择交流耦合还是直流耦合功能、输入信号不衰减或衰减50倍 输入频率理论最大800KHz输入幅值&#xff08;不衰…

2024HW-->Wireshark攻击流量分析

在HW中&#xff0c;最离不开的&#xff0c;肯定是看监控了&#xff0c;那么就要去了解一些wireshark的基础用法以及攻击的流量&#xff01;&#xff01;&#xff01;&#xff01; 1.Wireshark的基本用法 比如人家面试官给你一段流量包&#xff0c;你要会用 1.分组详情 对于我…

9_springboot_shiro_jwt_多端认证鉴权_整合jwt

1. Shiro框架回顾 到目前为之&#xff0c;Shiro框架本身的知识点已经介绍完了。web环境下&#xff0c;整个框架从使用的角度我们需要关注的几个点&#xff1a; 要使用Shiro框架&#xff0c;就要创建核心部件securityManager 对象。 SpringBoot项目中&#xff0c;引入shiro-spr…

蓝凌OA单点登录实现方案:以统一身份管理提升效率与安全新举措

蓝凌OA的优势与挑战 在数字化浪潮的推动下&#xff0c;企业对于高效、安全的身份管理需求愈发迫切。蓝凌OA系统&#xff0c;以其出色的流程管理和协同办公能力&#xff0c;已经成为众多企业实现数字化转型的重要工具。然而&#xff0c;随着企业信息化建设的不断深入&#xff0…

什么时候外部依赖接口慢拖死应用?

A应用调用B应用&#xff0c;当B应用的接口响应耗时平均都在3000ms的时&#xff0c;如果当前A调用B的请求数达300/s 那么在3s内A应用在途的请求数 300 * 3 900 &#xff0c;按照servlet原理一个http的请求需要一个线程提供服务&#xff0c;即需要900个线程提供服务&#xff0c…

CSS面试题常用知识总结day03

大家好我是没钱的君子下流坯&#xff0c;用自己的话解释自己的知识 前端行业下坡路&#xff0c;甚至可说前端已死&#xff0c;我还想在前段行业在干下去&#xff0c;所以从新开始储备自己的知识。 从CSS——>Javascript——>VUE2——>Vuex、VueRouter、webpack——>…

聚能共创下一代智能终端操作系统 软通动力荣膺“OpenHarmony优秀贡献单位”

近日&#xff0c;由开放原子开源基金会指导&#xff0c;以“开源共享未来”为主题的OpenHarmony社区年会在北京成功举办。本次活动汇集OpenHarmony项目群共建单位及生态伙伴等多方力量&#xff0c;旨在对2023年度OpenHarmony年度开源事业全面总结的同时&#xff0c;吸引更多伙伴…

【Java EE】SpringBoot的创建与简单使用

文章目录 &#x1f340;环境准备&#x1f333;Maven&#x1f332;SpringBoot是什么&#x1f384;Spring Boot 项目创建&#x1f338;使用Idea创建&#x1f338;创建SpringBoot项⽬&#x1f338;SpringBoot项目的运行 ⭕总结 &#x1f340;环境准备 如果你的IDEA是专业版&#…