Unity 动态打图集并完成小Demo的实现

2023-11-07

为什么要动态打图集

比如在英雄联盟中的选择英雄界面,有很多的图标供我们选择,而我们进入游戏之后只需要选择的那两三个图标而已,这是如果我们将所有图标都打成图集,就造成内存浪费,因为我们只需要两三个而已,那么我们有什么办法让我们只将要用到的图标进行打图集,其他的不打进图集吗?有的,那就是动态打图集。

效果如下
点击下面三个框中的一个,再点击上面十个图标中的一个,就完成了选择图标,一个个选。
在这里插入图片描述

如何进行动态打图集

打图集肯定要有打图集的算法,这里提供了打图集的算法供我们使用,去下载就好了。

图集分块算法地址:https://github.com/DaVikingCode/UnityRuntimeSpriteSheetsGenerator/tree/master/Assets/RuntimeSpriteSheetsGenerator/Scripts

下载AssetPacker文件和RectanglePacking文件就可以了,总共有6个C#脚本,将它拖入到Unity中。

有了上面的打图集算法,我们写个生成图集的类。新建一个名为AssetPackerMgr的空物体,将AssetPackerMgr .cs挂载上去。

using System;
using System.Collections;
using System.Collections.Generic;
using DaVikingCode.AssetPacker;
using UnityEngine;

public class AssetPackerMgr : MonoBehaviour
{
    public static AssetPackerMgr Instance { get; private set; }
    private Dictionary<string,AssetPacker> _packers = new Dictionary<string, AssetPacker>();

    private void Awake()
    {
        //这样写单例是因为避免存在两个AssetPackerMgr,比如跳到下个场景再跳回来的时候。
        if (Instance == null)
        {
            Instance = this;
            GameObject.DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    /// <summary>
    /// 生成新图集的方法
    /// </summary>
    /// <param name="altasName">图集名</param>
    /// <param name="paths">路径</param>
    /// <param name="complete">打完图集后的回调</param>
    public void GentatorNewAltas(string altasName,Dictionary<string,string> paths,Action complete = null)
    {
        if(paths == null)
            return;
        
        AssetPacker packer = new GameObject(altasName).AddComponent<AssetPacker>();
        packer.transform.SetParent(transform);
        packer.cacheName = altasName;
        foreach (KeyValuePair<string,string> path in paths)
        {
            packer.AddTextureToPack(path.Value,path.Key);
        }
        packer.Process();
        //打完图集后的回调方法,即为异步加载场景
        packer.OnProcessCompleted.AddListener(() =>
        {
            if (complete != null)
                complete();
        });
        
        _packers.Add(altasName,packer);
    }

    /// <summary>
    /// 获取AssetPacker
    /// </summary>
    /// <param name="altasName"></param>
    /// <returns></returns>
    public AssetPacker GetAltas(string altasName)
    {
        if (_packers.ContainsKey(altasName))
        {
            return _packers[altasName];
        }
        else
        {
            Debug.LogError("can not find altas name is "+altasName);
            return null;
        }
    }

    /// <summary>
    /// 清除altasName所对应的AssetPacker
    /// </summary>
    /// <param name="altasName"></param>
    public void ClearAltas(string altasName)
    {
        if (_packers.ContainsKey(altasName))
        {
            AssetPacker packer = _packers[altasName];
            _packers.Remove(altasName);
            Destroy(packer.gameObject);
        }
        else
        {
            Debug.LogError("can not remove altas,because it can not find,name is"+altasName);
            return;
        }
    }
}

在这里插入图片描述
图片中的1~10表示的是上面那10个小图标,打图集的话,肯定要知道图片路径的,所以我定义 了一个图片路径的类。

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

public class RuntimeAltasItem : MonoBehaviour
{
    public string Path;
}

挂载在这10个图标上。

我这里写个编辑器的扩展方法,来获取这十个图标的路径,因为编辑器下有获取路径的API。

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

public class SpritePathHelper : MonoBehaviour
{
   
   [MenuItem("GameObject/SpritePathHelper",false,0)]
   private static void SetPath()
   {
      foreach (GameObject go in Selection.gameObjects)
      {
         foreach (Transform trans in go.transform)
         {
            if(trans.GetComponent<Image>() == null)
               continue;

            Sprite sprite = trans.GetComponent<Image>().sprite;
            string path = AssetDatabase.GetAssetPath(sprite);
            //Application.dataPath后面包含Assets,path前面也包含Assets,组合后重复了,所以用Substring(6)从Assets之后取值
            path = Application.dataPath + path.Substring(6);
            RuntimeAltasItem item = trans.GetComponent<RuntimeAltasItem>();
            if (item == null)
               item = trans.gameObject.AddComponent<RuntimeAltasItem>();

            item.Path = path;
         }
      }
   }
}

我们选中SelectView,然后点击GameObject/SpritePathHelper就完成了获取图片路径并赋值了。

SelectView上挂载一个同名脚本,用来给每个图标添加监听事件,点击后就执行委托事件。

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

public class SelectView : MonoBehaviour
{
    private Action<Sprite, string> _onSelected;
    
    // Start is called before the first frame update
    void Start()
    {
        foreach (var child in GetComponentsInChildren<Button>())
        {
            child.onClick.AddListener(() =>
            {
                Sprite sprite = child.GetComponent<Image>().sprite;
                RuntimeAltasItem item = child.GetComponent<RuntimeAltasItem>();

                if (_onSelected != null)
                    _onSelected(sprite, item.Path);
            });
        }
    }

    /// <summary>
    /// 提供一个添加委托的方法
    /// </summary>
    /// <param name="selected"></param>
    public void AddSelectedListener(Action<Sprite, string> selected)
    {
        _onSelected = selected;
    }
}

新建一个ShowItem.cs,后面会通过代码添加该脚本到Icon1,Icon2,Icon3的。

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

public class ShowItem : MonoBehaviour
{
    public ShowName ID { get; private set; }
    private Image _image;
    private RuntimeAltasItem _altasItem;

    /// <summary>
    /// 初始化数据
    /// </summary>
    /// <param name="id"></param>
    public void Init(ShowName id)
    {
        ID = id;
        _image = GetComponent<Image>();
        _altasItem = GetComponent<RuntimeAltasItem>();
    }

    /// <summary>
    /// 设置图片
    /// </summary>
    /// <param name="sprite"></param>
    public void SetSprite(Sprite sprite)
    {
        _image.sprite = sprite;
    }

    /// <summary>
    /// 给Button添加点击事件
    /// </summary>
    /// <param name="selected"></param>
    public void AddListener(Action selected)
    {
        gameObject.GetComponent<Button>().onClick.AddListener(()=>selected());
    }

    /// <summary>
    /// 返回ID和图片路径
    /// </summary>
    /// <returns></returns>
    public KeyValuePair<string, string> GetData()
    {
        return new KeyValuePair<string, string>(ID.ToString(),_altasItem.Path);
    }
}

public enum ShowName
{
    ICON_1,
    ICON_2,
    ICON_3,
}

新建一个SelectShowView 挂载到Show上。

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

public class SelectShowView : MonoBehaviour
{
    private ShowItem _selectedItem;
    private RuntimeAltasItem _altasItem;
    
    // Start is called before the first frame update
    void Start()
    {
        ShowName id = ShowName.ICON_1;
        foreach (Transform trans in transform)
        {
            RuntimeAltasItem altasItem = trans.gameObject.AddComponent<RuntimeAltasItem>();
            ShowItem item =trans.gameObject.AddComponent<ShowItem>();
            
            item.Init(id);
            id++;
            
            item.AddListener(() =>
            {
                _selectedItem = item;
                _altasItem = altasItem;
            });
        }
    }

    public void SetShowItem(Sprite sprite,string path)
    {
        _selectedItem.SetSprite(sprite);
        _altasItem.Path = path;
    }

    /// <summary>
    /// 返回存要显示的图片的ID和图片路径的字典
    /// </summary>
    /// <returns></returns>
    public Dictionary<string,string> GetPaths()
    {
        //存要显示的图片的ID和图片路径的字典
        Dictionary<string,string> temp = new Dictionary<string, string>();
        KeyValuePair<string, string> tempPair;
        foreach (ShowItem item in GetComponentsInChildren<ShowItem>())
        {
            tempPair = item.GetData();
            temp.Add(tempPair.Key,tempPair.Value);
        }
        return temp;
    }
}

新建一个名为Complete的Button,添加SelectedComplete .cs脚本,当选择完图标的时候,可以执行异步加载场景。

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

public class SelectedComplete : MonoBehaviour
{
    public void Init(Func<Dictionary<string,string>> getPaths,LoadingView loadingView)
    {
        GetComponent<Button>().onClick.AddListener(() =>
        {
            loadingView.SetActiveState(true);
            AssetPackerMgr.Instance.GentatorNewAltas("Test",getPaths(),()=>loadingView.SwitchScene(SceneName.Game.ToString()));
        });
    }
}

public enum SceneName
{
    SelectView,
    Game
}

新建一个ShowView.cs,挂载在Canvas上

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

public class ShowView : MonoBehaviour
{
    private SelectShowView _selectShowView;
    
    void Start()
    {
        GetComponentInChildren<SelectView>().AddSelectedListener(SetShowItem);
        _selectShowView = GetComponentInChildren<SelectShowView>();
        GetComponentInChildren<SelectedComplete>().Init(()=>
            _selectShowView.GetPaths(),
            GetComponentInChildren<LoadingView>(true));
    }

    /// <summary>
    /// 设置将上面选择的图标显示在下面的Image上
    /// </summary>
    /// <param name="sprite"></param>
    /// <param name="path"></param>
    private void SetShowItem(Sprite sprite,string path)
    {
        if(_selectShowView == null)
            return;
        
        _selectShowView.SetShowItem(sprite,path);
    }
}

新建一个名为Loading的Image,设置成纯色的全屏背景充当异步加载的过度背景,上面添加LoadingView .cs,在Loading下面新建一个Text子物体,用于制作异步加载的过渡动画。Loading先设置隐藏。

using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class LoadingView : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GetComponentInChildren<Text>().DOText("Loading...", 3).SetLoops(-1, LoopType.Restart);
    }

    /// <summary>
    /// 设置加载界面的隐藏显示
    /// </summary>
    /// <param name="isShow"></param>
    public void SetActiveState(bool isShow)
    {
        gameObject.SetActive(isShow);
    }

    /// <summary>
    /// 异步加载场景
    /// </summary>
    /// <param name="sceneName">需要加载的场景</param>
    public void SwitchScene(string sceneName)
    {
        StartCoroutine(LoadScene(sceneName));
    }

    private IEnumerator LoadScene(string scenceName)
    {
        AsyncOperation async = SceneManager.LoadSceneAsync(scenceName);
        async.allowSceneActivation = false;

        while (!async.isDone)
        {
            if (async.progress >= 0.9f)
            {
                yield return new WaitForSeconds(2);
                async.allowSceneActivation = true;//为true的时候才会跳转场景
            }
            
            yield return new WaitForSeconds(0.5f);
        }
    }
}

上面的代码中的文本动画用到了Dotween插件,可自行去下载,或者可以自己手写一个简单的过渡动画也可以。

在这里插入图片描述
以上就是动态打图集并演示的过程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity 动态打图集并完成小Demo的实现 的相关文章

  • Unity中loading页加载的实现

    首先创建一个Global cs 使用单例用于存储场景的名字 便于后续脚本的调用 此脚本不必挂载在游戏物体上 using UnityEngine using System Collections public class Global Mon
  • 【Unity&C#&随机数】随机数

    一个简单的随机数获得 0或1 使用了这样的代码 想要获得0或者1 if Input anyKeyDown float i 1 if i 1 i Random Range 0 Rang i i lt 0 5 0 1 Debug Log Cou
  • unity网络资源导入

    1 找到需要导入的文件 这里导入fbx格式 2 打开unity界面 在Asset目录下创建文件夹FBX 将需要导入的fbx预制体或整个文件夹拖入创建的FBX文件夹下 3 选中需要的fbx预制体并拖至场景中 4 双击定位到当前物体 5 找到需
  • Unity 分块延迟渲染01 (TBDR)

    现代移动端图形体系结构的概述 现代SoC通常会同时集成CPU和GPU CPU被用于处理需要低内存延迟的序列 大量分支的数据集 其晶体管用于流控制和数据缓存 GPU为处理大型 未分支的数据集 如3D渲染 晶体管专用于寄存器和算术逻辑单元 而不
  • Unity 粒子特效、材质发光 HDR ShaderGraph图文教程[完成lit发光设置]

    效果如图 准备工作 在hdr模式下 关闭Directional Light 相机设置 移动球挂一个点光源作为子节点 设置自行调节 0 创建移动球的材质及shader shader gt 在Project Create Shader Grap
  • Unity Shader入门精要第七章 基础纹理之遮罩纹理

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一 实践 参考 前言 遮罩纹理 mask texture 是本章要介绍的最后一种纹理 它非常有用 在很多商业游戏中 都可以见到它的身影 那么什么是遮罩呢 简单来讲 遮罩允许我们
  • Unity动画系统详解

    目录 动画编辑器 编辑器面板 动画复用 前言 人形重定向动画 Humanoid 通用动画 Generic 旧版本动画 Legacy 动画控制器 系统状态 切换条件 状态机脚本 IK动画 反向动力学 BlendTree 混合树 Animato
  • Unity3d 插件 系列——DoTweenPro介绍(图文详细+案例)

    Unity3d 插件 系列 DoTweenPro介绍 图文详细 案例 前言 一 DoTweenPro简介 二 DoTweenPro安装 三 DoTweenPro主要组件 1 DoTweenAnimation 2 DoTweenPath 3
  • Unity中UI框架的使用1-添加面板、显示Loading页面

    其中BasePanel和Canvas都是挂在面板的预制物上的 1 导入我们的UI框架 本篇文章中有用的是两个UIPanelType NUIManager和NBasePanel 会放在文章最后供大家使用 2 先将我们做好的Panel设置成预制
  • Unity之获取游戏物体对象或组件的几个方法

    文章目录 前言 通过物体名称获取对象 GameObject Find Transform Find 通过物体标签获取对象 GameObject FindWithTag GameObject FindGameObjectWithTag Gam
  • unity后台加密时间锁

    前言 在做一些项目的时候 有些不良甲方在给完项目后会有不给尾款的情况 之前都是加一些水印啥的 感觉不是很方便 第一不美观 第二如果甲方给完尾款后还得重新打包去水印 然后又做过一个本地的时间锁 等到时间 程序直接退出 但是感觉还是不方便 有时
  • unity工程崩溃资源找回

    1 Unity死机未保存场景 当你在Unity中编辑场景 突然死机时 可以在项目文件目录中找到Temp文件夹 双击文件夹 找到 Backupscenes文件夹 把后缀为 backup的文件后缀改为 unity 然后拖进Unity的Proje
  • unity实现鼠标右键控制视角

    主要实现的功能是相机跟随主角 鼠标右击移动后 相机的视角会旋转 思路 在主角里创建空的子物体 把相机绑在空物体上 通过旋转空物体来实现视角的旋转 要把相机调整到适当位置 代码如下 public float rotateSpeed 100 设
  • 【Unity步步升】监控与检测物体的各种方案,如:射线、碰撞、挂载等...

    在制作AR模型数值控制方案的时候遇到了检测的问题 学习过程受益匪浅 故今天为大家整理带来一篇监控与检测物体的参考方案集合 目录 一 射线检测 二 物体存在检测 三 碰撞检测 一 射线检测 单射线检测 首先完成搭建场景如下图1 1 我这里用到
  • unity3d切换场景Application.LoadLevel(1)含义

    Application LoadLevel 1 场景ID
  • Unity万向节死锁解决方案(2023/12/4)

    1 万向节死锁无法解决 这是因为它的特性就是如此 就像玻璃杯就是玻璃 这不可否认 别钻牛角尖昂 2 大多数情况下欧拉角足够用 例如 CF 摄像机不可能绕z轴旋转 x轴旋转也不会超过九十度 因为那样人物的腰子会被扭断 塔防游戏 保卫萝卜 吃鸡
  • 微信游戏如何开发

    中懿游游戏软件开发 微信游戏开发通常涉及使用微信小游戏平台进行开发 微信小游戏是一种在微信平台上运行的轻量级游戏 用户可以在微信中直接体验 无需下载安装 以下是在微信平台上开发小游戏的一般步骤 1 注册微信开发者账号 访问 微信开放平台 注
  • 游戏开发常见操作梳理之NPC任务系统

    多数游戏存在任务系统 接下来介绍通过NPC触发任务的游戏制作代码 using System Collections using System Collections Generic using UnityEngine
  • 游戏开发常见操作梳理之NPC药品商店系统(NGUI版)

    后续会出UGUI Json的版本 敬请期待 游戏开发中经常会出现药品商店 实际操作与武器商店类似 甚至根据实际情况可以简化设置 废话不多说 直接上代码 药品商店的源码 using System Collections using Syste
  • 游戏开发常用实践操作之按动任意键触发

    接下来一些笔记会对于一些大大小小的实践操作进行记录 希望对你有所帮助 在游戏中 我们经常会遇到一些按动任意键触发的操作 接下来展示核心代码 以下是对于Unity中的操作 使用的UI是NGUI 对于核心操作没有影响 你可以自己置换 void

随机推荐

  • Linux 中软件包的安装常用指令

    目录 apt 常用指令 yum 常用指令 apt 常用指令 apt 与 apt get 大部分参数通用 但也会有区别 执行 apt 命令时 需要使用 root 用户的身份执行命令 如果报错 无效的操作 那可以加个sudo 试试 更新软件源
  • KMP算法详解

    目录 一 KMP是什么 二 原理 1 思路 2 预处理 3 借助nxt实现字符串匹配 总结 一 KMP是什么 烤馍片KMP算法是一种改进的字符串匹配算法 由D E Knuth J H Morris和V R Pratt提出的 因此人们称它为克
  • labelme汉化的app.py完整代码

    由于之前做了一期labelme的教程 但是汉化部分的代码有误 于是在这里贴出完整的app py代码 coding utf 8 import functools import math import os import os path as
  • scrapy错误-[scrapy.core.scraper] ERROR: Spider error processing

    一 问题 就是我的callback没得回调函数 二 然后我查看源代码 发现 三 我把解析页数的函数名设置为 def parse self response 就没保错了 能运行成功 总结 在spider的 init py文件的源代码下 设置了
  • 什么是HTML? 看这一篇就够了(附带主流IDE推荐)

    1 HTML简介 1 1 HTML是什么 百度词条 HTML称为超文本标记语言 是一种标识性的语言 它包括一系列标签 通过这些标签可以将网络上的文档格式统一 使分散的Internet资源连接为一个逻辑整体 HTML文本是由HTML命令组成的
  • 第十九篇:处理僵尸进程的两种经典方法

    前言 如果父进程没有结束 而子进程终止了 那么在父进程调用 wait 函数回收这个子进程或者父进程终止以前 这个子进程将一直是僵尸进程 本文将提供两种方法处理这个问题 方法一 父进程回收法 wait函数将使其调用者阻塞 直到其某个子进程终止
  • 伺服电机的三种控制方式与三闭环控制

    项目 FPGA双电机主从快速稳定控制实现 第一章 伺服电机的三种控制方式与三闭环控制 伺服电机的三种控制方式与三闭环控制 项目 FPGA双电机主从快速稳定控制实现 前言 一 电机控制方式 二 电机三个闭环负反馈PID控制系统 三 三闭环位置
  • GLUE基准数据集介绍

    图1 整篇文章的思维导图 一 简介 自然语言处理 NLP 主要自然语言理解 NLU 和自然语言生成 NLG 为了让NLU任务发挥最大的作用 来自纽约大学 华盛顿大学等机构创建了一个多任务的自然语言理解基准和分析平台 也就是GLUE Gene
  • 完美解决dataframe添加列,并且指定列的位置

    需求是这样的 我需要从原始表中提取几列数据 分别填入税表的人员和收入表中 原始表中只有 姓名 身份证号码 年金领取额是有效数据 但是税务局的模板表中有一大堆莫名其妙的字段不需要填写 先把原始表定义一下 把身份证字符串一下 再把需要的人员 收
  • Spark整理

    文章目录 1 概述 1 1 Spark 和 Hadoop 组成 1 2 Spark 和 Hadoop 区别 2 Spark 运行架构 2 1 基础架构 2 2 Master Worker Standalone模式 2 3 Applicati
  • 如何给VScode安装clang(C language)插件

    前言 1 本篇经验专门为 使用VScode开发c语言项目的学生和工程师而写 2 安装了clang C language 插件的VScode编辑器 补全功能将更加智能 正文 首先你得先安装vscode软件 安装教程请参考下链接 对于本人就不费
  • STC15单片机——定时/计数器2、3、4

    STC15单片机拥有5个定时器 分别为定时器0 1 2 3 4 本文章将记录定时器2 3 4所使用的寄存器 以及注意事项 由于STC15单片机定时器的使用于传统51单片机类似 这里仅标出应用所需的j寄存器 以及对陌生位的相关说明 其他不作过
  • 2020年下一个创业风口是什么?

    提到风口 大家总是兴致勃勃 满心期待的看完一个风口项目后 剩下的不是去选择执行 而是继续问道 还有其它的风口项目吗 所以 在我看来 对于大多数人而言 风口就是继续追问 没完没了的问还有其它的吗 今年没有抓住风口 告诉自己 不能灰心 明年拜菩
  • 支持向量机(SVM)

    SVM简介 SVM Support Vector Machine 它是一种二分类模型 其基本模型定义为特征空间上的间隔最大的线性分类器 其学习策略便是间隔最大化 最终可转化为一个凸二次规划问题的求解 这里涉及了几个概念 二分类模型 线性分类
  • 去除百度推广等广告的插件神器

    给大家推荐一款去除百度推广的神器 包括右边 及右下角弹出的广告 1 搜索ADblock进入官网https adblockplus org 点击 安装到chrome 弹出提示框点击 添加扩展程序 2 重新打开网址 你会发现之前的广告都消失了
  • 微信小程序开发一个小型商城(四、商品列表)

    上一篇文章 微信小程序开发一个小型商城 三 商品分类设计 在从上一个界面跳转过来 会看到商品列表这个界面 如下图所示 页面分析 从上到下 分别是一个已经定义好的自定义组件 下面的综合 销量 也是一个自定义组件 下面商品的一个个的小框框就是一
  • postgresql安装配置和基本操作

    1 安装 linux上安装 最好是centos7 6或者7 8 参考官网 PGSQL的官方地址 PostgreSQL The world s most advanced open source database PGSQL的国内社区 Pos
  • 【ElasticSearch】查询报错JsonpMappingException

    ElasticSearch查询报错JsonpMappingException 具体报错信息如下 co elastic clients json JsonpMappingException Error deserializing co ela
  • ajax+同步+返回数据库,如何使AJAX同步

    异常是我需要从数据库中立即返回的数据 不过 我需要 连续代码 来等待Id被返回 最好的办法是不要让这种情况发生 而是要接受事件驱动的 基于浏览器和网络编程的异步性质 非常小的选项是强制ajax请求同步 目前 在jQuery 1 x中 您可以
  • Unity 动态打图集并完成小Demo的实现

    为什么要动态打图集 比如在英雄联盟中的选择英雄界面 有很多的图标供我们选择 而我们进入游戏之后只需要选择的那两三个图标而已 这是如果我们将所有图标都打成图集 就造成内存浪费 因为我们只需要两三个而已 那么我们有什么办法让我们只将要用到的图标