返回目录

第五章 颜色映射与职业动画

二       颜色组(Color Chart)

颜色组是保存许多颜色的一个容器,可以在Swapper中直接创建List<Color>或Color[]来表示一组颜色,但这既不利于职务分担也不利于编辑。所以,我们单独创建一个容器类ColorChart,用它来保存一组颜色,再添加必备方法,Swapper只需调用它的方法就可以了。

1        创建ColorChart.cs

为了便于编辑颜色,需要它继承自ScriptableObject。同时它还是个颜色的容器,我们让它成为迭代器,继承IEnumerable<Color>并添加索引器(Indexer)。


using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace DR.Book.SRPG_Dev.ColorPalette
{[Serializable][CreateAssetMenu(fileName = "New Color Chart.asset", menuName = "SRPG/Color Chart")]public class ColorChart : ScriptableObject, IEnumerable<Color>{[SerializeField]private Color[] m_Colors = new Color[] { };public Color this[int index]{get { return m_Colors[index]; }set { m_Colors[index] = value; }}public IEnumerator<Color> GetEnumerator(){foreach (Color color in m_Colors){yield return color;}}IEnumerator IEnumerable.GetEnumerator(){return m_Colors.GetEnumerator();}}
}


这样就可以在Create/SRPG/ColorChart菜单下创建它了,还能编辑我们的颜色,我们还需要动态改变它的颜色数量,所以添加count属性。需要注意的是,除非销毁对象,否则我们要让m_Colors不为null。


        /// <summary>/// 颜色数量/// </summary>public int count{get { return m_Colors.Length; }set{if (value < 0){value = 0;}if (m_Colors.Length != value){Array.Resize<Color>(ref m_Colors, value);}}}


其中,Array.Resize方法保证了在颜色数量发生改变时,保留原来的颜色。


再来我们添加一个整体设置颜色的方法SetColors(Color[])。

        /// <summary>/// 设置颜色/// </summary>/// <param name="colors"></param>public void SetColors(Color[] colors){if (colors == null){m_Colors = new Color[0];}else{m_Colors = new Color[colors.Length];Array.Copy(colors, m_Colors, colors.Length);}}

其中,由于直接赋值会变成Color[]的引用,作为容器这在多数情况是不可取的,所以我们使用Array.Copy方法来复制数组。


2        添加所需的方法

整个流程图其实是需要获取到一个转换颜色过后的Texture2D,所以我来建立这么一个尝试获取转换后的Texture2D的方法“public bool TryGetSwapTexture(Texture2DsrcTexture, ColorChart srcChart, out Texture2D swapTexture)”。

首先,要保证源不能为null。

        /// <summary>/// 尝试获取转换后的Texture2D/// </summary>/// <param name="srcTexture"></param>/// <param name="srcChart"></param>/// <param name="swappingTexture"></param>/// <returns></returns>public bool TryGetSwapTexture(Texture2D srcTexture, ColorChart srcChart, out Texture2D swapTexture){swapTexture = null;if (srcTexture == null || srcChart == null){return false;}// TODO 获取转换的Texture2Dreturn true;}

其次,获取素材颜色的工作Texture2D中已经有了,所以不用我们自己来写。如果Texture2D不可读的话,Unity会在Console面板中输出Error。

            Color[] colors = srcTexture.GetPixels();

再次,我们把其它流程再细分:

  • IndexOf(Color color):获取Color在Chart中的Index;
  • GetSwapColor(Color color,ColorChart srcChart):获取转换后颜色。

先来看关于查找Index的方法(IndexOf),这和一般的查找稍稍有不同。平时,我们直接判断是不是相等就可以了,但因为Unity的颜色存储,并不是使用255,255,255,255的方式存储,而是使用了一个0到1的近似值存储的,并不一定精确。在某些Texture2D中,直接判断相等是无法得到Index的。所以,我们要使用近似值来判断Color是否一致。Unity中已经有了判断近似值的方法,它在Mathf中。


        /// <summary>/// 获取颜色在表中Index,/// 由于Color并不是按255,255,255的整形方式存储,/// 所以采用近似值的方式判断是不是同一个颜色/// </summary>/// <param name="color"></param>/// <returns></returns>public int IndexOf(Color color){if (m_Colors != null){for (int i = 0; i < m_Colors.Length; i++){Color tmp = m_Colors[i];if (Mathf.Approximately(color.r, tmp.r)&& Mathf.Approximately(color.g, tmp.g)&& Mathf.Approximately(color.b, tmp.b)&& Mathf.Approximately(color.a, tmp.a)){return i;}}}return -1;}

Mathf.Approximately是用来判断非常小的近似值的,解决了我们的问题。然后我们根据这个Index来查找转换颜色。

        /// <summary>/// 获取在本表中的对应位置的颜色,如果没有找到,返回原颜色/// </summary>/// <param name="color"></param>/// <param name="srcChart"></param>/// <returns></returns>public Color GetSwapColor(Color color, ColorChart srcChart){if (srcChart == null){return color;}int index = srcChart.IndexOf(color);if (index == -1 || index >= m_Colors.Length){return color;}return m_Colors[index];}

最后,还剩下创建新的Texture2D并填充颜色了。这也是Texture2D中有的方法。

            // 和源相同的设置创建Texture2DTexture2D clone = new Texture2D(srcTexture.width, srcTexture.height){alphaIsTransparency = srcTexture.alphaIsTransparency,wrapMode = srcTexture.wrapMode,filterMode = srcTexture.filterMode,};// 填充转换后的颜色,并保存clone.SetPixels(colors);clone.Apply();

新创建的Texture2D一定要用调用Apply()方法保存,否则不会真正填充颜色。

完整的TryGetSwapTexture方法:

        /// <summary>/// 尝试获取转换后的Texture2D/// </summary>/// <param name="srcTexture"></param>/// <param name="srcChart"></param>/// <param name="swappingTexture"></param>/// <returns></returns>public bool TryGetSwapTexture(Texture2D srcTexture, ColorChart srcChart, out Texture2D swapTexture){swapTexture = null;if (srcTexture == null || srcChart == null){return false;}// 获取源图所有颜色,并转换颜色Color[] colors = srcTexture.GetPixels();for (int i = 0; i < colors.Length; i++){if (colors[i].a != 0){colors[i] = GetSwapColor(colors[i], srcChart);}                }// 和源相同的设置创建Texture2DTexture2D clone = new Texture2D(srcTexture.width, srcTexture.height){alphaIsTransparency = srcTexture.alphaIsTransparency,wrapMode = srcTexture.wrapMode,filterMode = srcTexture.filterMode,};// 填充转换后的颜色,并保存clone.SetPixels(colors);clone.Apply();swapTexture = clone;return true;}

SRPG游戏开发(十)第五章 颜色映射与职业动画 - 二 颜色组(Color Chart)相关推荐

  1. SRPG游戏开发(九)第五章 颜色映射与职业动画 - 一 颜色映射流程(Flow Chart)

    返回目录 第五章 颜色映射与职业动画 这一章我们来完成2D游戏中颜色映射(Palette Swap)调色盘的相关内容,并初步建立一个职业的动画控制器(Animator)与相关动画(Animations ...

  2. SRPG游戏开发(六十四)间章 第十一点五章 总结(Summary)

    返回<SRPG游戏开发>导航 间章 第十一点五章 总结(Summary) 这一章,是对第十章与第十一章的一个补充性质的文章. 文章目录 间章 第十一点五章 总结(Summary) 一 说明 ...

  3. 《SRPG游戏开发》导航(2019.03.04更新)

    <SRPG游戏开发>导航 第一章到第五章并没有使用Markdown,且经过CSDN几次改版和取消目录,这几章排版有些怪怪的. 2019.03.04 第十一章(十 - 十二) ,间章 第十一 ...

  4. SRPG游戏开发(六十三)第十一章 地图动作与地图事件 - 十二 完善地图信息与测试(Perfect MapEventInfo and Testing)

    返回<SRPG游戏开发>导航 第十一章 地图动作与地图事件(Map Action and Map Event) 我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制. 我们这一 ...

  5. SRPG游戏开发(六十)第十一章 地图动作与地图事件 - 九 触发事件与切换回合(Trigger Events and Change Turn)

    返回<SRPG游戏开发>导航 第十一章 地图动作与地图事件(Map Action and Map Event) 我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制. 我们这一 ...

  6. SRPG游戏开发(六十一)第十一章 地图动作与地图事件 - 十 NPC操作(NPC Control)

    返回<SRPG游戏开发>导航 第十一章 地图动作与地图事件(Map Action and Map Event) 我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制. 我们这一 ...

  7. 【ANDROID游戏开发十六】ANDROID GESTURE之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/337.html - ...

  8. APP游戏开发十诫!第一个雏型就要搞定的事

    APP游戏开发十诫!第一个雏型就要搞定的事 半路:在启动游戏 App 项目时,多数开发者都能条列出上百项的重要功能,似乎每个项目都非得完成不可,但到底哪些才是项目早期至关紧要,必须在第一个游戏雏型完成 ...

  9. HTML5 2D游戏引擎研发系列 第五章

    HTML5 2D游戏引擎研发系列 第五章 <Canvas技术篇-画布技术-纹理集复杂动画> 作者:HTML5游戏开发者社区-白泽 转载请注明出处:http://html5gamedev.o ...

最新文章

  1. Python 自动化办公之 Excel 拆分并自动发邮件
  2. 美团_cc城市自定义
  3. excel可视化图表插件_Axure 教程:利用图表前端插件实现高级可视化图表
  4. Select 可编辑 - 完美支持各大主流浏览器
  5. abstract类中不可以有private的成员_C++中public、protected、private的区别
  6. clion上添加程序的预定添加程序的命令行
  7. c语言中char的取值扩大,C语言中 char 类型的取值范围为什么是-128~127
  8. 《上海悠悠接口自动化平台》-4.注册用例集实战演示
  9. vue2.0 axios封装
  10. Python项目 huobi量化交易系统
  11. ♪ ♩ ♫ 海的声音(二)《三体-死神永生》
  12. AD软件绘制stm32最小系统电路原理图与PCB图
  13. 操作OMF(Oracle Managed Files,Oracle管理的文件)
  14. 【NOI2007】社交网络
  15. MySQL、SqlServer、Oracle 三种数据库的优缺点总结
  16. GPL协议-通用性公开许可证(General Public License,简称GPL)
  17. 【Dash搭建可视化网站】项目4: 利用Dash Plotly实现数据图表可视化
  18. 一起来分解一个Netty应用
  19. javaweb简单小项目-投票系统
  20. 三轴陀螺仪 偏置稳定性 光纤陀螺 光纤陀螺仪 光纤陀螺惯性导航系统 光纤陀螺惯性测量单元 六自由度IMU 单轴激光陀螺仪 双天线组合导航系统 双轴精确陀螺仪 导航级FOG怎么选择?

热门文章

  1. 数据库常考题型(4)——求函数依赖在模式上投影
  2. 关于计算机的英语名言,英语名人名言计算机ComputersTechnology
  3. 数据建模-方法论及实施步骤
  4. 2021年MyBatis面试题30道
  5. 2019年五一放假公众号推文主题怎么选?
  6. 软件需求管理用例方法 pdf_一卡通管理软件功能需求
  7. 接口测试平台代码实现74: 多接口用例-14
  8. 机器人绩溪人_绩溪县IC693PWR331机器人
  9. ARIS BPA(业务流程分析)系列二: 如何达到运营卓越
  10. 【coarse-to-fine:基于频谱和空间损失约束】