【Unity3D】创建自定义字体

前置准备

在这里插入图片描述
如图所示,项目工程中需要用文件夹存储0-9的Sprite图片。

使用流程

在这里插入图片描述

直接右键存放图片的文件夹,选择【创建自定义字体】,之后会在脚本定义的FontOutputPath中生成材质球和字体。

源码

using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;public class CustomFontTool
{static string FontOutputPath = "Assets/CustomResources/Font";const int ATLAS_MAX_SIZE = 256;public const int BORDER = 2;[MenuItem("Assets/工具/UI/创建自定义字体", false, 100)]static private void CreateCustomFont(){var assetGUIDs = Selection.assetGUIDs;if (assetGUIDs.Length <= 0){Debug.LogError("没有选择文件夹");return;}string folderPath = AssetDatabase.GUIDToAssetPath(assetGUIDs[0]);string absPath = IOUtils.GetAbsPath(Application.dataPath + "/../" + folderPath);Debug.Log("路径:" + folderPath);string folderName = IOUtils.GetFolderName(absPath);var outputDir = FontOutputPath + "/" + folderName;IOUtils.CreateFolder(outputDir);string fontPath = outputDir + "/" + folderName + ".fontsettings";IOUtils.DeleteFile(fontPath);string saveFile = absPath + "/" + folderName + ".png";IOUtils.DeleteFile(saveFile);string matPath = outputDir + "/" + folderName + ".mat";IOUtils.DeleteFile(matPath);AssetDatabase.Refresh();string[] files = IOUtils.GetFiles(absPath,"png");Dictionary<string, Dictionary<string, int>> texInfos = new Dictionary<string, Dictionary<string, int>>();Texture2D[] textures = new Texture2D[files.Length];string[] textureNames = new string[textures.Length];for (int i=0;i<files.Length;i++){string file = files[i];string localPath = IOUtils.SubPath(file, IOUtils.GetAbsPath(Application.dataPath + "/../"));Sprite sprite = AssetDatabase.LoadAssetAtPath(localPath, typeof(Sprite)) as Sprite;string texName = sprite.texture.name;textureNames[i] = texName;textures[i] = Clamp(sprite.texture);texInfos.Add(texName, getTexInfo(sprite,texName));}Texture2D atlas = new Texture2D(ATLAS_MAX_SIZE, ATLAS_MAX_SIZE);Rect[] rects = atlas.PackTextures(textures, 0, ATLAS_MAX_SIZE, false);if(rects.Length <= 0){Debug.LogErrorFormat("打包文件夹图集失败[{0}]", folderPath);return;}string saveLocalFile = IOUtils.SubPath(saveFile, IOUtils.GetAbsPath(Application.dataPath + "/../"));File.WriteAllBytes(saveFile, atlas.EncodeToPNG());AssetDatabase.ImportAsset(saveLocalFile, ImportAssetOptions.ForceUpdate);TextureImporter importer = AssetImporter.GetAtPath(saveLocalFile) as TextureImporter;importer.textureType = TextureImporterType.Sprite;importer.spriteImportMode = SpriteImportMode.Multiple;importer.spritePixelsPerUnit = 100;importer.alphaIsTransparency = true;SpriteMetaData[] metaDatas = new SpriteMetaData[textureNames.Length];for (int i = 0; i < metaDatas.Length; i++){string texName = textureNames[i];SpriteMetaData metaData = new SpriteMetaData();metaData.name = texName;Rect rect = rects[i];if (rects.Length > 1){Dictionary<string, int> infos = null;bool exist = texInfos.TryGetValue(texName, out infos);int left = 0, top = 0, right = 0, bottom = 0;if(exist && infos.ContainsKey("l")) {left = infos["l"];}if (exist && infos.ContainsKey("t")){top = infos["t"];}if (exist && infos.ContainsKey("r")){right = infos["r"];}if (exist && infos.ContainsKey("b")){bottom = infos["b"];}float x = (rect.xMin * atlas.width + BORDER) + left;float y = (rect.yMin * atlas.height + BORDER) + bottom;float w = (rect.width * atlas.width - BORDER * 2) -left + right;float h = (rect.height * atlas.height - BORDER * 2) -bottom + top;metaData.rect = new Rect(x,y,w,h);}else{metaData.rect = new Rect(rect.xMin * atlas.width, rect.yMin * atlas.height, rect.width * atlas.width, rect.height * atlas.height);}metaData.border = new Vector4();metaData.pivot = new Vector2(0.5f, 0.5f);metaDatas[i] = metaData;}importer.spritesheet = metaDatas;importer.maxTextureSize = ATLAS_MAX_SIZE;importer.isReadable = false;importer.mipmapEnabled = false;importer.textureCompression = TextureImporterCompression.Compressed;//if (format == TextureImporterFormat.RGBA32)//{//    importer.SetPlatformTextureSettings(BuildTarget.Android.ToString(), 2048, format, 100, false);//    if (AssetPathHelper.GetBuildTarget() == BuildTarget.iOS)//    {`//        TextureImporterPlatformSettings importerSettings_IOS = new TextureImporterPlatformSettings();//        importerSettings_IOS.overridden = true;//        importerSettings_IOS.name = "iPhone";//        importerSettings_IOS.textureCompression = TextureImporterCompression.Uncompressed;//        importerSettings_IOS.maxTextureSize = 2048;//        importerSettings_IOS.format = format;//        importer.SetPlatformTextureSettings(importerSettings_IOS);//    }//}AssetDatabase.ImportAsset(saveLocalFile, ImportAssetOptions.ForceUpdate);float texWidth = atlas.width;float texHeight = atlas.height;List<CharacterInfo> datas = new List<CharacterInfo>();for (int i=0;i<textures.Length;i++){string texName = textureNames[i];Rect rect = metaDatas[i].rect;CharacterInfo data = new CharacterInfo();data.index = texInfos[texName]["ascii"];data.advance = (int)rect.width;data.glyphWidth = (int)rect.width;data.glyphHeight = (int)-rect.height;data.uvTopLeft = new Vector2(rect.min.x / texWidth, rect.min.y / texHeight);data.uvTopRight = new Vector2(rect.max.x / texWidth, rect.min.y / texHeight);data.uvBottomLeft = new Vector2(rect.min.x / texWidth, rect.max.y / texHeight);data.uvBottomRight = new Vector2(rect.max.x / texWidth, rect.max.y / texHeight);data.minX = 0;data.maxX = (int)rect.width;data.minY = (int)(rect.height * 0.5f);data.maxY = (int)(-rect.height * 0.5f);datas.Add(data);}Font customFont = new Font();customFont.characterInfo = datas.ToArray();Material material = new Material(Shader.Find("UI/Default"));material.mainTexture = AssetDatabase.LoadAssetAtPath(saveLocalFile, typeof(Texture)) as Texture;AssetDatabase.CreateAsset(material, matPath);AssetDatabase.ImportAsset(matPath, ImportAssetOptions.ForceUpdate);customFont.material = AssetDatabase.LoadAssetAtPath<Material>(matPath) as Material;AssetDatabase.CreateAsset(customFont, fontPath);AssetDatabase.ImportAsset(fontPath, ImportAssetOptions.ForceUpdate);}static int getAscii(string text){if(text == "space"){return 32;}else if(text == "colon"){return 58;}else if(text == "forwardSlash"){return 47;}else if(text == "dot"){return 46;}else if(text.Length > 1){return -1;}else{return text[0];}}static Dictionary<string, int> getTexInfo(Sprite sprite, string texName){Vector4 a = sprite.border;Dictionary<string, int> texInfos = new Dictionary<string, int>();string[] nameInfos = texName.Split("_"[0]);if (nameInfos.Length > 2){throw new Exception(string.Format("图片命名格式异常[{0}](ascii_l = x, t = x, r = x, b = x)", texName));}string asciiInfo = nameInfos[0];int ascii = getAscii(asciiInfo);if (ascii == -1){throw new Exception(string.Format("无法识别的ascii映射[{0}][{1}]", asciiInfo, texName));}texInfos.Add("ascii", ascii);if (nameInfos.Length == 2){string[] offsetInfos = nameInfos[1].Split(","[0]);foreach (var v in offsetInfos){string[] dirInfos = v.Split("="[0]);if (dirInfos.Length != 2){throw new Exception(string.Format("图片命名格式异常[{0}][{1}]", v, texName));}string key = dirInfos[0];if (!key.Equals("l") && !key.Equals("t") && !key.Equals("r") && !key.Equals("b")){throw new Exception(string.Format("图片命名格式异常[{0}][{1}]", v, texName));}int value;bool ok = int.TryParse(dirInfos[1], out value);if (!ok){throw new Exception(string.Format("图片命名格式异常[{0}][{1}]", v, texName));}texInfos.Add(key, value);}}return texInfos;}public static Texture2D Clamp(Texture2D sourceTexture){int sourceWidth = sourceTexture.width;int sourceHeight = sourceTexture.height;Color32[] sourcePixels = sourceTexture.GetPixels32();int targetWidth = sourceWidth + BORDER * 2;int targetHeight = sourceHeight + BORDER * 2;Color32[] targetPixels = new Color32[targetWidth * targetHeight];Texture2D targetTexture = new Texture2D(targetWidth, targetHeight);for (int i = 0; i < sourceHeight; i++){for (int j = 0; j < sourceWidth; j++){targetPixels[(i + BORDER) * targetWidth + (j + BORDER)] = sourcePixels[i * sourceWidth + j];}}//左边缘for (int v = 0; v < sourceHeight; v++){for (int k = 0; k < BORDER; k++){targetPixels[(v + BORDER) * targetWidth + k] = sourcePixels[v * sourceWidth];}}//右边缘for (int v = 0; v < sourceHeight; v++){for (int k = 0; k < BORDER; k++){targetPixels[(v + BORDER) * targetWidth + (sourceWidth + BORDER + k)] = sourcePixels[v * sourceWidth + sourceWidth - 1];}}//上边缘for (int h = 0; h < sourceWidth; h++){for (int k = 0; k < BORDER; k++){targetPixels[(sourceHeight + BORDER + k) * targetWidth + BORDER + h] = sourcePixels[(sourceHeight - 1) * sourceWidth + h];}}//下边缘for (int h = 0; h < sourceWidth; h++){for (int k = 0; k < BORDER; k++){targetPixels[k * targetWidth + BORDER + h] = sourcePixels[h];}}targetTexture.SetPixels32(targetPixels);targetTexture.Apply();return targetTexture;}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

logminer挖掘日志归档查找问题

--根据发生问题时间点查找归档文件 select first_time,NAME from gv$archived_log where first_time>2016-03-15 17:00:00 and first_time<2016-03-15 21:00:00; 2016-03-15 17:23:55 ARCH/jxdb/archivelog/2016_03_15/thread_1_seq_41588.4060.906577337 2016-03-15 17:…

电商项目高级篇06-缓存

电商项目高级篇06-缓存 1、docker下启动redis2、项目整合redis 缓存 流程图&#xff1a; data cache.load(id);//从缓存加载数据 If(data null){ data db.load(id);//从数据库加载数据 cache.put(id,data);//保存到 cache 中 } return data;在我们的单体项目中可以用Map作…

如何使用GCC手动编译stm32程序

如何不使用任何IDE&#xff08;集成开发环境&#xff09;编译stm32程序? 集成开发环境将编辑器、编译器、链接器、调试器等开发工具集成在一个统一的软件中&#xff0c;使得开发人员可以更加简单、高效地完成软件开发过程。如果我们不使用KEIL,IAR等集成开发环境&#xff0c;…

一个专为云原生环境设计的高性能分布式文件系统

大家好&#xff0c;今天给大家分享一款开源创新的分布式 POSIX 文件系统JuiceFS&#xff0c;旨在解决海量云存储与各类应用平台&#xff08;如大数据、机器学习、人工智能等&#xff09;之间高效对接的问题。 项目介绍 JuiceFS 是一款面向云原生设计的高性能分布式文件系统&am…

Vue-TreeSelect组件最下级隐藏No sub-options

问题&#xff1a;最下级没有数据的话&#xff0c;去除No sub-options信息 为什么没下级&#xff0c;会展示这个&#xff1f; 整个树形结构数据都是由后端构造好返回给前端的。默认子类没数据的话&#xff0c;children是一个空数组。也就是因为这最下级的空数组&#xff0c;导致…

k8s集群增加nfs-subdir-external-provisioner存储类

文章目录 前言一、版本信息二、本机安装nfs组件包三、下载nfs-subdir-external-provisioner配置文件并进行配置1.下载文件2.修改配置 三、进行部署备注&#xff1a;关于镜像无法拉取问题的处理 前言 手里的一台服务器搭建一个单点的k8s集群&#xff0c;然后在本机上使用nfs-su…

C语言数据结构-链表

C语言数据结构-链表 1.单链表1.1概念与结构1.2结点3.2 链表性质1.3链表的打印1.4实现单链表1.4.1 插入1.4.2删除1.4.3查找1.4.4在指定位置之前插入或删除1.4.5在指定位置之后插入或删除1.4.6删除指定位置1.4.7销毁链表 2.链表的分类3.双向链表3.1实现双向链表3.1.1尾插3.1.2头插…

【SpringCloud详细教程】-04-服务容错--Sentinel

精品专题&#xff1a; 01.《C语言从不挂科到高绩点》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482 02. 《SpringBoot详细教程》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12789841.html?spm1001.20…

【Python中while循环】

一、深拷贝、浅拷贝 1、需求 1&#xff09;拷贝原列表产生一个新列表 2&#xff09;想让两个列表完全独立开&#xff08;针对改操作&#xff0c;读的操作不改变&#xff09; 要满足上述的条件&#xff0c;只能使用深拷贝 2、如何拷贝列表 1&#xff09;直接赋值 # 定义一个…

在 Mac(ARM 架构)上安装 JDK 8 环境

文章目录 步骤 1&#xff1a;检查系统版本步骤 2&#xff1a;下载支持 ARM 的 JDK 8步骤 3&#xff1a;安装 JDK步骤 4&#xff1a;配置环境变量步骤 5&#xff1a;验证安装步骤 6&#xff1a;注意事项步骤7&#xff1a;查看Java的安装路径 在 Mac&#xff08;ARM 架构&#xf…

对比C++,Rust在内存安全上做的努力

简介 近年来&#xff0c;越来越多的组织表示&#xff0c;如果新项目在技术选型时需要使用系统级开发语言&#xff0c;那么不要选择使用C/C这种内存不安全的系统语言&#xff0c;推荐使用内存安全的Rust作为替代。 谷歌也声称&#xff0c;Android 的安全漏洞&#xff0c;从 20…

小程序基础:流程。

一、前言 该文章是个人的学习笔记&#xff0c;是学习了黑马程序的微信小程序开发视频后写的笔记&#xff0c;将老师所讲的内容重点汇总起来&#xff0c;目的是为了方便自己日后回顾&#xff0c;同时也方便大家学习和了解小程序的开发 想要入门小程序&#xff0c;那么看这一篇文…

【漏洞复现】CVE-2020-13925

漏洞信息 NVD - CVE-2020-13925 Similar to CVE-2020-1956, Kylin has one more restful API which concatenates the API inputs into OS commands and then executes them on the server; while the reported API misses necessary input validation, which causes the hac…

数据结构 (11)串的基本概念

一、串的定义 1.串是由一个或者多个字符组成的有限序列&#xff0c;一般记为&#xff1a;sa1a2…an&#xff08;n≥0&#xff09;。其中&#xff0c;s是串的名称&#xff0c;用单括号括起来的字符序列是串的值&#xff1b;ai&#xff08;1≤i≤n&#xff09;可以是字母、数字或…

LLM PPT Translator

LLM PPT Translator 引言Github 地址UI PreviewTranslated Result Samples 引言 周末开发了1个PowerPoint文档翻译工具&#xff0c;上传PowerPoint文档&#xff0c;指定想翻译的目标语言&#xff0c;通过LLM的能力将文档翻译成目标语言的文档。 Github 地址 https://github.…

Python数据分析实例五、US 大选捐款数据分析

美国联邦选举委员会 (FEC) 公布了对政治竞选活动的贡献数据。这包括投稿人姓名、职业和雇主、地址和投款金额。2012 年美国总统大选的贡献数据以单个 150 MB 的 CSV 文件P00000001-ALL.csv形式提供,该文件可以通过以下pandas.read_csv加载: import pandas as pdfec = pd.r…

3.http模块

文章目录 [TOC](文章目录) 1、什么是http模块&#xff1f;1.1.作用1.2.服务器相关概念1.2.创建基本的web服务器-实现的核心步骤和代码1.2.1导入http模块1.2.2.req 请求对象 1.3.根据不同的url地址 响应不同的html内容1.4.案例-clock时钟的web服务器 1、什么是http模块&#xff…

【Nginx】核心概念与安装配置解释

文章目录 1. 概述2. 核心概念2.1.Http服务器2.2.反向代理2.3. 负载均衡 3. 安装与配置3.1.安装3.2.配置文件解释3.2.1.全局配置块3.2.2.HTTP 配置块3.2.3.Server 块3.2.4.Location 块3.2.5.upstream3.2.6. mine.type文件 3.3.多虚拟主机配置 4. 总结 1. 概述 Nginx是我们常用的…

uniapp开发微信小程序笔记8-uniapp使用vant框架

前言&#xff1a;其实用uni-app开发微信小程序的首选不应该是vant&#xff0c;因为vant没有专门给uni-app设置专栏&#xff0c;可以看到目前Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本&#xff0c;并由社区团队维护 React 版本和支付宝小程序版本。 但是我之前维…

IDEA2024创建一个spingboot项目

以下是创建一个基本的 Spring Boot 项目的步骤和示例&#xff1a; 初始化一个springboot工程其实有许多方法&#xff0c;笔者这里挑了一个最快捷的方式搭建一个项目。我们直接通过官方平台&#xff08;start.spring.io&#xff09;进行配置&#xff0c;然后下载压缩包就可以获取…