├── .gitignore ├── Preview ├── Preview.png ├── V3Anime.jpg ├── batches.png ├── AnimePlayer.png ├── AnimeSupport.gif ├── MapGroundMix.png ├── MapObjectMix.png ├── PUK3Graphic.jpg ├── AnimeHSupport.gif ├── Preview.png.meta ├── V3Anime.jpg.meta ├── batches.png.meta ├── AnimeHSupport.gif.meta ├── AnimePlayer.png.meta ├── AnimeSupport.gif.meta ├── MapGroundMix.png.meta ├── MapObjectMix.png.meta └── PUK3Graphic.jpg.meta ├── example ├── Temp │ ├── minimap_tile.png │ ├── MapTileSorting.png │ ├── AnimePlayerProps.jpg │ ├── minimap_tile.png.meta │ ├── MapTileSorting.png.meta │ └── AnimePlayerProps.jpg.meta ├── Scene │ ├── 5.Map.unity.meta │ ├── 1.Graphic.unity.meta │ ├── 2.Anime_SingleUnit.unity.meta │ ├── 3.Anime_MultiUnit.unity.meta │ └── 4.Anime_UnitControl.unity.meta ├── Prefeb.meta ├── Prefeb │ ├── Prefeb_Unit.prefab.meta │ └── Prefeb_Unit.prefab ├── Scene.meta ├── Script.meta ├── Temp.meta └── Script │ ├── Util.cs.meta │ ├── Prefeb_Unit.cs.meta │ ├── Scene_Map.cs.meta │ ├── Scene_Graphic.cs.meta │ ├── Scene_Anime_MultiUnit.cs.meta │ ├── Scene_Anime_SingleUnit.cs.meta │ ├── Scene_Anime_UnitControl.cs.meta │ ├── Prefeb_Unit.cs │ ├── Scene_Anime_SingleUnit.cs │ ├── Scene_Anime_MultiUnit.cs │ ├── Scene_Graphic.cs │ ├── Scene_Anime_UnitControl.cs │ ├── Scene_Map.cs │ └── Util.cs ├── CrossgateToolkit ├── GraphicData.cs.meta ├── DynamicGraphic.cs.meta ├── LICENSE.meta ├── ms.honorlee.crossgate-toolkit.asmdef.meta ├── Map.cs.meta ├── Anime.cs.meta ├── Audio.cs.meta ├── CGTool.cs.meta ├── Graphic.cs.meta ├── MapExtra.cs.meta ├── Palet.cs.meta ├── AnimePlayer.cs.meta ├── GraphicInfo.cs.meta ├── ms.honorlee.crossgate-toolkit.asmdef ├── LICENSE ├── CGTool.cs ├── Palet.cs ├── Graphic.cs ├── GraphicInfo.cs ├── Anime.cs ├── Audio.cs ├── DynamicGraphic.cs └── Map.cs ├── LICENSE.meta ├── README.md.meta ├── package.json.meta ├── Preview.meta ├── example.meta ├── CrossgateToolkit.meta ├── package.json ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Stor 2 | -------------------------------------------------------------------------------- /Preview/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/Preview.png -------------------------------------------------------------------------------- /Preview/V3Anime.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/V3Anime.jpg -------------------------------------------------------------------------------- /Preview/batches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/batches.png -------------------------------------------------------------------------------- /Preview/AnimePlayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/AnimePlayer.png -------------------------------------------------------------------------------- /Preview/AnimeSupport.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/AnimeSupport.gif -------------------------------------------------------------------------------- /Preview/MapGroundMix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/MapGroundMix.png -------------------------------------------------------------------------------- /Preview/MapObjectMix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/MapObjectMix.png -------------------------------------------------------------------------------- /Preview/PUK3Graphic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/PUK3Graphic.jpg -------------------------------------------------------------------------------- /Preview/AnimeHSupport.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/Preview/AnimeHSupport.gif -------------------------------------------------------------------------------- /example/Temp/minimap_tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/example/Temp/minimap_tile.png -------------------------------------------------------------------------------- /example/Temp/MapTileSorting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/example/Temp/MapTileSorting.png -------------------------------------------------------------------------------- /example/Temp/AnimePlayerProps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HonorLee-cn/CGTool/HEAD/example/Temp/AnimePlayerProps.jpg -------------------------------------------------------------------------------- /CrossgateToolkit/GraphicData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7923a3d66bd340d4a735fb394d21d0aa 3 | timeCreated: 1700512473 -------------------------------------------------------------------------------- /CrossgateToolkit/DynamicGraphic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2d30f38066d4e8e9829ca2e498bf3ac 3 | timeCreated: 1705439693 -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 54cbf3bdf1f9d40e2a96b4442041d9d6 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ca1e3ac51b31043ac9701ff2a1f46532 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40e54b9cdbcd4f76ac342ed3fb95d53a 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /CrossgateToolkit/LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 22020b7f25348410ebf11d13c1942b65 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /example/Scene/5.Map.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6d1be16073a9342ccb88fd6840870bc3 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Preview.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8f4e78845f34648539d43fd47eb374e5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /example.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d3c89cc2d681f4586b2b8fc1bfe480b3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /example/Scene/1.Graphic.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dcd7aa09311b64ad5bb5a56cccc8deb0 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /example/Prefeb.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c291698ed7c6e4b4b82c906b9263c401 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /example/Prefeb/Prefeb_Unit.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3ff3199d7cebb4e46b310b9943cf73b2 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /example/Scene.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 303dc18db856e4c9ea1fbe6761bd3c51 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /example/Script.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a9fec28ee385442a9f5b79c888e8bcc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /example/Temp.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1da0e7469c9404ad3bc986727ab9be5a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /CrossgateToolkit.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99516dbee495e4864aae9b0e43880abf 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /example/Scene/2.Anime_SingleUnit.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1223d000f936b4360a7307947bfbc055 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /example/Scene/3.Anime_MultiUnit.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4a10bf8f768da4be2be1cca1e67f96b8 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /example/Scene/4.Anime_UnitControl.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5012f8680d8c445a98cc5913a0ca8c3b 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /CrossgateToolkit/ms.honorlee.crossgate-toolkit.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 59febcf8fbac74b24aaa8133de0c2c72 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /CrossgateToolkit/Map.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d3838ed9d2b6a4ba1a3933ba7f9381ef 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /example/Script/Util.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa7779584b87f43e3907386264b0d5a3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/Anime.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8afa8455c2a8043cbb29b38c63fb386b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/Audio.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 802987c6713ae462084ebf036a59fd85 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/CGTool.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 281a60ed1ced4412aae13f6ae84954be 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/Graphic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 494e2273eccfa45d1a623a6cc98605c7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/MapExtra.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d8baca80e6d642ceab85a9747f95491 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/Palet.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 283e83919fb11457aa9262070e5dabaa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /example/Script/Prefeb_Unit.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9044c999cb58e4222a5047f68edd378c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /example/Script/Scene_Map.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a38b61199c1e24950aed7c72a8cfeaa7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/AnimePlayer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd9d50e4c140946e284602bc0c4bea54 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/GraphicInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 637b0b392dc604ce6ab83c5737a20c04 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /example/Script/Scene_Graphic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f0a92356c01504a1fb55daae6962c99c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /example/Script/Scene_Anime_MultiUnit.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 74f3c7cd98e34483b821102279c9dde0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /example/Script/Scene_Anime_SingleUnit.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d50882c95cfdf43b58eebfcd4ff6bf37 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /example/Script/Scene_Anime_UnitControl.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a9c6e5c81fd994b5db7e3ae87b874be5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /CrossgateToolkit/ms.honorlee.crossgate-toolkit.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ms.honorlee.crossgate-toolkit", 3 | "rootNamespace": "CrossgateToolkit", 4 | "references": [ 5 | "Unity.Burst", 6 | "Unity.VisualScripting.Core" 7 | ], 8 | "includePlatforms": [], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "me.honorlee.crossgate-toolkit", 3 | "version": "2.0.0", 4 | "displayName": "CGTool - Crossgate(魔力宝贝)图档解析工具库 ", 5 | "description": "这是针对《Crossgate(魔力宝贝)》游戏(3.7及以下版本)图档解析工具库,除了可以解析游戏bin图档索引、图档数据外,同时也支持动画数据解析、动画播放、地图(服务端/客户端格式)数据解析、音频数据解析等功能。", 6 | "unity": "2021.3", 7 | "author": { 8 | "name":"Honor Lee", 9 | "email": "dev@honorlee.me", 10 | "url": "https://honorlee.me" 11 | }, 12 | "references": [ 13 | "Unity.Burst", 14 | "Unity.VisualScripting" 15 | ], 16 | "dependencies": { 17 | "com.unity.burst": "1.6.0", 18 | "com.unity.visualscripting": "1.9.0" 19 | } 20 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) <2022> 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . -------------------------------------------------------------------------------- /CrossgateToolkit/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) <2022> 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . -------------------------------------------------------------------------------- /example/Script/Prefeb_Unit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using CrossgateToolkit; 5 | using UnityEngine; 6 | 7 | public class Prefeb_Unit : MonoBehaviour 8 | { 9 | public AnimePlayer animePlayer; 10 | 11 | public RectTransform RectTransform; 12 | 13 | private void Awake() 14 | { 15 | RectTransform = GetComponent(); 16 | // 可以监听动画播放帧中的音频事件并播放音效 17 | animePlayer.onAudioListener = (audioID) => 18 | { 19 | // 播放音效 20 | // 1.获取AudioClip并自行交给AudioSource播放,推荐背景音乐等长时间循环音频交给AudioSource播放 21 | // AudioClip audioClip = CrossgateToolkit.Audio.Play([Your AudioSource],Audio.Type.BGM,audioID); 22 | 23 | // 2.直接播放音效,推荐技能、人物等一次性特效音频直接交给Audio类播放和管控,即不指定AudioSource 24 | CrossgateToolkit.Audio.Play(null,Audio.Type.EFFECT,audioID); 25 | }; 26 | } 27 | 28 | // Start is called before the first frame update 29 | void Start() 30 | { 31 | 32 | } 33 | 34 | // Update is called once per frame 35 | void Update() 36 | { 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /example/Script/Scene_Anime_SingleUnit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using CrossgateToolkit; 5 | using UnityEngine; 6 | using UnityEngine.UI; 7 | 8 | public class Scene_Anime_SingleUnit : MonoBehaviour 9 | { 10 | public AnimePlayer animePlayer; 11 | 12 | public Anime.DirectionType DirectionType; 13 | 14 | public Anime.ActionType ActionType; 15 | 16 | public uint Serial; 17 | 18 | public Text[] Texts; 19 | // Start is called before the first frame update 20 | private void Awake() 21 | { 22 | Util.Init(); 23 | Serial = Util.GetRandomSerial(); 24 | DirectionType = Anime.DirectionType.SouthWest; 25 | ActionType = Anime.ActionType.Idle; 26 | } 27 | 28 | void Start() 29 | { 30 | animePlayer.play(Serial,DirectionType,ActionType,Anime.PlayType.Loop); 31 | UpdateText(); 32 | } 33 | 34 | // Update is called once per frame 35 | void Update() 36 | { 37 | 38 | } 39 | 40 | public void ChangeUint() 41 | { 42 | Serial = Util.GetRandomSerial(); 43 | animePlayer.Serial = Serial; 44 | UpdateText(); 45 | } 46 | 47 | public void ChangeDirection() 48 | { 49 | DirectionType = Util.GetNextDirection(DirectionType); 50 | animePlayer.DirectionType = DirectionType; 51 | UpdateText(); 52 | } 53 | 54 | public void ChangeAction() 55 | { 56 | // 注意不是所有角色都有 BeforeRun/AfterRun 或其他动作 57 | ActionType = Util.GetNextAction(ActionType); 58 | animePlayer.ActionType = ActionType; 59 | UpdateText(); 60 | } 61 | 62 | public void UpdateText() 63 | { 64 | Texts[0].text = Serial.ToString(); 65 | Texts[1].text = DirectionType.ToString(); 66 | Texts[2].text = ActionType.ToString(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /CrossgateToolkit/CGTool.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * 魔力宝贝图档解析脚本 - CGTool 3 | * 4 | * @Author HonorLee (dev@honorlee.me) 5 | * @Version 2.0 (2023-11-19) 6 | * @License GPL-3.0 7 | * 8 | * CGTool.cs 入口文件 9 | */ 10 | 11 | using System; 12 | using System.IO; 13 | using UnityEngine; 14 | 15 | namespace CrossgateToolkit 16 | { 17 | public static class CGTool 18 | { 19 | // 路径配置 20 | public class CGPath 21 | { 22 | // 调色板目录 23 | public string PAL; 24 | // 图档目录 25 | public string BIN; 26 | // 地图目录 27 | public string MAP; 28 | // BGM目录 29 | public string BGM; 30 | // 音效目录 31 | public string AUDIO; 32 | 33 | } 34 | 35 | // 基础路径默认配置 36 | public static CGPath PATH = new CGPath() 37 | { 38 | BIN = Environment.CurrentDirectory + "/bin", 39 | PAL = Environment.CurrentDirectory + "/pal", 40 | MAP = Environment.CurrentDirectory + "/map", 41 | BGM = Environment.CurrentDirectory + "/bgm", 42 | AUDIO = Environment.CurrentDirectory + "/se" 43 | }; 44 | 45 | public static string ENCRYPT_KEY = ""; 46 | 47 | /** 48 | * 初始化CGTool,并按顺序加载并初始化指定模块 49 | * Graphic加载顺序以Bin目录中的文件名排序 50 | * 其中Bin目录根目录下优先级最高,其次是Bin目录下的子目录 51 | */ 52 | public static void Init(string encryptKey = "") 53 | { 54 | // 加密KEY 55 | ENCRYPT_KEY = encryptKey; 56 | 57 | // 初始化调色板 58 | if (PATH.PAL != null) Palet.Init(); 59 | // 初始化图档解析器 60 | if (PATH.BIN != null) Graphic.Init(); 61 | // 初始化地图索引 62 | if (PATH.MAP != null) Map.Init(); 63 | 64 | 65 | Debug.Log("[CGTool] CGTool初始化完成"); 66 | } 67 | 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /example/Script/Scene_Anime_MultiUnit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using CrossgateToolkit; 5 | using UnityEngine; 6 | using Random = UnityEngine.Random; 7 | 8 | public class Scene_Anime_MultiUnit : MonoBehaviour 9 | { 10 | public Transform UnitContainer; 11 | public Prefeb_Unit unitPrefeb; 12 | List units = new List(); 13 | 14 | private void Awake() 15 | { 16 | Util.Init(); 17 | } 18 | 19 | void Start() 20 | { 21 | int x = 18; 22 | int y = 5; 23 | int width = x * 60; 24 | int height = y * 100; 25 | for (int i = 0; i < x; i++) 26 | { 27 | for (int j = 0; j < y; j++) 28 | { 29 | Prefeb_Unit unit = Instantiate(unitPrefeb, UnitContainer); 30 | unit.name = "Unit_" + i + "_" + j; 31 | unit.RectTransform.anchoredPosition = 32 | new Vector2(-width / 2f + i * 60, -height / 2f + j * 100 + 10); 33 | unit.animePlayer.Serial = Util.GetRandomSerial(); 34 | unit.animePlayer.DirectionType = Util.GetRandomDirection(); 35 | unit.animePlayer.ActionType = (Anime.ActionType)Random.Range(0, 21); 36 | units.Add(unit); 37 | } 38 | } 39 | } 40 | 41 | public void ChangeSerial() 42 | { 43 | foreach (var unit in units) 44 | { 45 | unit.animePlayer.Serial = Util.GetRandomSerial(); 46 | } 47 | } 48 | 49 | public void ChangeDirection() 50 | { 51 | foreach (var unit in units) 52 | { 53 | unit.animePlayer.DirectionType = Util.GetRandomDirection(); 54 | } 55 | } 56 | 57 | public void ChangeAction() 58 | { 59 | foreach (var unit in units) 60 | { 61 | unit.animePlayer.ActionType = (Anime.ActionType)Random.Range(0, 21); 62 | } 63 | } 64 | 65 | // Update is called once per frame 66 | void Update() 67 | { 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /example/Prefeb/Prefeb_Unit.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &3581443505488461264 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 3581443505488461265} 12 | - component: {fileID: 3581443505488461266} 13 | m_Layer: 5 14 | m_Name: AnimePlayer 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!224 &3581443505488461265 21 | RectTransform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 3581443505488461264} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_ConstrainProportionsScale: 0 31 | m_Children: [] 32 | m_Father: {fileID: 3581443506478119344} 33 | m_RootOrder: 0 34 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 35 | m_AnchorMin: {x: 0.5, y: 0} 36 | m_AnchorMax: {x: 0.5, y: 0} 37 | m_AnchoredPosition: {x: 0, y: 0} 38 | m_SizeDelta: {x: 100, y: 100} 39 | m_Pivot: {x: 0.5, y: 0} 40 | --- !u!114 &3581443505488461266 41 | MonoBehaviour: 42 | m_ObjectHideFlags: 0 43 | m_CorrespondingSourceObject: {fileID: 0} 44 | m_PrefabInstance: {fileID: 0} 45 | m_PrefabAsset: {fileID: 0} 46 | m_GameObject: {fileID: 3581443505488461264} 47 | m_Enabled: 1 48 | m_EditorHideFlags: 0 49 | m_Script: {fileID: 11500000, guid: bd9d50e4c140946e284602bc0c4bea54, type: 3} 50 | m_Name: 51 | m_EditorClassIdentifier: 52 | isRenderByImage: 1 53 | isFrameBatch: 1 54 | isLinearFilter: 0 55 | frameTexture: {fileID: 0} 56 | --- !u!1 &3581443506478119343 57 | GameObject: 58 | m_ObjectHideFlags: 0 59 | m_CorrespondingSourceObject: {fileID: 0} 60 | m_PrefabInstance: {fileID: 0} 61 | m_PrefabAsset: {fileID: 0} 62 | serializedVersion: 6 63 | m_Component: 64 | - component: {fileID: 3581443506478119344} 65 | - component: {fileID: 3172618607091955258} 66 | m_Layer: 5 67 | m_Name: Prefeb_Unit 68 | m_TagString: Untagged 69 | m_Icon: {fileID: 0} 70 | m_NavMeshLayer: 0 71 | m_StaticEditorFlags: 0 72 | m_IsActive: 1 73 | --- !u!224 &3581443506478119344 74 | RectTransform: 75 | m_ObjectHideFlags: 0 76 | m_CorrespondingSourceObject: {fileID: 0} 77 | m_PrefabInstance: {fileID: 0} 78 | m_PrefabAsset: {fileID: 0} 79 | m_GameObject: {fileID: 3581443506478119343} 80 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 81 | m_LocalPosition: {x: 0, y: 0, z: 0} 82 | m_LocalScale: {x: 1, y: 1, z: 1} 83 | m_ConstrainProportionsScale: 0 84 | m_Children: 85 | - {fileID: 3581443505488461265} 86 | m_Father: {fileID: 0} 87 | m_RootOrder: 0 88 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 89 | m_AnchorMin: {x: 0.5, y: 0.5} 90 | m_AnchorMax: {x: 0.5, y: 0.5} 91 | m_AnchoredPosition: {x: 0, y: 0} 92 | m_SizeDelta: {x: 100, y: 100} 93 | m_Pivot: {x: 0.5, y: 0} 94 | --- !u!114 &3172618607091955258 95 | MonoBehaviour: 96 | m_ObjectHideFlags: 0 97 | m_CorrespondingSourceObject: {fileID: 0} 98 | m_PrefabInstance: {fileID: 0} 99 | m_PrefabAsset: {fileID: 0} 100 | m_GameObject: {fileID: 3581443506478119343} 101 | m_Enabled: 1 102 | m_EditorHideFlags: 0 103 | m_Script: {fileID: 11500000, guid: 9044c999cb58e4222a5047f68edd378c, type: 3} 104 | m_Name: 105 | m_EditorClassIdentifier: 106 | animePlayer: {fileID: 3581443505488461266} 107 | -------------------------------------------------------------------------------- /Preview/Preview.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cd89209f2e828430185f6f3d56e3bf69 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Preview/V3Anime.jpg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 60f5b634bb7de4ee1987e1b6048522fa 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Preview/batches.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 16f61ec572a364fa6a955d1b925272c4 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Preview/AnimeHSupport.gif.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 158480bd1c99841eb8139b2a0b5aafc0 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Preview/AnimePlayer.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c7627ba59c7df4826aa2b82838eafc98 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Preview/AnimeSupport.gif.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 667213bc318724530aa9c81f3f1a380f 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Preview/MapGroundMix.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 24b31680f5c68490f96abf384a80ead9 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Preview/MapObjectMix.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73903682068bf430ab979ad54d7e7e69 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Preview/PUK3Graphic.jpg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62bc4f4bd580d4207b843fb0416ca42f 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /example/Temp/minimap_tile.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2ddbf947884314f3591bfa68d72e4cea 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 0 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 0 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 1 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Server 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: WebGL 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /example/Temp/MapTileSorting.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c892a72def28457cb5242d0a5730b38 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 1 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /example/Temp/AnimePlayerProps.jpg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3d759879c7a8a44dcb7cc5ea3d71c010 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 0 66 | cookieLightType: 0 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 0 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 0 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 0 104 | - serializedVersion: 3 105 | buildTarget: Server 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: 131 | pSDRemoveMatte: 0 132 | pSDShowRemoveMatteOption: 0 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /example/Script/Scene_Graphic.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using CrossgateToolkit; 4 | using UnityEngine; 5 | using UnityEngine.UI; 6 | 7 | public class Scene_Graphic : MonoBehaviour 8 | { 9 | [SerializeField,Header("单张图档")] 10 | private Image SingleGraphic; 11 | [SerializeField,Header("合批图档")] 12 | private Image BatchGraphic; 13 | [SerializeField,Header("动态合批图档")] 14 | private Image DynamicBatchGraphic; 15 | // Start is called before the first frame update 16 | void Start() 17 | { 18 | 19 | } 20 | 21 | // Update is called once per frame 22 | void Update() 23 | { 24 | 25 | } 26 | 27 | private void Awake() 28 | { 29 | Util.Init(); 30 | GetSingleGraphic(); 31 | 32 | // 两种合批方式 33 | // 可以观察两种合批方式所形成的图像图集差异 34 | GetBatchGraphic(); // 一次性合批图像 35 | StartCoroutine(GetDynamicBatchGraphic()); // 动态合批图像 36 | } 37 | 38 | public void GetSingleGraphic() 39 | { 40 | // 获取单张图档 41 | GraphicDetail graphicDetail = CrossgateToolkit.Graphic.GetGraphicDetail(10302); 42 | SingleGraphic.sprite = graphicDetail.SpritePPU100; 43 | SingleGraphic.SetNativeSize(); 44 | // 获取单张图档的PPU-100的图像 45 | // SingleGraphic.sprite = CrossgateToolkit.Graphic.GetGraphicDetail(4116).SpritePPU100; 46 | } 47 | 48 | public void GetBatchGraphic() 49 | { 50 | // 以合批方式获取并处理图像图集 51 | // 此处使用图档编号(非索引)获取图像 52 | uint[] serials = new uint[] 53 | { 54 | // 地面 55 | 4116,4117,4118,4119,4120,4121,4122,4123,4124,4125, 56 | // 其他不同尺寸图像 57 | 10561,10571,10573,10443,10403 58 | }; 59 | 60 | // 获取合批图集前,需要手动获取整理图像信息数据 61 | List graphicInfoDatas = new List(); 62 | for (int i = 0; i < serials.Length; i++) 63 | { 64 | graphicInfoDatas.Add(CrossgateToolkit.GraphicInfo.GetGraphicInfoData(serials[i])); 65 | } 66 | 67 | // 合批图像,并获取对应编号与图像映射 68 | Dictionary graphicDetails = GraphicData.BakeGraphics(graphicInfoDatas, true, 0, -1, false, 256, 5); 69 | 70 | // 获取合批的原图像 71 | Texture2D texture2D = graphicDetails[4116].SpritePPU100.texture; 72 | BatchGraphic.sprite = Sprite.Create(texture2D,new Rect(0,0,texture2D.width,texture2D.height),new Vector2(0.5f,0.5f)); 73 | BatchGraphic.SetNativeSize(); 74 | // 说明:合批图集定义最大图集尺寸为512,合批后的图像图集,尺寸不会超过512 75 | // 一次性合批的图像会根据图像尺寸由小到大,由低到高方式进行排列处理,直到达到最大尺寸限制 76 | } 77 | 78 | IEnumerator GetDynamicBatchGraphic() 79 | { 80 | // 以动态图集方式获取并处理图像图集 81 | // 此处使用图档编号(非索引)获取图像 82 | uint[] serials = new uint[] 83 | { 84 | // 地面 85 | 4116,4117,4118,4119,4120,4121,4122,4123,4124,4125, 86 | // 其他不同尺寸图像 87 | 10561,10571,10573,10443,10403 88 | }; 89 | 90 | // 动态图集无需手动获取整理图像信息数据 91 | 92 | // 首先定义图集 93 | DynamicGraphic dynamicGraphic = new DynamicGraphic(256,256,5,0,false,true); 94 | // 动态图集为自动动态扩容图集 95 | // 当当前图集内无空余空间容纳当前填充图形时,会自动进行扩容,形成新的图集图像,但尺寸不会超过定义的图集尺寸 96 | 97 | // 可以直接通过图像编号填充图集并获取填充后的图像数据 98 | Sprite sprite = dynamicGraphic.GetSprite(4116); 99 | sprite = dynamicGraphic.GetSprite(4117); 100 | 101 | // 可以手动清除图集避免内存泄漏 102 | dynamicGraphic.Clear(); 103 | 104 | // 亦可通过协程方式填充图集,避免大批量获取图像时造成主线程卡顿 105 | // 协程方式填充图集需要通过回调方式获取填充后的图像数据 106 | bool next = false; 107 | for (var i = 0; i < serials.Length; i++) 108 | { 109 | StartCoroutine( 110 | dynamicGraphic.GetSpriteSync(serials[i], (outputSprite) => 111 | { 112 | // 获取到图像数据后的处理 113 | // 此处可以将图像数据赋值给Image等UI组件 114 | // 也可以将图像数据保存到本地等 115 | sprite = outputSprite; 116 | next = true; 117 | })); 118 | yield return new WaitUntil(() => next); 119 | } 120 | 121 | Texture2D texture2D = sprite.texture; 122 | DynamicBatchGraphic.sprite = Sprite.Create(texture2D,new Rect(0,0,texture2D.width,texture2D.height),new Vector2(0.5f,0.5f)); 123 | DynamicBatchGraphic.SetNativeSize(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /CrossgateToolkit/Palet.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * 魔力宝贝图档解析脚本 - CGTool 3 | * 4 | * @Author HonorLee (dev@honorlee.me) 5 | * @Version 1.0 (2023-04-15) 6 | * @License GPL-3.0 7 | * 8 | * Palet.cs 调色板解析类 9 | */ 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using System.IO; 14 | using UnityEngine; 15 | 16 | namespace CrossgateToolkit 17 | { 18 | public class Palet 19 | { 20 | 21 | private static Dictionary> _cache = new Dictionary>(); 22 | 23 | //获取调色板 24 | public static List GetPalet(int index) 25 | { 26 | //返回缓存数据 27 | _cache.TryGetValue(index, out List paletData); 28 | return paletData; 29 | } 30 | 31 | //调色板初始化 32 | public static void Init() 33 | { 34 | DirectoryInfo folderInfo = new DirectoryInfo(CGTool.PATH.PAL); 35 | 36 | if (!folderInfo.Exists) throw new Exception("调色板目录不存在,请检查CGTool中是否配置相应PATH路径"); 37 | 38 | FileInfo[] files = folderInfo.GetFiles(); 39 | foreach (FileInfo file in files) 40 | { 41 | if (!file.Name.StartsWith("palet_") || !file.Name.EndsWith(".cgp")) continue; 42 | string tmp = file.Name.Split("_")[1]; 43 | string indexStr = tmp.Split(".")[0]; 44 | // string indexStr = file.Name.Substring(6, 2); 45 | if (int.TryParse(indexStr, out int index)) 46 | { 47 | List paletData = _loadPalet(file); 48 | if (paletData != null) _cache.Add(index, paletData); 49 | } 50 | } 51 | 52 | Debug.Log("[CGTool] 调色板初始化完成,共加载" + _cache.Count + "个调色板"); 53 | } 54 | 55 | // 添加新调色板 56 | public static void AddPalet(int index, List paletData) 57 | { 58 | _cache[index] = paletData; 59 | } 60 | 61 | //加载缓存数据 62 | private static List _loadPalet(FileInfo paletFile) 63 | { 64 | FileStream paletFileStream = paletFile.OpenRead(); 65 | BinaryReader paletReader = new BinaryReader(paletFileStream); 66 | 67 | //调色板解析表 68 | List PaletColors = new List(); 69 | 70 | //头部调色板 71 | int[] headPlate = new int[] 72 | { 73 | 0x000000, 0x000080, 0x008000, 0x008080, 0x800080, 0x800000, 0x808000, 0xc0c0c0, 0xc0dcc0, 0xf0caa6, 74 | 0x0000de, 0x005fff, 0xa0ffff, 0xd25f00, 0xffd250, 0x28e128 75 | }; 76 | //尾部调色板 77 | int[] footPlate = new int[] 78 | { 79 | 0x96c3f5, 0x5fa01e, 0x467dc3, 0x1e559b, 0x374146, 0x1e2328, 0xf0fbff, 0xa56e3a, 0x808080, 0x0000ff, 80 | 0x00ff00, 0x00ffff, 0xff0000, 0xff80ff, 0xffff00, 0xffffff 81 | }; 82 | 83 | //解压缩 84 | foreach (var i in headPlate) 85 | { 86 | byte[] bytes = BitConverter.GetBytes(i); 87 | Color32 color32 = new Color32(); 88 | color32.r = bytes[0]; 89 | color32.g = bytes[1]; 90 | color32.b = bytes[2]; 91 | color32.a = (byte)(i == 0 ? 0x00 : 0xFF); 92 | PaletColors.Add(color32); 93 | } 94 | 95 | 96 | 97 | 98 | for (var i = 0; i < 224; i++) 99 | { 100 | byte[] paletBytes = paletReader.ReadBytes(3); 101 | // if(i<16 || i>224) continue; 102 | Color32 color32 = new Color32(); 103 | color32.r = paletBytes[2]; 104 | color32.g = paletBytes[1]; 105 | color32.b = paletBytes[0]; 106 | color32.a = 0xFF; 107 | PaletColors.Add(color32); 108 | } 109 | 110 | foreach (var i in footPlate) 111 | { 112 | byte[] bytes = BitConverter.GetBytes(i); 113 | Color32 color32 = new Color32(); 114 | color32.r = bytes[0]; 115 | color32.g = bytes[1]; 116 | color32.b = bytes[2]; 117 | color32.a = 0xFF; 118 | PaletColors.Add(color32); 119 | } 120 | 121 | PaletColors.Add(Color.clear); 122 | //清理缓存 123 | paletReader.Dispose(); 124 | paletReader.Close(); 125 | paletFileStream.Dispose(); 126 | paletFileStream.Close(); 127 | 128 | return PaletColors; 129 | } 130 | } 131 | } -------------------------------------------------------------------------------- /example/Script/Scene_Anime_UnitControl.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using CrossgateToolkit; 4 | using UnityEngine; 5 | 6 | public class Scene_Anime_UnitControl : MonoBehaviour 7 | { 8 | [Header("单位列表")] 9 | [Header("跑步单位")] public Prefeb_Unit Unit_Runner; 10 | [Header("攻击单位")] public Prefeb_Unit Unit_Attacker; 11 | [Header("防御单位")] public Prefeb_Unit Unit_Defender; 12 | [Header("特效单位")] public Prefeb_Unit Unit_Effect; 13 | [Header("动作单位")] public Prefeb_Unit Unit_Action; 14 | // Start is called before the first frame update 15 | void Start() 16 | { 17 | 18 | } 19 | 20 | // Update is called once per frame 21 | void Update() 22 | { 23 | 24 | } 25 | 26 | private void Awake() 27 | { 28 | Util.Init(); 29 | } 30 | 31 | public void Play() 32 | { 33 | RunnerRun(); 34 | AttackerRun(); 35 | StartCoroutine(PlayControl()); 36 | } 37 | 38 | private void RunnerRun() 39 | { 40 | // 动画队列一般用于对动画流程没有严格要求的场景 41 | // 动画播放过程中,如果某个动画数据缺失或不存在,则会自动跳过该动画并自动播放下一动画 42 | // 如果需要控制动画的具体播放时机和顺序或控制其他变量行为,建议使用动画回调监听方式处理 43 | 44 | // 以队列方式播放特殊三段式跑步动画 45 | Unit_Runner.animePlayer.Serial = 105000; 46 | Unit_Runner.animePlayer.DirectionType = Anime.DirectionType.South; 47 | Unit_Runner.animePlayer.playOnce(Unit_Runner.animePlayer.DirectionType,Anime.ActionType.BeforeRun) 48 | .nextPlay(Unit_Runner.animePlayer.DirectionType,Anime.ActionType.Run,Anime.PlayType.Once) 49 | .nextPlay(Unit_Runner.animePlayer.DirectionType,Anime.ActionType.AfterRun,Anime.PlayType.Once) 50 | .nextPlay(Unit_Runner.animePlayer.DirectionType,Anime.ActionType.Idle,Anime.PlayType.Loop); 51 | } 52 | 53 | private void AttackerRun() 54 | { 55 | // 动画帧事件监听 56 | // 普通的攻击动画正常会有击中和攻击完成两种事件回调 57 | // 如:小石像怪,有多段击中效果,最后一段击中则为攻击完成 58 | // 又如:冰冻魔法,有多段击中效果,最后一段击中则为攻击完成 59 | 60 | // 但可以肯定有部分动画因图档版本问题或打包过程中出现动作帧缺失的情况,则有可能无法触发击中或是攻击完成事件 61 | // 这时可能需要通过使用动画播放完成事件回调来处理 62 | 63 | Unit_Attacker.animePlayer.Serial = 101200; 64 | Unit_Attacker.animePlayer.DirectionType = Anime.DirectionType.SouthEast; 65 | 66 | Unit_Defender.animePlayer.Serial = 105052; 67 | Unit_Defender.animePlayer.DirectionType = Anime.DirectionType.NorthWest; 68 | 69 | Unit_Attacker.animePlayer.playOnce(Unit_Attacker.animePlayer.DirectionType, Anime.ActionType.Attack, 1f, 70 | (effectType) => 71 | { 72 | // 动画事件回调 73 | 74 | // 击中或攻击结束效果时,出现被击中动画 75 | // Unit_Effect.animePlayer.Serial = 110001; 76 | Unit_Effect.animePlayer.play(110001,Anime.DirectionType.North,Anime.ActionType.Idle,Anime.PlayType.OnceAndDestroy); 77 | Unit_Effect.RectTransform.position = Unit_Defender.RectTransform.position + new Vector3(0, 0.5f, 0); 78 | 79 | // 击中效果 80 | if (effectType == Anime.EffectType.Hit) 81 | { 82 | // 对于多段攻击可以延迟下一帧的帧率以达到子弹时间或是其他效果 83 | Unit_Attacker.animePlayer.DelayPlay(0.5f); 84 | // 可以在击中效果中处理受击方的受击动画效果,同样也可以控制帧率速度倍率 85 | Unit_Defender.animePlayer.playOnce(Unit_Defender.animePlayer.DirectionType, Anime.ActionType.Hurt, 86 | 0.2f); 87 | // 可以给受击方增加抖动处理等等,这里不再做演示 88 | } 89 | 90 | // 攻击完成 91 | if (effectType == Anime.EffectType.HitOver) 92 | { 93 | // 攻击结束阶段可以处理实际的伤害数值显示等 94 | Unit_Defender.animePlayer.playOnce(Unit_Defender.animePlayer.DirectionType, Anime.ActionType.Hurt); 95 | } 96 | }, (act) => 97 | { 98 | // 动画播放完成回调 99 | // 此处可以处理动画播放完成后的逻辑处理 100 | Unit_Attacker.animePlayer.ActionType = Anime.ActionType.Idle; 101 | }); 102 | } 103 | 104 | IEnumerator PlayControl() 105 | { 106 | // 通过协程以及动画播放完成监听的方式控制动画播放 107 | // 也可通过非协程的多级回调方式控制动画播放,看具体应用场景和编码习惯 108 | bool runAble = false; 109 | Unit_Action.animePlayer.Serial = 106270; 110 | Unit_Action.animePlayer.DirectionType = Anime.DirectionType.SouthWest; 111 | Unit_Action.animePlayer.playOnce(Anime.DirectionType.SouthWest, Anime.ActionType.Rock, 1f, null, 112 | (act) => runAble = true); 113 | yield return new WaitUntil(() => runAble); 114 | yield return new WaitForSeconds(0.5f); 115 | runAble = false; 116 | Unit_Action.animePlayer.playOnce(Anime.DirectionType.SouthWest, Anime.ActionType.Scissors, 1f, null, 117 | (act) => runAble = true); 118 | yield return new WaitUntil(() => runAble); 119 | yield return new WaitForSeconds(0.5f); 120 | Unit_Action.animePlayer.playOnce(Anime.DirectionType.SouthWest, Anime.ActionType.Paper, 1f, null, 121 | (act) => runAble = true); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /example/Script/Scene_Map.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using CrossgateToolkit; 4 | using UnityEngine; 5 | using UnityEngine.Tilemaps; 6 | 7 | public class Scene_Map : MonoBehaviour 8 | { 9 | [SerializeField,Header("地图渲染用Camera")] 10 | private Camera MapCamera; 11 | [SerializeField,Header("地图地面TileMap")] 12 | private Tilemap TileMap_Ground; 13 | [SerializeField,Header("地图物件TileMap")] 14 | private Tilemap TileMap_Object; 15 | 16 | [SerializeField,Header("地图Grid")] 17 | private Grid MapGrid; 18 | 19 | [SerializeField, Header("地图背景音乐")] 20 | private AudioSource MapBGM; 21 | 22 | 23 | [SerializeField,Header("小地图TileMap")] 24 | private Tilemap TileMap_MiniMap; 25 | [SerializeField,Header("小地图TileSprite")] 26 | private Sprite MiniMapSprite; 27 | 28 | // 地图数据 29 | private MapInfo mapInfo; 30 | // 地图音乐 31 | private uint mapBGMID; 32 | // 地图图像数据 33 | private Dictionary GroundGraphicDetails; 34 | private Dictionary ObjectGraphicDetails; 35 | 36 | // Start is called before the first frame update 37 | void Start() 38 | { 39 | // 地图渲染相机需要注意调整排序方式 40 | MapCamera.transparencySortMode = TransparencySortMode.CustomAxis; 41 | MapCamera.transparencySortAxis = new Vector3(0, 1, -0.1f); 42 | 43 | LoadMap(); 44 | } 45 | 46 | private void Awake() 47 | { 48 | Util.Init(); 49 | } 50 | 51 | private void LoadMap() 52 | { 53 | // 获取地图信息,此处以编号为1000的法兰城地图为例 54 | mapInfo = Map.GetMap(1000); 55 | 56 | // 地图的数据已经过重新排序处理,无论加载的是服务端地图或是客户端地图,均按照场景中所示排序规则进行处理 57 | 58 | // 图集合批处理 59 | BakeMapGraphics(); 60 | 61 | // 绘制地图,此处直接绘制全图 62 | // 实际使用中推荐以卡马克卷轴算法进行局部绘制,以提高性能 63 | DrawMapGround(); 64 | DrawMapObject(); 65 | 66 | // 调整位置 67 | int x = mapInfo.Width / 2 * 32 - mapInfo.Height / 2 * 32; 68 | int y = -mapInfo.Height / 2 * 24 - mapInfo.Width / 2 * 24; 69 | MapGrid.GetComponent().localPosition = new Vector3(x, y, 0); 70 | 71 | // 绘制小地图 72 | DrawMiniMap(); 73 | } 74 | 75 | // 对地图图像进行合批处理 76 | private void BakeMapGraphics() 77 | { 78 | // 以合批图集的形式缓存地图图像数据 79 | // 此处仅以一次性合批图集方式进行示范 80 | // 如若针对服务端动态地图方式,则需要动态合批图集,可参考Scene_Graphic.cs中的GetDynamicBatchGraphic()方法进行处理 81 | 82 | List graphicInfoDatas; 83 | // 获取地面数据并进行合批 84 | graphicInfoDatas = new List(); 85 | for (var i = 0; i < mapInfo.GroundDatas.Count; i++) 86 | { 87 | MapBlockData mapBlockData = mapInfo.GroundDatas[i]; 88 | if(mapBlockData==null || mapBlockData.GraphicInfo==null) continue; 89 | graphicInfoDatas.Add(mapBlockData.GraphicInfo); 90 | } 91 | GroundGraphicDetails = GraphicData.BakeGraphics(graphicInfoDatas, true, 0, -1, false, 2048); 92 | 93 | // 获取物件数据并进行合批 94 | graphicInfoDatas = new List(); 95 | for (var i = 0; i < mapInfo.ObjectDatas.Count; i++) 96 | { 97 | MapBlockData mapBlockData = mapInfo.ObjectDatas[i]; 98 | if(mapBlockData==null || mapBlockData.GraphicInfo==null) continue; 99 | graphicInfoDatas.Add(mapBlockData.GraphicInfo); 100 | } 101 | ObjectGraphicDetails = GraphicData.BakeGraphics(graphicInfoDatas, true, 0, -1, false, 2048); 102 | } 103 | 104 | // 绘制地图地面 105 | private void DrawMapGround() 106 | { 107 | int width = mapInfo.Width; 108 | int height = mapInfo.Height; 109 | List drawPositions = new List(); 110 | List drawTiles = new List(); 111 | for(int x = 0; x < width; x++) 112 | { 113 | for(int y = 0; y < height; y++) 114 | { 115 | MapBlockData mapBlockData = mapInfo.GroundDatas[y * width + x]; 116 | if(mapBlockData==null || mapBlockData.GraphicInfo==null) continue; 117 | GraphicDetail graphicDetail = GroundGraphicDetails[mapBlockData.MapSerial]; 118 | Tile groundTile = Tile.CreateInstance(typeof(Tile)) as Tile; 119 | groundTile.sprite = graphicDetail.Sprite; 120 | drawPositions.Add(new Vector3Int(x, y, 0)); 121 | drawTiles.Add(groundTile); 122 | } 123 | } 124 | 125 | TileMap_Ground.SetTiles(drawPositions.ToArray(), drawTiles.ToArray()); 126 | } 127 | 128 | // 绘制地图物件 129 | private void DrawMapObject() 130 | { 131 | int width = mapInfo.Width; 132 | int height = mapInfo.Height; 133 | List drawPositions = new List(); 134 | List drawTiles = new List(); 135 | for(int x = 0; x < width; x++) 136 | { 137 | for(int y = 0; y < height; y++) 138 | { 139 | MapBlockData mapBlockData = mapInfo.ObjectDatas[y * width + x]; 140 | if(mapBlockData==null || mapBlockData.GraphicInfo==null) continue; 141 | if (mapBlockData.GraphicInfo.Serial < 1000) 142 | { 143 | // 小于1000的编号为音频编号 144 | if (mapBGMID == 0) 145 | { 146 | mapBGMID = mapBlockData.MapSerial; 147 | // 播放背景音乐 148 | Audio.Play(MapBGM, Audio.Type.BGM, (int)mapBGMID); 149 | } 150 | } 151 | GraphicDetail graphicDetail = ObjectGraphicDetails[mapBlockData.MapSerial]; 152 | Tile objectTile = Tile.CreateInstance(typeof(Tile)) as Tile; 153 | objectTile.sprite = graphicDetail.Sprite; 154 | // 注意排序的修正,mapBlockData提供了基础的Z轴修正,如需更精确的效果请自行计算处理 155 | drawPositions.Add(new Vector3Int(x, y, 0)); 156 | drawTiles.Add(objectTile); 157 | } 158 | } 159 | 160 | TileMap_Object.SetTiles(drawPositions.ToArray(), drawTiles.ToArray()); 161 | } 162 | 163 | // 绘制小地图 164 | private void DrawMiniMap() 165 | { 166 | // CGTool提供了简单的处理方式 167 | // 可以直接通过获取图档数据的主色调来处理小地图 168 | 169 | List drawPositions = new List(); 170 | List drawTiles = new List(); 171 | 172 | for(int x = 0; x < mapInfo.Width; x++) 173 | { 174 | for(int y = 0; y < mapInfo.Height; y++) 175 | { 176 | MapBlockData mapBlockData = mapInfo.GroundDatas[y * mapInfo.Width + x]; 177 | MapBlockData mapObjectData = mapInfo.ObjectDatas[y * mapInfo.Width + x]; 178 | if(mapBlockData==null && mapObjectData==null) continue; 179 | 180 | Tile tile = Tile.CreateInstance(typeof(Tile)) as Tile; 181 | tile.sprite = MiniMapSprite; 182 | 183 | 184 | if (mapObjectData == null) 185 | { 186 | // 没有地面物件时使用地面主色 187 | tile.color = GroundGraphicDetails[mapBlockData.MapSerial].PrimaryColor; 188 | } 189 | else 190 | { 191 | // 有地面物件时使用物件主色,此处只做演示,正常情况下需要根据建筑物的占地尺寸对相应区块进行填充以提高小地图的视觉效果 192 | tile.color = ObjectGraphicDetails[mapObjectData.MapSerial].PrimaryColor; 193 | } 194 | 195 | drawPositions.Add(new Vector3Int(x, y, 0)); 196 | drawTiles.Add(tile); 197 | } 198 | } 199 | 200 | TileMap_MiniMap.SetTiles(drawPositions.ToArray(), drawTiles.ToArray()); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /CrossgateToolkit/Graphic.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * 魔力宝贝图档解析脚本 - CGTool 3 | * 4 | * @Author HonorLee (dev@honorlee.me) 5 | * @Version 1.0 (2023-04-15) 6 | * @License GPL-3.0 7 | * 8 | * Graphic.cs 图档解析类 9 | */ 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using System.IO; 14 | using System.Linq; 15 | using UnityEngine; 16 | 17 | namespace CrossgateToolkit 18 | { 19 | //图档类 20 | public static class Graphic 21 | { 22 | private class FilePair 23 | { 24 | public FileInfo InfoFile; 25 | public FileInfo DataFile; 26 | public string Version; 27 | } 28 | 29 | // 临时文件列表缓存 30 | private static List _graphicFilePairs = new List(); 31 | private static List _animeFilePairs = new List(); 32 | 33 | // 高版本号标识 34 | // public static readonly Dictionary Flag_HighVersion = new Dictionary(); 35 | 36 | // 初始化 37 | public static void Init() 38 | { 39 | // 解析Bin文件目录结构 40 | if(!Directory.Exists(CGTool.PATH.BIN)) throw new Exception("图档目录不存在,请检查CGTool中是否配置相应PATH路径"); 41 | //float time = Time.realtimeSinceStartup; 42 | // 整理目录结构,生成对应待处理文件列表 43 | List _directorys = new List(); 44 | _directorys.Add(new DirectoryInfo(CGTool.PATH.BIN)); 45 | _directorys.AddRange(new DirectoryInfo(CGTool.PATH.BIN).GetDirectories().OrderBy(d => d.Name).ToList()); 46 | foreach (DirectoryInfo directory in _directorys) 47 | { 48 | AnalysisDirectory(directory); 49 | } 50 | Debug.Log("[CGTool] 图档资源查找完毕,共找到: (" + _graphicFilePairs.Count + ") 个图档文件, (" + _animeFilePairs.Count + 51 | ") 个动画文件"); 52 | 53 | // 预加载 GraphicInfo 54 | foreach (FilePair graphicFilePair in _graphicFilePairs) 55 | { 56 | GraphicInfo.Init(graphicFilePair.Version,graphicFilePair.InfoFile, graphicFilePair.DataFile); 57 | } 58 | 59 | // 预加载 Anime 60 | foreach (FilePair animeFilePair in _animeFilePairs) 61 | { 62 | Anime.Init(animeFilePair.Version, animeFilePair.InfoFile, animeFilePair.DataFile); 63 | } 64 | //Debug.Log("[CGTool] 图档资源加载完毕,耗时: " + (Time.realtimeSinceStartup - time) + "s"); 65 | } 66 | 67 | // 版本号分析 68 | private class VersionInfo 69 | { 70 | public string Version; 71 | public int VersionCode; 72 | public string FullVersion; 73 | } 74 | private static VersionInfo AnalysisVersion(string prefix,FileInfo fileinfo) 75 | { 76 | VersionInfo versionInfo = new VersionInfo(); 77 | int suffixIndex = fileinfo.Name.LastIndexOf('.'); 78 | 79 | // 解析版本号 80 | string filename = fileinfo.Name.Substring(0, suffixIndex); 81 | versionInfo.FullVersion = filename.Substring(prefix.Length); 82 | if (string.IsNullOrEmpty(versionInfo.FullVersion)) 83 | { 84 | string parentName = fileinfo.Directory != null ? fileinfo.Directory.Name : ""; 85 | versionInfo.FullVersion = ""; 86 | versionInfo.Version = parentName.ToUpper(); 87 | } 88 | else 89 | { 90 | string[] versionArr = versionInfo.FullVersion.Split('_'); 91 | if (String.IsNullOrEmpty(versionArr[0])) 92 | { 93 | versionArr = versionArr.Skip(1).ToArray(); 94 | } 95 | 96 | if (int.TryParse(versionArr[0], out int code)) 97 | { 98 | versionInfo.VersionCode = code; 99 | } 100 | else 101 | { 102 | versionInfo.Version = versionArr[0].ToUpper(); 103 | if(int.TryParse(versionArr[^1], out int vcode)) 104 | { 105 | versionInfo.VersionCode = vcode; 106 | } 107 | } 108 | } 109 | 110 | 111 | return versionInfo; 112 | } 113 | // 分析目录,并获取对应配对文件 114 | private static void AnalysisDirectory(DirectoryInfo directoryInfo) 115 | { 116 | // Debug.Log("[CGTool] 开始分析目录: " + directoryInfo.FullName); 117 | string Version = directoryInfo.Name; 118 | FileInfo[] fileInfos = directoryInfo.GetFiles(); 119 | fileInfos = fileInfos.OrderBy(f => f.Name).ToArray(); 120 | foreach (FileInfo fileInfo in fileInfos) 121 | { 122 | if (!fileInfo.Name.EndsWith(".bin",StringComparison.OrdinalIgnoreCase)) continue; 123 | 124 | if (fileInfo.Name.StartsWith("graphicinfo", StringComparison.OrdinalIgnoreCase)) 125 | { 126 | // 找到GraphicInfo文件 127 | // 获取对应版本号 GraphicInfo(*).bin 128 | VersionInfo versionInfo = AnalysisVersion("graphicinfo", fileInfo); 129 | // 判断是否存在对应graphic文件,忽略大小写 130 | string graphicFileName = "graphic" + versionInfo.FullVersion + ".bin"; 131 | FileInfo graphicFileInfo = GetFileInfoByName(fileInfo.Directory, graphicFileName); 132 | if (!graphicFileInfo.Exists) 133 | { 134 | throw new Exception("找不到对应的图档文件: " + fileInfo.FullName); 135 | } 136 | FilePair filePair = new FilePair() 137 | { 138 | InfoFile = fileInfo, 139 | DataFile = graphicFileInfo, 140 | Version = versionInfo.Version ?? Version 141 | }; 142 | _graphicFilePairs.Add(filePair); 143 | }else if (fileInfo.Name.StartsWith("animeinfo", StringComparison.OrdinalIgnoreCase)) 144 | { 145 | // 找到AnimeInfo文件 146 | // 获取对应版本号 AnimeInfo(*).bin 147 | VersionInfo versionInfo = AnalysisVersion("animeinfo", fileInfo); 148 | // 判断是否存在对应anime文件 149 | string animeFileName = "anime" + versionInfo.FullVersion + ".bin"; 150 | FileInfo animeFileInfo = GetFileInfoByName(fileInfo.Directory, animeFileName); 151 | if (!animeFileInfo.Exists) 152 | { 153 | throw new Exception("找不到对应的动画文件: " + fileInfo.FullName); 154 | } 155 | FilePair filePair = new FilePair() 156 | { 157 | InfoFile = fileInfo, 158 | DataFile = animeFileInfo, 159 | Version = versionInfo.Version ?? Version 160 | }; 161 | _animeFilePairs.Add(filePair); 162 | } 163 | } 164 | } 165 | 166 | // 忽略大小写获取对应文件 167 | private static FileInfo GetFileInfoByName(DirectoryInfo directoryInfo,string fileName) 168 | { 169 | FileInfo[] fileInfos = directoryInfo.GetFiles(); 170 | foreach (FileInfo fileInfo in fileInfos) 171 | { 172 | if (fileInfo.Name.Equals(fileName, StringComparison.OrdinalIgnoreCase)) 173 | { 174 | return fileInfo; 175 | } 176 | } 177 | 178 | return null; 179 | } 180 | 181 | // 获取图档数据 182 | public static GraphicDetail GetGraphicDetail(uint serial,int palet = 0,bool linerFilter = false) 183 | { 184 | GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(serial); 185 | if (graphicInfoData == null) return null; 186 | return GraphicData.GetGraphicDetail(graphicInfoData, palet, -1, linerFilter); 187 | } 188 | 189 | // 获取图档数据 190 | public static GraphicDetail GetGraphicDetailByIndex(string Version,uint index,int palet = 0,bool linerFilter = false) 191 | { 192 | GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(Version, index); 193 | if (graphicInfoData == null) return null; 194 | return GraphicData.GetGraphicDetail(graphicInfoData, palet, -1, linerFilter); 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /CrossgateToolkit/GraphicInfo.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * 魔力宝贝图档解析脚本 - CGTool 3 | * 4 | * @Author HonorLee (dev@honorlee.me) 5 | * @Version 1.0 (2023-04-15) 6 | * @License GPL-3.0 7 | * 8 | * GraphicInfo.cs 图档索引解析类 9 | */ 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using System.IO; 14 | using UnityEngine; 15 | 16 | namespace CrossgateToolkit 17 | { 18 | //GraphicInfo数据块 19 | public class GraphicInfoData 20 | { 21 | // GraphicInfo基础数据 22 | //4 bytes 索引 23 | public uint Index; 24 | //4 bytes Graphic 地址 25 | public uint Addr; 26 | //4 bytes Graphic 数据长度 27 | public uint Length; 28 | //4 bytes Graphic 偏移 - X 29 | public int OffsetX; 30 | //4 bytes Graphic 偏移 - Y 31 | public int OffsetY; 32 | //4 bytes Graphic 宽 33 | public uint Width; 34 | //4 bytes Graphic 高 35 | public uint Height; 36 | //4 bytes Graphic East占地 37 | public int East; 38 | //4 bytes Graphic South 占地 39 | public int South; 40 | //bool 穿越标识 41 | public bool Blocked; 42 | //1 byte 作为地面无层级遮挡[Test] 43 | public bool AsGround; 44 | //4 bytes 未知标识 45 | public byte[] Unknow; 46 | //4 bytes 编号 47 | public uint Serial; 48 | 49 | // GraphicInfo附加数据 50 | // GraphicInfo对应Graphic文件流读取器 51 | public BinaryReader GraphicReader; 52 | public byte VERSION_FLAG; 53 | //已解压的调色板索引 54 | public byte[] UnpackedPaletIndex; 55 | public List InnerPalet; 56 | 57 | public bool IsEncrypted; 58 | public EncryptInfo EncryptInfo; 59 | } 60 | 61 | public class EncryptInfo 62 | { 63 | public long PwdIndex; 64 | public int PwdLen; 65 | public byte[] Pwd; 66 | 67 | } 68 | 69 | public class GraphicInfo:MonoBehaviour 70 | { 71 | //索引字典 Serial -> GraphicInfoData 72 | private static readonly Dictionary _cache = new Dictionary(); 73 | // private static readonly Dictionary _indexCache = new Dictionary(); 74 | 75 | private static readonly Dictionary> _indexCache = new Dictionary>(); 76 | public static void Init(string Version,FileInfo graphicInfoFile,FileInfo graphicFile) 77 | { 78 | if(!_indexCache.ContainsKey(Version)) _indexCache.Add(Version,new Dictionary()); 79 | //创建流读取器 80 | FileStream fileStream = graphicInfoFile.OpenRead(); 81 | BinaryReader fileReader = new BinaryReader(fileStream); 82 | 83 | FileStream graphicFileStream = graphicFile.OpenRead(); 84 | BinaryReader graphicFileReader = new BinaryReader(graphicFileStream); 85 | 86 | byte[] head = graphicFileReader.ReadBytes(3); 87 | bool isEncrypted = false; 88 | EncryptInfo encryptInfo = null; 89 | if (head[0] == 0x52 && head[1] == 0x44) isEncrypted = false; 90 | else 91 | { 92 | isEncrypted = true; 93 | bool fromHead = head[0] % 2 == 0; 94 | encryptInfo = new EncryptInfo(); 95 | encryptInfo.PwdLen = head[2]; 96 | 97 | // 密码索引 98 | if (fromHead) 99 | { 100 | encryptInfo.PwdIndex = 3 + head[1]; 101 | } 102 | else 103 | { 104 | // 获取文件大小 105 | long fileSize = graphicFile.Length; 106 | encryptInfo.PwdIndex = fileSize - encryptInfo.PwdLen - 3 - head[1] + 3; 107 | } 108 | 109 | // 获取密码 110 | graphicFileStream.Position = encryptInfo.PwdIndex; 111 | encryptInfo.Pwd = graphicFileReader.ReadBytes(encryptInfo.PwdLen); 112 | 113 | // 密码解密 114 | byte[] keyCodes = new byte[CGTool.ENCRYPT_KEY.Length]; 115 | for (var i = 0; i < CGTool.ENCRYPT_KEY.Length; i++) 116 | { 117 | // 获取秘钥的ASCII码 118 | byte code = (byte)(CGTool.ENCRYPT_KEY[i]); 119 | keyCodes[i] = code; 120 | } 121 | 122 | // 解密密码 123 | for (int i = 0; i < encryptInfo.PwdLen; i++) 124 | { 125 | for (var i1 = 0; i1 < keyCodes.Length; i1++) 126 | { 127 | encryptInfo.Pwd[i] = (byte)(encryptInfo.Pwd[i] ^ keyCodes[i1]); 128 | 129 | } 130 | } 131 | } 132 | 133 | //解析Info数据表 134 | long DataLength = fileStream.Length/40; 135 | for (int i = 0; i < DataLength; i++) 136 | { 137 | GraphicInfoData graphicInfoData = new GraphicInfoData(); 138 | graphicInfoData.Index = BitConverter.ToUInt32(fileReader.ReadBytes(4),0); 139 | graphicInfoData.Addr = BitConverter.ToUInt32(fileReader.ReadBytes(4),0); 140 | graphicInfoData.Length = BitConverter.ToUInt32(fileReader.ReadBytes(4),0); 141 | graphicInfoData.OffsetX = BitConverter.ToInt32(fileReader.ReadBytes(4),0); 142 | graphicInfoData.OffsetY = BitConverter.ToInt32(fileReader.ReadBytes(4),0); 143 | graphicInfoData.Width = BitConverter.ToUInt32(fileReader.ReadBytes(4),0); 144 | graphicInfoData.Height = BitConverter.ToUInt32(fileReader.ReadBytes(4),0); 145 | graphicInfoData.East = fileReader.ReadByte(); 146 | graphicInfoData.South = fileReader.ReadByte(); 147 | graphicInfoData.Blocked = fileReader.ReadByte() % 2 == 0; 148 | graphicInfoData.AsGround = fileReader.ReadByte() == 1; 149 | graphicInfoData.Unknow = fileReader.ReadBytes(4); 150 | graphicInfoData.Serial = BitConverter.ToUInt32(fileReader.ReadBytes(4),0); 151 | graphicInfoData.GraphicReader = graphicFileReader; 152 | graphicInfoData.IsEncrypted = isEncrypted; 153 | graphicInfoData.EncryptInfo = encryptInfo; 154 | // if (graphicInfoData.Serial >= 220000 && graphicInfoData.Width == 64 && graphicInfoData.Height == 47 && graphicInfoData.Blocked) 155 | // { 156 | // Debug.LogError(graphicInfoData.Serial + "穿越" + Blocked); 157 | // } 158 | 159 | //建立Index映射表 160 | _indexCache[Version][graphicInfoData.Index] = graphicInfoData; 161 | 162 | //建立Serial映射表 163 | if (graphicInfoData.Serial != 0) _cache[graphicInfoData.Serial] = graphicInfoData; 164 | 165 | // _logger.Write("Index: " + graphicInfoData.Index + " Addr: " + graphicInfoData.Addr + 166 | // " Width: " + graphicInfoData.Width + 167 | // " Height: " + graphicInfoData.Height + 168 | // " OffsetX: " + graphicInfoData.OffsetX + 169 | // " OffsetY: " + graphicInfoData.OffsetY + 170 | // " East: " + graphicInfoData.East + 171 | // " South: " + graphicInfoData.South + 172 | // " Blocked: " + graphicInfoData.Blocked + 173 | // " Unknow: " + BitConverter.ToString(graphicInfoData.Unknow).Replace("-", ",") + 174 | // " MapSerial: " + graphicInfoData.MapSerial); 175 | } 176 | 177 | Debug.Log("[CGTool] 加载GraphicInfo - 文件: [" + 178 | // (Graphic.Flag_HighVersion[Version] ? "H" : "N") + "] [" + 179 | Version + "] " + 180 | graphicInfoFile.Name + " 贴图总量: " + DataLength + (isEncrypted ? " 加密图档" : "")); 181 | } 182 | 183 | //获取GraphicInfoData 184 | public static GraphicInfoData GetGraphicInfoData(uint Serial) 185 | { 186 | _cache.TryGetValue(Serial, out var graphicInfoData); 187 | return graphicInfoData; 188 | } 189 | 190 | public static GraphicInfoData GetGraphicInfoDataByIndex(string Version,uint Index) 191 | { 192 | _indexCache.TryGetValue(Version, out var indexDict); 193 | if(indexDict == null) throw new Exception("找不到对应版本的GraphicInfo数据"); 194 | indexDict.TryGetValue(Index, out var graphicInfoData); 195 | return graphicInfoData; 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crossgate-魔力宝贝 2 | ## Unity C# 图档解析库 3 | 4 | ## 1、开源目的 5 | 本脚本旨在学习研究```Crossgate``` ```魔力宝贝``` 图档bin文件的解压与使用,相关资料来源于互联网文章与相关技术大佬指导 6 | 7 | 再次感谢```阿伍```等在互联网上分享相关解压、算法解析等教学文章的技术大佬所提供的帮助 8 | 9 | 本脚本遵照GPL共享协议,可随意修改、调整代码学习使用 10 | 11 | 请务删除或修改文档或源代码中相关版权声明信息,且严禁用于商业项目 12 | 13 | 因利用本脚本盈利或其他行为导致的任何商业版权纠纷,脚本作者不承担任何责任或损失 14 | 15 | 本解析库原始发布地址: [https://git.honorlee.me/HonorLee/CGTool](https://git.honorlee.me/HonorLee/CGTool) 16 | 17 | 同步更新至Github: [https://github.com/HonorLee-cn/CGTool](https://github.com/HonorLee-cn/CGTool) 18 | 19 | 如有任何问题请至Github提交Issues或联系作者 20 | 21 | ![预览](Preview/Preview.png) 22 | 23 | ## 2、功能支持 24 | > 当前版本目前已支持 魔力宝贝3.7-龙之沙漏 及以下版本的图档解析,以及 4.0 版本以上图档、动画数据解析 25 | > 26 | > 注意:当前版本 4.0 及以上地图暂不支持 27 | > 28 | > 目前版本支持以下功能: 29 | > 30 | > * `GraphicInfo` [图档索引解析](#获取图档索引数据) 31 | > * `GraphicData` [图档数据解析](#获取图档实体数据) 32 | > * `Palet` 调色板数据解析 33 | > * `Map` [服务端/客户端 图数据解析](#获取地图数据) 34 | > * `Audio` [音频索引及加载](#播放音频) 35 | > * `AnimeInfo` 动画索引解析 36 | > * `Anime` 动画数据解析 37 | > * `AnimePlayer` [动画播放器挂载组件](#动画播放) 38 | > * `AnimePlayer` 动画关键帧(攻击/攻击完成)事件回调 39 | > * `AnimePlayer` 音频帧事件回调 40 | > * `DynamicGraphic` [动态图集](#动态图集) 41 | 42 |
43 |
44 |
45 |
46 | 47 |
48 | 49 | ## 3、使用说明 50 | 51 | ### 基本环境 52 | 53 | 请确认Unity已安装以下Package包: 54 | ``` 55 | "dependencies": { 56 | "com.unity.burst": "1.6.0", 57 | "com.unity.visualscripting": "1.9.0" 58 | } 59 | ``` 60 | 61 | 克隆当前仓库或下载zip包解压,将 CrossgateToolkit 文件夹放置于Unity项目文件夹内引用 62 | 63 | 可直接下载Release中unitypackage直接导入 64 | 65 | ### 工具库说明 66 | 67 | 最新 V2.0 版本已移除对魔力宝贝原版本的强绑定,初始化程序将根据目标路径进行自动分析 68 | 69 | 规划图档目录结构时,图档根目录下建议以数字版本号方式命名不同版本图档子目录 70 | 71 | CGTool在初始化时对所配置图档根目录进行扫描,并按照``根目录优先``、``子目录按字符排序``方式依次加载并初始化图档数据 72 | 73 | 所涉及的所有Index则为图档序号、Serial为图档或动画的具体编号而非索引档中序号,实际使用时请注意区分 74 | 75 | 76 | 77 | 其他相关部分会逐渐更新完善 78 | 79 | ### 框架初始化 80 | 在入口或初始化脚本头部引入CGTool初始化文件 81 | ```csharp 82 | using CrossgateToolkit; 83 | ``` 84 | 并在相关初始化位置对CGTool进行初始化 85 | ```csharp 86 | // 配置Crossgate相关资源路径,如跳过则默认为 Environment.CurrentDirectory 下相关 目录 87 | CGTool.PATH = new CGTool.CGPath() 88 | { 89 | // 调色板目录,不可省略 90 | PAL = Application.persistentDataPath + "/pal", 91 | // BIN图档目录,包含图档索引、图档文件、动画索引、动画文件等根目录 92 | // 初始化时会自动便利查询分析所有文件数据,不可省略 93 | BIN = Application.persistentDataPath + "/bin", 94 | // 地图文件目录,省略则不对地图数据初始化 95 | MAP = Application.persistentDataPath + "/map", 96 | // 音频文件目录,省略则不对音频初始化 97 | BGM = Application.persistentDataPath + "/bgm", 98 | AUDIO = Application.persistentDataPath + "/se" 99 | }; 100 | // 初始化 101 | CGTool.Init(); 102 | ``` 103 | CGTool初始化时,会自动对相关索引Info文件进行解析,请根据实际所采用版本情况,对脚本代码中解析相关的文件名称进行修改调整 104 | 105 | 106 | ### 获取图档索引数据 107 | (图档基本索引数据属性信息) 108 | ```csharp 109 | // 正常通过编号获取图档信息,无需版本号(常规图档) 110 | GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(uint Serial); 111 | 112 | // 通过索引获取图档信息,带版本号(特殊无编号图档获取,如动画获取每帧图档时) 113 | GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(string version, uint Serial); 114 | ``` 115 | 116 | ### 获取图档实体数据 117 | (图档实际数据,包含图像Sprite资源) 118 | ```csharp 119 | // 直接通过编号获取 120 | GraphicDetail graphicDetail = Graphic.GetGraphicDetail(uint serial,int palet = 0); 121 | // 或 通过GraphicInfoData获取 122 | GraphicDetail graphicDetail = GraphicData.GetGraphicDetail(GraphicInfoData graphicInfoData, int palet = 0); 123 | /** 124 | * 使用说明: 125 | * 所有通过Graphic获取的图档Sprite均已做偏移处理,可直接使用 126 | * 需自行判断图档是否存在,并处理图档不存在的情况 127 | * 1.获取指定编号的图档索引信息 128 | * 2.根据获取到的索引取得图档数据 129 | * 3.使用图档数据中的Sprite资源进行绘制 130 | */ 131 | 132 | GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(Serial); 133 | GraphicDetail graphicDetail = GraphicData.GetGraphicDetail(graphicInfoData ,0); 134 | SpriteRenderer(Image).sprite = graphicDetail.Sprite; 135 | ``` 136 | 137 | ### 获取地图数据 138 | ```csharp 139 | // 通过编号获取地图数据,地图数据中包含地面及地上物件数据以及寻路用的二维数组 140 | // 可自行阅读源码查询相关属性成员和使用方式 141 | Map.MapInfo mapInfo = Map.GetMap(uint Serial); 142 | ``` 143 | 144 | ### 图档合批 145 | 146 | 为减少渲染时的Drawcall和Batchs动态合批数量提高性能并降低内存消耗,工具库提供了大量图档合批(并)处理方法 147 | 148 | 图档合并时,会自动根据每个图档图像由小到大进行排序处理,以最大限度将多个图档合并至一个或多个稍大的Texture2D中 149 | 150 | ```csharp 151 | /** 152 | * 合批图档 153 | * 通过指定图档序列,对图档进行合批处理,并返回合批后的图档数据 154 | * @param graphicInfoDatas 图档索引数据序列 155 | * @param AsSerialBatch 以图档编号而非索引号返回合批数据,默认为true,反之则以图档索引号返回数据 156 | * @param palet 调色板序号 157 | * @param subPalet 副调色板序号,此项针对动画数据 158 | * @param linear 以线性过滤方式生成图集 159 | * @param maxTextureSize 单个Texture最大尺寸,地面数据建议2048,物件数据建议低于4096 160 | * @param padding 图档间隔,可以有效避免图档渲染时出现多余的黑边或像素黏连 161 | * @param compress 启用压缩 162 | * @return Dictionary 合批后的图档数据,Key(unit)为图档数据编号(或AsSerialBatch为false时为图档序号),Value为图档数据 163 | */ 164 | GraphicData.BakeGraphics( 165 | List graphicInfoDatas, 166 | int palet = 0, 167 | int maxTextureSize = 2048, 168 | int padding = 0) 169 | ``` 170 | 171 | ### 地图地面/物件图档合批数据 172 | 针对地图图档部分合批提供了相应的简化方法,可以酌情使用 173 | ```csharp 174 | /** 175 | * * 地面数据将拼合成一个或多个2048*2048尺寸Texture2D 176 | * * 物件(建筑等)拼合成一个或多个不大于4096*4096尺寸Texture2D 177 | * 另: 由于4.0后地图模式变动,部分地图图档过大,所以这个方法可能不适用于4.0后的地图 178 | */ 179 | 180 | // 地面合批 181 | Dictionary MapGroundSerialDic = 182 | Map.BakeGrounds( // <= 合并地面图形 183 | List graphicInfoDatas, 184 | int PaletIndex = 0 185 | ); 186 | 187 | // 物件合批 188 | Dictionary MapObjectSerialDic = 189 | Graphic.BakeObjects( // <= 合并物件图形 190 | List graphicInfoDatas, 191 | int PaletIndex = 0 192 | ); 193 | ``` 194 | ![地面合并效果](Preview/MapGroundMix.png) 195 | ![物件合并效果](Preview/MapObjectMix.png) 196 | ![资源合并后效果](Preview/batches.png) 197 | 198 | ### 播放音频 199 | ```csharp 200 | CGTool.Audio.Play(AudioSource audioSource,Type type, int serial) 201 | 202 | //播放背景音乐 203 | CGTool.Audio.Play(AudioSource audioSource,Audio.Type.BGM,int serial); 204 | //获取音效音频 205 | CGTool.Audio.Play(AudioSource audioSource,Audio.Type.EFFECT,int serial); 206 | ``` 207 | 208 | ### 动画播放 209 | ```csharp 210 | /** 211 | * 动画播放器,用于播放CG动画,支持多动画队列播放 212 | * 1.3更新后已无需手动挂载SpriteRenderer、Image组件,程序会自动处理 213 | * 只需将AnimePlayer挂载到任意GameObject上即可 214 | * 可手动指定渲染方式是否以Image组件渲染 215 | * 可选择是否对序列帧图像进行合批(建议开启) 216 | * 217 | * 动画解析Anime类中包含以下多个枚举预设: 218 | * DirectionType 方向类型,含8个不同方向 219 | * ActionType 动作类型,含20个不同动作 220 | * EffectType 动作效果,含Hit和HitOver两种判定 221 | * PlayType 播放类型,含Loop、Once、OnceAndDestory三种类型 222 | * 223 | * 当动画播放完成后会自动调用onFinishCallback回调函数 224 | * 另外可指定onActionListener和onAudioListener监听动画动作帧和音频帧相关判定 225 | * 226 | * 目前已知的动作帧有: 227 | * 击中 Hit (未结束攻击动作,如小石像、黄蜂、绿螳螂等单次攻击动作中有多次击中效果) 228 | * 伤害结算 HitOver 229 | */ 230 | 231 | AnimePlayer player = GetComponent(); 232 | 233 | /** 234 | * 播放动画,调用此方法将会清空当前播放队列,调用完成可通过链式调用nextPlay方法添加动画到播放队列 235 | * @param Serial 动画序列号 236 | * @param Direction 动画方向 237 | * @param ActionType 动画动作 238 | * @param PlayType 播放类型 Loop / Once / OnceAndDestory 239 | * @param Speed 播放速度倍率,以 1s 为单位基准,根据动画帧率计算实际播放周期时长 240 | * @param onFinishCallback 动画结束回调 241 | * @return AnimePlayer 242 | */ 243 | 244 | player.play( 245 | uint Serial, 246 | Anime.DirectionType Direction = Anime.DirectionType.North, 247 | Anime.ActionType actionType = Anime.ActionType.Stand, 248 | Anime.PlayType playType = Anime.PlayType.Once, 249 | float Speed = 1f, 250 | AnimeCallback onFinishCallback = null 251 | ); 252 | 253 | // 简化播放: 此方法大多数情况下用以播放特效动画,没有方向和动作类型 254 | player.play( 255 | uint Serial, 256 | Anime.PlayType playType, 257 | float speed = 1f, 258 | AnimeCallback onFinishCallback = null 259 | ); 260 | 261 | // 播放一次 262 | player.playOnce( 263 | Anime.DirectionType directionType, 264 | Anime.ActionType actionType, 265 | float Speed=1f, 266 | AnimeCallback onFinishCallback=null 267 | ); 268 | 269 | // 循环播放 270 | player.playLoop( 271 | Anime.DirectionType directionType, 272 | Anime.ActionType actionType, 273 | float Speed=1f, 274 | AnimeCallback onFinishCallback=null 275 | ); 276 | 277 | /** 278 | * 可通过setter方法设置动画 279 | * 通过setter方法设置的动画将使用以下默认配置 280 | * DirectionType = DirectionType.North 281 | * ActionType = ActionType.Stand 282 | * PlayType = PlayType.Loop 283 | * Speed = 1f 284 | */ 285 | player.Serial = uint AnimeSerial; 286 | 287 | // 设置帧动效反馈监听 288 | player.onEffectListener = effect => {...}; 289 | 290 | // 设置帧音效反馈监听 291 | player.onAudioListener = audioIndex => {...}; 292 | 293 | // 链式调用添加动作队列 294 | player.play(...params).nextPlay(...params); 295 | 296 | // 动态修改动画所用的调色板索引 297 | player.PaletIndex = int PaletIndex; 298 | 299 | // 动态修改动画播放类型 300 | player.PlayType = Anime.PlayType; 301 | 302 | // 动态调整当前动画方向 303 | player.DirectionType = Anime.DirectionType; 304 | 305 | // 动态调整当前动画动作 306 | player.ActionType = Anime.ActionType; 307 | 308 | // 动画帧延时,动态修改当前动画,延长每帧之间的时间间隔(此方法定义有歧义,后续更新调整) 309 | player.DelayPlay(float delayTime) 310 | 311 | // 停止动画 312 | player.Stop(); 313 | 314 | ``` 315 | 316 | ### 动态图集 317 | 比```图档合批```更加灵活的动态图集功能,在运行时进行图档图集的写入处理操作 318 | 319 | 主要针对网游地图的动态获取增加的可扩展动态图集,包含图集建立、自维护和清理 320 | 321 | 每个动态图集对象内部会根据图档情况进行动态扩充,并采用相对高效的可用空间搜索方式进行图集填充,尽量减少空间浪费 322 | 323 | 动态图集固定采用 ```图集缓存 + 二级缓存模式```,并采用Unity的Graphic异步复制纹理方式写入图集,最大限度降低图集使用过程中CPU的计算量 324 | 325 | ```csharp 326 | /// 327 | /// 创建动态图集 328 | /// 329 | /// 图集最大宽度 330 | /// 图集最大高度 331 | /// 图集各图档间隔 332 | /// 调色板编号 333 | /// 线性过滤 334 | /// 以100的PPU方式生成Sprite对象 335 | /// 当图集对象无可用空间时,对Texture进行压缩 336 | 337 | DynamicGraphic( 338 | int GraphicWidth, 339 | int GraphicHeight, 340 | int GraphicPadding = 0, 341 | int palet = 0, 342 | bool linear = false, 343 | bool ppu100 = false, 344 | bool compressWhenFull = false) 345 | 346 | ``` 347 | 348 | ```csharp 349 | // 创建一个1024*1024尺寸,间距 0 ,调色板编号 0,非线性过滤,输出PPU为100的的动态图集,且进行压缩 350 | DynamicGraphic dynamicGraphic = new DynamicGraphic(1024, 1024, 0, 0, false, true, true); 351 | 352 | // 通过动态图集获取图像 353 | Sprite sprite = dynamicGraphic.GetSprite(uint Serial); 354 | 355 | // 通过协程方式获取图像 356 | StartCoroutine(dynamicGraphic.GetSpriteSync(uint Serial,(sprite)=>{ 357 | // 使用回调Sprite 358 | })); 359 | 360 | // 图集清理 361 | dynamicGraphic.Clear(bool GC = false); 362 | ``` 363 | 364 | ### 其他 365 | 请根据情况自行探索修改代码适应应用场景 366 | 367 | 368 | 369 | ## 4、更新日志 370 | 371 | ### v 3.1 372 | > `UPD` 地图Object层对象及地图单位Z轴算法修正 373 | 374 | ### v 3.0 375 | > `ADD` 本次大更新主要是性能优化及功能性更新,部分方法调用参数发生变化 376 | > 377 | > `ADD` 图档Sprite获取以及动画使用增加线性过滤参数 378 | > 379 | > `ADD` 动画使用增加PPU100、线性过滤、图集压缩等参数选项 380 | > 381 | > `ADD` 图档获取Sprite时可通过GraphicDetail.SpritePPU100获取PPU为100的Sprite对象 382 | > 383 | > `ADD` 增加动态图集 `DynamicGraphic` 类,具体使用方法请参考README示例或查阅代码 384 | > 385 | > `UPD` 调整部分代码和图档获取,性能增强,降低CPU压力,减少内存占用等 386 | 387 | ### v 2.6 388 | > `UPD` 修改了Anime初始化过程,将预载全部动画帧修改为读取时加载,减少初始化时间 389 | > 390 | > `UPD` Anime微调部分逻辑处理,并将动作类型中```Stand```调整为```Idle``` 391 | > 392 | > `FIX` Anime修正回调和nextplay链式调用队列控制 393 | 394 | ### v 2.5 395 | > `FIX` Audio播放代码忘了补充 396 | > 397 | > `UPD` 加入BLiner过滤支持,可以在获取图档时获取对应过滤图像,同时对AnimePlayer增加Liner可选项 398 | 399 | ### v 2.4 400 | > `FIX` 继续调整目录分析,处理部分特殊情况 401 | > 402 | > `FIX` 对于修改过的Anime进行适配,修复高低版本动画数据混合情况解析报错问题 403 | 404 | ### v 2.3 405 | > `FIX` 调整高版本动画播放标记、翻转问题 406 | 407 | ### v 2.2 408 | > `ADD` 增加 4.0 版本(乐园之卵)及后续版本图档、动画解析 409 | > 410 | > `UPD` 调整图档目录版本号分析过程,以更好的适应多种图档目录结构 411 | 412 | ### v 2.1 413 | > `UPD` 图档合并方法进行统一处理,并增加地图相关简便方法 414 | 415 | ### v 2.0 416 | > `ADD` 修改初始化方法以支持更复杂的图档文件建构 417 | > 418 | > `UPD` 图档解析支持多层目录结构并能自动识别加载,方便对图档进行扩充升级,建议根据版本号对图档子目录进行命名 419 | > 420 | > `UPD` 图档获取和加载方法优化,减少无用参数 421 | > 422 | > `UPD` 根据新的加载方式调整相关工具库代码以适应新的加载方式 423 | 424 | ### v 1.7 425 | > `ADD` 加入地图物件合批处理 426 | 427 | ### v 1.6 428 | > `ADD` 加入客户端地图读取支持,同时附加了客户端地图文件缺失的名字和调色版映射表 429 | > 430 | > `UPD` Anime合批处理图形之间增加间隔,避免出现像素黏连 431 | > 432 | > `UPD` AnimePlayer挂载件预留FrameTexture属性可在Editor中查看合批的图像 433 | > 434 | > `UPD` CGTool入口调整,可指定bin目录位置 435 | 436 | ### v 1.5 437 | > `UPD` Anime序列帧合批忘了考虑不同调色板的问题,现已增加相关处理 438 | 439 | ### v 1.4 440 | > `ADD` 加入Anime序列帧合批,挂载AnimePlayer后可手动设置是否开启合批(建议开启) 441 | 442 | ### v 1.3 443 | > `UPD` 优化AnimePlayer组件的挂载和使用方式 444 | > 445 | > `UPD` 优化AnimePlayer动画播放器,增加动画相关处理方法 446 | > 447 | > `UPD` 更新README说明文档,增加、调整使用说明 448 | > 449 | 450 | ### v 1.2 451 | 452 | > `FIX` 修正文件加载时判断为正则,避免因使用不同版本bin导致加载报错问题 453 | 454 | ### v 1.1 455 | > `ADD` 音频索引及加载AudioTool 456 | > 457 | > `ADD` 动画播放器添加对Image渲染支持,用以支持GUI动画播放 458 | > 459 | > `ADD` Graphic增加地面图档动态合批 460 | > 461 | > `ADD` Anime增加动画帧动态合批方法 462 | > 463 | > `UPD` 优化Graphic解析,统一改为RGBA4444模式,以减少内存占用 464 | > 465 | > `UPD` 重新整理初始化代码,优化初始化流程 466 | > 467 | > `UPD` 优化动画播放器,增加动画相关处理方法 468 | > 469 | > `UPD` 动画播放器添加对Image渲染支持,用以支持GUI动画播放 470 | > 471 | > `FIX` 修复动画序列中攻击判定、音频序列解析方式错误的问题 472 | 473 | ### v 1.0 474 | 475 | > `ADD` 脚本初始化 476 | > 477 | > `ADD` 图档索引GraphicInfo文件解析 478 | > 479 | > `ADD` 图档Graphic文件数据解析 480 | > 481 | > `ADD` 调色板Palet文件解析 482 | > 483 | > `ADD` 动画索引AnimeInfo文件解析 484 | > 485 | > `ADD` 动画Anime文件数据解析 486 | > 487 | > `ADD` 服务端地图文件解析 488 | 489 | 490 | 491 | ## 5、待处理 492 | 493 | - 支援 4.0 以上版本图档解析 494 | - 其他未知 495 | - 优化 496 | 497 | ## LICENSE 498 | This project is licensed under the GPL license. Copyrights are respective of each contributor listed at the beginning of each definition file. 499 | 500 | 501 | -------------------------------------------------------------------------------- /CrossgateToolkit/Anime.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * 魔力宝贝图档解析脚本 - CGTool 3 | * 4 | * @Author HonorLee (dev@honorlee.me) 5 | * @Version 1.0 (2023-04-15) 6 | * @License GPL-3.0 7 | * 8 | * Anime.cs 动画基础类 9 | */ 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using System.IO; 14 | using System.Linq; 15 | using UnityEngine; 16 | 17 | namespace CrossgateToolkit 18 | { 19 | //动画信息 20 | public class AnimeInfo 21 | { 22 | // 版本 23 | public string Version; 24 | //4 bytes 动画序号 25 | public uint Serial; 26 | //4 bytes 动画文件地址 27 | public uint Addr; 28 | //2 bytes 动作数量 29 | public int ActionCount; 30 | //2 bytes 未知字节 31 | public byte[] Unknow; 32 | //动画数据 Direction -> ActionType -> AnimeData 33 | public Dictionary> AnimeDatas; 34 | // 数据读取对象 35 | public BinaryReader DataReader; 36 | } 37 | 38 | //动画帧数据 39 | public class AnimeFrameInfo 40 | { 41 | //图档编号 42 | public uint GraphicIndex; 43 | //宽度 44 | public int Width; 45 | //高度 46 | public int Height; 47 | //偏移X 48 | public int OffsetX; 49 | //偏移Y 50 | public int OffsetY; 51 | //音效编号 52 | public int AudioIndex; 53 | //动效编号 54 | public Anime.EffectType Effect; 55 | //GraphicInfo; 56 | public GraphicInfoData GraphicInfo; 57 | //动画Sprite 58 | // public Dictionary AnimeSprites = new Dictionary(); 59 | public Dictionary> AnimeSprites = new Dictionary>(); 60 | } 61 | 62 | //动画数据 63 | public class AnimeDetail 64 | { 65 | // 动画编号 66 | public uint Serial; 67 | // 动画版本 68 | public string Version; 69 | // 方向 70 | public int Direction; 71 | // 动作 72 | public int ActionType; 73 | // 动画循环时间 74 | public uint CycleTime; 75 | // 帧数 76 | public uint FrameCount; 77 | 78 | // 高版本 - 标识 79 | public bool IsHighVersion; 80 | // 高版本 - 调色板 81 | public int Palet; 82 | // 高版本 - 图像反转 83 | public AnimeFlag FLAG = AnimeFlag.NULL; 84 | // 高版本 - 结束标识 85 | public byte[] FLAG_END; 86 | // public Dictionary AnimeTextures = new Dictionary(); 87 | public Dictionary> AnimeTextures = new Dictionary>(); 88 | // public Texture2D AnimeTexture; 89 | public List AnimeFrameInfos; 90 | // public byte[] unknown; 91 | } 92 | 93 | [Flags] 94 | public enum AnimeFlag 95 | { 96 | NULL = 0, 97 | REVERSE_X = 1<<0, 98 | REVERSE_Y = 1<<1, 99 | LOCK_PAL = 1<<2, 100 | LIGHT_THROUGH = 1<<3 101 | } 102 | 103 | //动画相关Enum类型 104 | public class Anime : MonoBehaviour 105 | { 106 | //方向 107 | public enum DirectionType 108 | { 109 | NULL = -1, 110 | North = 0, 111 | NorthEast = 1, 112 | East = 2, 113 | SouthEast = 3, 114 | South = 4, 115 | SouthWest = 5, 116 | West = 6, 117 | NorthWest = 7 118 | } 119 | //方向九宫映射表 120 | public static DirectionType[,] DirectionTypeMap = new DirectionType[3,3] 121 | { 122 | {DirectionType.North,DirectionType.NorthEast,DirectionType.East}, 123 | {DirectionType.NorthWest,DirectionType.NULL,DirectionType.SouthEast}, 124 | {DirectionType.West,DirectionType.SouthWest,DirectionType.South} 125 | }; 126 | //动作 127 | public enum ActionType 128 | { 129 | NULL = -1, 130 | Idle = 0, 131 | Walk = 1, 132 | BeforeRun = 2, 133 | Run = 3, 134 | AfterRun = 4, 135 | Attack = 5, 136 | Magic = 6, 137 | Throw = 7, 138 | Hurt = 8, 139 | Defence = 9, 140 | Dead = 10, 141 | Sit = 11, 142 | Hi = 12, 143 | Happy = 13, 144 | Angry = 14, 145 | Sad = 15, 146 | Shake = 16, 147 | Rock = 17, 148 | Scissors = 18, 149 | Paper = 19, 150 | Fishing = 20, 151 | 152 | } 153 | //动效 154 | public enum EffectType 155 | { 156 | Hit =1, 157 | HitOver =2 158 | } 159 | 160 | public enum PlayType 161 | { 162 | Loop, 163 | Once, 164 | OnceAndDestroy 165 | } 166 | private static byte[] highVersionFlag = { 0xFF, 0xFF, 0xFF, 0xFF }; 167 | 168 | //动画列表缓存 Serial -> AnimeInfo 169 | private static Dictionary _animeInfoCache = new Dictionary(); 170 | 171 | //加载动画数据 172 | public static void Init(string Version,FileInfo animeInfoFile,FileInfo animeFile) 173 | { 174 | //创建流读取器 175 | FileStream infoFileStream = animeInfoFile.OpenRead(); 176 | FileStream dataFileStream = animeFile.OpenRead(); 177 | BinaryReader infoFileReader = new BinaryReader(infoFileStream); 178 | BinaryReader dataFileReader = new BinaryReader(dataFileStream); 179 | 180 | long DataLength = infoFileStream.Length / 12; 181 | 182 | // 循环初始化动画数据 183 | for (int i = 0; i < DataLength; i++) 184 | { 185 | //初始化对象 186 | AnimeInfo animeInfo = new AnimeInfo 187 | { 188 | Version = Version, 189 | Serial = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0), 190 | Addr = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0), 191 | ActionCount = infoFileReader.ReadUInt16(), 192 | Unknow = infoFileReader.ReadBytes(2) 193 | }; 194 | if (animeInfo.Addr > dataFileStream.Length) break; 195 | 196 | animeInfo.DataReader = dataFileReader; 197 | _animeInfoCache[animeInfo.Serial] = animeInfo; 198 | } 199 | infoFileReader.Dispose(); 200 | infoFileReader.Close(); 201 | infoFileStream.Close(); 202 | 203 | Debug.Log("[CGTool] 加载AnimeInfo - 文件: [" + 204 | // (Graphic.Flag_HighVersion[Version] ? "H" : "N") + "] [" + 205 | Version + "] " + 206 | animeInfoFile.Name + 207 | " 动画总量: " + DataLength); 208 | } 209 | 210 | private static void ReadAnimeData(AnimeInfo animeInfo) 211 | { 212 | animeInfo.DataReader.BaseStream.Position = animeInfo.Addr; 213 | animeInfo.AnimeDatas = new Dictionary>(); 214 | for (int j = 0; j < animeInfo.ActionCount; j++) 215 | { 216 | // 高版本标识 217 | bool isHighVersion = false; 218 | animeInfo.DataReader.BaseStream.Position += 16; 219 | if(animeInfo.DataReader.ReadBytes(4).SequenceEqual(highVersionFlag)) isHighVersion = true; 220 | animeInfo.DataReader.BaseStream.Position -= 20; 221 | 222 | AnimeDetail animeData = new AnimeDetail(); 223 | animeData.Version = animeInfo.Version; 224 | animeData.Serial = animeInfo.Serial; 225 | animeData.Direction = animeInfo.DataReader.ReadUInt16(); 226 | animeData.ActionType = animeInfo.DataReader.ReadUInt16(); 227 | animeData.CycleTime = BitConverter.ToUInt32(animeInfo.DataReader.ReadBytes(4),0); 228 | animeData.FrameCount = BitConverter.ToUInt32(animeInfo.DataReader.ReadBytes(4),0); 229 | 230 | // 高版本 231 | if (isHighVersion) 232 | { 233 | animeData.IsHighVersion = true; 234 | animeData.Palet = animeInfo.DataReader.ReadUInt16(); 235 | int flag = animeInfo.DataReader.ReadUInt16(); 236 | if (flag > 0) 237 | { 238 | if ((flag & 1) == (1 << 0)) animeData.FLAG |= AnimeFlag.REVERSE_X; 239 | if ((flag & 2) == (1 << 1)) animeData.FLAG |= AnimeFlag.REVERSE_Y; 240 | if ((flag & 4) == (1 << 2)) animeData.FLAG |= AnimeFlag.LOCK_PAL; 241 | if ((flag & 8) == (1 << 3)) animeData.FLAG |= AnimeFlag.LIGHT_THROUGH; 242 | } 243 | 244 | animeData.FLAG_END = animeInfo.DataReader.ReadBytes(4); 245 | } 246 | 247 | animeData.AnimeFrameInfos = new List(); 248 | 249 | // if (animeInfo.Index == 101201) Debug.Log("----------------------------------"); 250 | for (int k = 0; k < animeData.FrameCount; k++) 251 | { 252 | byte[] frameBytes = animeInfo.DataReader.ReadBytes(10); 253 | if (frameBytes.Length <10) break; 254 | BinaryReader frameReader = new BinaryReader(new MemoryStream(frameBytes)); 255 | AnimeFrameInfo animeFrameInfo = new AnimeFrameInfo(); 256 | //GraphicIndex序号 257 | animeFrameInfo.GraphicIndex = BitConverter.ToUInt32(frameReader.ReadBytes(4),0); 258 | animeFrameInfo.OffsetX = BitConverter.ToInt16(frameReader.ReadBytes(2),0); 259 | animeFrameInfo.OffsetY = BitConverter.ToInt16(frameReader.ReadBytes(2), 0); 260 | 261 | //标识位 262 | int flag = BitConverter.ToInt16(frameReader.ReadBytes(2),0); 263 | 264 | if (flag>20000) 265 | { 266 | //击打判定 267 | animeFrameInfo.Effect = EffectType.Hit; 268 | animeFrameInfo.AudioIndex = flag - 20000; 269 | } 270 | else if(flag>10000) 271 | { 272 | //攻击动作结束判定 273 | animeFrameInfo.Effect = EffectType.HitOver; 274 | animeFrameInfo.AudioIndex = flag - 10000; 275 | } 276 | else 277 | { 278 | animeFrameInfo.AudioIndex = flag; 279 | } 280 | animeData.AnimeFrameInfos.Add(animeFrameInfo); 281 | } 282 | animeData.FrameCount = (uint) animeData.AnimeFrameInfos.Count; 283 | 284 | if (!animeInfo.AnimeDatas.ContainsKey(animeData.Direction)) 285 | animeInfo.AnimeDatas.Add(animeData.Direction, new Dictionary()); 286 | 287 | animeInfo.AnimeDatas[animeData.Direction][animeData.ActionType] = animeData; 288 | } 289 | } 290 | 291 | //获取动画数据信息 292 | public static AnimeInfo GetAnimeInfo(uint serial) 293 | { 294 | _animeInfoCache.TryGetValue(serial, out AnimeInfo animeInfo); 295 | if (animeInfo is { AnimeDatas: null }) ReadAnimeData(animeInfo); 296 | return animeInfo; 297 | } 298 | 299 | //获取动画数据 300 | public static AnimeDetail GetAnimeDetail(uint serial,DirectionType Direction,ActionType Action) 301 | { 302 | AnimeInfo animeInfo = GetAnimeInfo(serial); 303 | if (animeInfo == null) return null; 304 | 305 | if (animeInfo.AnimeDatas.ContainsKey((int)Direction)) 306 | { 307 | if (animeInfo.AnimeDatas[(int) Direction].ContainsKey((int) Action)) 308 | { 309 | AnimeDetail animeDetail = animeInfo.AnimeDatas[(int) Direction][(int) Action]; 310 | // if(animeDetail.AnimeTexture == null) prepareAnimeFrames(animeDetail); 311 | return animeDetail; 312 | } 313 | } 314 | 315 | return null; 316 | } 317 | 318 | //预处理动画图形合批烘焙 319 | public static void BakeAnimeFrames(AnimeDetail animeDetail,int palet = 0, bool linear = false,bool compress = false) 320 | { 321 | // 查看是否存在缓存Texture数据 322 | animeDetail.AnimeTextures.TryGetValue(palet, out var textureDict); 323 | if(textureDict!=null) 324 | { 325 | if(textureDict.ContainsKey(linear)) return; 326 | } 327 | 328 | //所有帧的图形数据 329 | GraphicDetail[] graphicDetails = new GraphicDetail[animeDetail.FrameCount]; 330 | 331 | //合并后的Texture2D尺寸 332 | List graphicInfoDatas = new List(); 333 | Dictionary graphicInfoDataDict = new Dictionary(); 334 | int subPaletIndex = -1; 335 | if (animeDetail.IsHighVersion) subPaletIndex = (int)animeDetail.Serial; 336 | for (var i = 0; i < animeDetail.FrameCount; i++) 337 | { 338 | //载入图档 339 | GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(animeDetail.Version,animeDetail.AnimeFrameInfos[i].GraphicIndex); 340 | if (graphicInfoData == null) continue; 341 | graphicInfoDatas.Add(graphicInfoData); 342 | graphicInfoDataDict[graphicInfoData.Index] = graphicInfoData; 343 | animeDetail.AnimeFrameInfos[i].GraphicInfo = graphicInfoData; 344 | animeDetail.AnimeFrameInfos[i].OffsetX = (int) graphicInfoData.OffsetX; 345 | animeDetail.AnimeFrameInfos[i].OffsetY = (int) graphicInfoData.OffsetY; 346 | } 347 | 348 | Dictionary graphicDetailDict = 349 | GraphicData.BakeGraphics(graphicInfoDatas, false, palet, subPaletIndex, linear, 2048, 5, compress); 350 | Texture2D texture2dMix = null; 351 | for (var i = 0; i < animeDetail.FrameCount; i++) 352 | { 353 | graphicDetailDict.TryGetValue(animeDetail.AnimeFrameInfos[i].GraphicInfo.Index,out var graphicDetail); 354 | if(graphicDetail == null) continue; 355 | graphicDetails[i] = graphicDetail; 356 | if (texture2dMix == null) texture2dMix = graphicDetail.Sprite.texture; 357 | 358 | AnimeFrameInfo animeFrameInfo = animeDetail.AnimeFrameInfos[i]; 359 | animeFrameInfo.Width = (int) graphicDetail.Width; 360 | animeFrameInfo.Height = (int) graphicDetail.Height; 361 | if(!animeFrameInfo.AnimeSprites.ContainsKey(palet)) animeFrameInfo.AnimeSprites[palet] = new Dictionary(); 362 | if(!animeFrameInfo.AnimeSprites[palet].ContainsKey(linear)) animeFrameInfo.AnimeSprites[palet] 363 | .Add(linear,graphicDetail); 364 | } 365 | 366 | if(!animeDetail.AnimeTextures.ContainsKey(palet)) animeDetail.AnimeTextures.Add(palet,new Dictionary()); 367 | animeDetail.AnimeTextures[palet][linear] = texture2dMix; 368 | 369 | } 370 | 371 | 372 | } 373 | } -------------------------------------------------------------------------------- /CrossgateToolkit/Audio.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * 魔力宝贝图档解析脚本 - CGTool 3 | * 4 | * @Author HonorLee (dev@honorlee.me) 5 | * @Version 1.0 (2023-08-26) 6 | * @License GPL-3.0 7 | * 8 | * AudioTool.cs 音频工具 9 | * 本工具用于加载音频AudioClip,音频文件位于Assets/Resources/Audio目录下并使用Resources.Load加载 10 | * 请将Crossgate的音频目录bgm、se拷贝到Assets/Resources/Audio目录下 11 | * 如有其他需要可调整加载方式 12 | */ 13 | 14 | using System; 15 | using System.Collections; 16 | using System.Collections.Generic; 17 | using System.IO; 18 | using Unity.VisualScripting; 19 | using UnityEngine; 20 | using UnityEngine.Networking; 21 | 22 | namespace CrossgateToolkit 23 | { 24 | public class EffectPlayer : MonoBehaviour 25 | { 26 | public AudioSource audioSource; 27 | public delegate void OnAudioPlayEnd(); 28 | public OnAudioPlayEnd onAudioPlayEnd; 29 | private void Awake() 30 | { 31 | audioSource = gameObject.AddComponent(); 32 | audioSource.loop = false; 33 | audioSource.playOnAwake = false; 34 | } 35 | 36 | public void Play(AudioClip clip) 37 | { 38 | audioSource.clip = clip; 39 | audioSource.Play(); 40 | StartCoroutine(wait(clip.length)); 41 | } 42 | 43 | 44 | 45 | IEnumerator wait(float length) 46 | { 47 | yield return new WaitForSeconds(length + 0.3f); 48 | onAudioPlayEnd?.Invoke(); 49 | } 50 | 51 | 52 | } 53 | public static class Audio 54 | { 55 | 56 | // 背景音频缓存 57 | private static Dictionary _bgmDic = new Dictionary(); 58 | // 声效音频缓存 59 | private static Dictionary _effectDic = new Dictionary(); 60 | private static Queue _effectPlayerPool = new Queue(); 61 | private static GameObject _effectPlayerContainer; 62 | private static int lastEffectId = -1; 63 | private static int lastEffectTime = -1; 64 | public static float EffectVolume = 1f; 65 | public enum Type 66 | { 67 | BGM, 68 | EFFECT 69 | } 70 | // 播放指定类型、编号的音频AudioClip 71 | public static void Play(AudioSource audioSource,Type type, int id) 72 | { 73 | // 对于同时间大量同一音效的播放,只播放一次 74 | if (type == Type.EFFECT && id == lastEffectId && Time.time - lastEffectTime < 0.1f) return; 75 | AudioClip audioClip; 76 | Dictionary dic = type == Type.BGM ? _bgmDic : _effectDic; 77 | if (dic.TryGetValue(id, out audioClip)) 78 | { 79 | _playAudio(type,audioSource, audioClip); 80 | } 81 | else 82 | { 83 | Dictionary map = type == Type.BGM ? _bgmMap : _effectMap; 84 | if(map.TryGetValue(id, out string audioName)) 85 | { 86 | string path = type == Type.BGM ? CGTool.PATH.BGM : CGTool.PATH.AUDIO; 87 | if (string.IsNullOrEmpty(path)) 88 | { 89 | path = type == Type.BGM ? "Audio/bgm" : "Audio/se"; 90 | audioClip = Resources.Load(path + "/" + audioName); 91 | if (audioClip == null) return; 92 | 93 | dic[id] = audioClip; 94 | _playAudio(type,audioSource, audioClip); 95 | } 96 | else 97 | { 98 | DirectoryInfo directoryInfo = new DirectoryInfo(path); 99 | if(!directoryInfo.Exists) return; 100 | FileInfo[] files = directoryInfo.GetFiles(audioName + ".wav", SearchOption.AllDirectories); 101 | if (files.Length > 0) 102 | { 103 | string filePath = files[0].FullName; 104 | 105 | CoroutineRunner.instance.StartCoroutine(LoadAudioClipAsync(filePath, loadedAudioClip => 106 | { 107 | if (loadedAudioClip != null) 108 | { 109 | dic[id] = loadedAudioClip; 110 | _playAudio(type,audioSource, loadedAudioClip); 111 | } 112 | })); 113 | } 114 | } 115 | 116 | } 117 | } 118 | } 119 | 120 | private static void _playAudio(Type type,AudioSource audioSource, AudioClip audioClip) 121 | { 122 | if (type == Type.EFFECT && audioSource == null) 123 | { 124 | if(_effectPlayerContainer==null) _effectPlayerContainer = new GameObject("EffectPlayerContainer"); 125 | EffectPlayer effectPlayer = null; 126 | if (_effectPlayerPool.Count > 0) 127 | { 128 | effectPlayer = _effectPlayerPool.Dequeue(); 129 | } 130 | else 131 | { 132 | effectPlayer = new GameObject("EffectPlayer").AddComponent(); 133 | effectPlayer.transform.SetParent(_effectPlayerContainer.transform); 134 | effectPlayer.onAudioPlayEnd = () => 135 | { 136 | effectPlayer.audioSource.clip = null; 137 | _effectPlayerPool.Enqueue(effectPlayer); 138 | }; 139 | } 140 | effectPlayer.audioSource.volume = EffectVolume; 141 | effectPlayer.Play(audioClip); 142 | } 143 | else 144 | { 145 | audioSource.Stop(); 146 | audioSource.clip = audioClip; 147 | audioSource.Play(); 148 | } 149 | } 150 | 151 | private delegate void AudioClipLoaded(AudioClip audioClip); 152 | private static IEnumerator LoadAudioClipAsync(string filePath, AudioClipLoaded onAudioLoaded) 153 | { 154 | if (File.Exists(filePath)) 155 | { 156 | string audioURL = "file://" + filePath; 157 | 158 | using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(audioURL, AudioType.UNKNOWN)) 159 | { 160 | yield return www.SendWebRequest(); 161 | if (www.result == UnityWebRequest.Result.Success) 162 | { 163 | AudioClip audioClip = DownloadHandlerAudioClip.GetContent(www); 164 | onAudioLoaded?.Invoke(audioClip); 165 | } 166 | else 167 | { 168 | onAudioLoaded?.Invoke(null); 169 | } 170 | } 171 | } 172 | else 173 | { 174 | onAudioLoaded?.Invoke(null); 175 | } 176 | } 177 | 178 | private static Dictionary _bgmMap = new Dictionary() 179 | { 180 | [200] = "cgbgm_m0", 181 | [201] = "cgbgm_m1", 182 | [202] = "cgbgm_m2", 183 | [203] = "cgbgm_m3", 184 | [204] = "cgbgm_m4", 185 | [209] = "cgbgm_f0", 186 | [210] = "cgbgm_f1", 187 | [211] = "cgbgm_f2", 188 | [212] = "cgbgm_d0", 189 | [213] = "cgbgm_d1", 190 | [214] = "cgbgm_d2", 191 | [215] = "cgbgm_d3", 192 | [216] = "cgbgm_d4", 193 | [205] = "cgbgm_b0", 194 | [206] = "cgbgm_b1", 195 | [207] = "cgbgm_b2", 196 | [208] = "cgbgm_b3", 197 | [217] = "cgbgm_t0", 198 | [219] = "exbgm_s0", 199 | [220] = "exbgm_f0", 200 | [221] = "exbgm_m0", 201 | [222] = "v2bgm_f0", 202 | [223] = "v2bgm_m0", 203 | [224] = "v2bgm_ex", 204 | [225] = "v2bgm_ex", 205 | [226] = "puk2_battle1", 206 | [227] = "puk2_battle2", 207 | [228] = "puk2_field1", 208 | [229] = "puk2_mati", 209 | [230] = "puk2_sinden", 210 | [231] = "puk2_yama", 211 | [232] = "puk2_haikyo", 212 | [233] = "puk2_m_town", 213 | [234] = "puk2_OP", 214 | [235] = "puk3_battle1", 215 | [236] = "puk3_battle2", 216 | [237] = "puk3_dungeon", 217 | [238] = "puk3_kame", 218 | [239] = "puk3_kujira", 219 | [240] = "puk3_kumo", 220 | [241] = "puk3_love", 221 | [242] = "puk3_playerbattle", 222 | [243] = "PUK3_title", 223 | }; 224 | 225 | private static Dictionary _effectMap = new Dictionary() 226 | { 227 | [1] = "cgnat00",//环境音 流水 228 | [2] = "cgnat01",//环境音 流水 229 | [3] = "cgnat02",//环境音 港口船边 230 | [4] = "cgnat03",//环境音 风声(火山顶那种) 231 | [5] = "cgnat04",//环境音 (火山) 232 | [6] = "cgnat05a",//环境音 洞穴滴水 233 | [7] = "cgnat05b",//环境音 洞穴滴水 234 | [8] = "cgnat06a",//环境音 草丛 235 | [9] = "cgnat06b",//环境音 草丛 236 | [10] = "cgnat07",//环境音 树林 237 | [11] = "cgnat08",//环境音 树林 238 | [12] = "cgnat09",//环境音 瀑布 239 | [13] = "cgnat10",//环境音 篝火 240 | [14] = "cgnat11",//环境音 火旁 241 | [15] = "exnat00",//环境音 穿行驶时甲板上 242 | [16] = "v2mon150a",//环境音 雷声 243 | [17] = "34sand_clock",//环境音 不知道 244 | [18] = "35sand_clock",//环境音 不知道 245 | [19] = "36wind",//环境音 不知道 246 | [20] = "37bird",//环境音 鸟叫 247 | [21] = "puk3_Wind01",// 无 248 | [22] = "puk3_Wind02",// 无 249 | [23] = "puk3_Wind03",// 无 250 | [24] = "puk3_gaya01",//无 251 | [25] = "puk3_drop01",//无 252 | [26] = "puk3_drop02",//无 253 | [51] = "cgsys00",//鼠标左键点击 254 | [52] = "cgsys01",//鼠标左键点击道具 255 | [53] = "cgsys02",//点击登录 256 | [54] = "cgsys03",//点击返回 257 | [55] = "cgsys04",//点选不能使用的道具 258 | [56] = "cgsys05",//弹窗 259 | [57] = "cgsys06",//选择道具使用目标 260 | [58] = "cgsys07",//翻页 261 | [59] = "cgsys08",//登录角色 262 | [60] = "cgsys09",//登出 263 | [61] = "cgsys10a",//暗杀 264 | [62] = "cgsys10b",//暗杀 265 | [63] = "cgsys11",//邮件 266 | [64] = "cgsys12",//宠物升级 267 | [65] = "cgsys13a",//未知 268 | [66] = "cgsys13b",//丢钱在地上 269 | [67] = "cgsys13c",//丢钱在地上 270 | [68] = "cgsys14",//捡起地上物品 271 | [69] = "cgsys15",//扔地上物品 272 | [71] = "cgsys17",//加入队伍 273 | [72] = "cgsys18",//退出队伍 274 | [73] = "cgsys19",//换名片 275 | [74] = "cgsys20",//频道说话 276 | [75] = "cgsys21",//未知 277 | [76] = "cgsys22",//打开道具如果里面没东西 278 | [77] = "cgsys23",//使用料理 279 | [78] = "cgsys24",//使用道具给队友 280 | [79] = "cgsys25",//使用道具给队友 281 | [101] = "cgply00a", 282 | [102] = "cgply00b", 283 | [103] = "cgply01a", 284 | [104] = "cgply01b", 285 | [105] = "cgply02a", 286 | [106] = "cgply02b", 287 | [107] = "cgply03a",//空手MIS 288 | [108] = "cgply03b", 289 | [109] = "cgply04a", 290 | [110] = "cgply04b", 291 | [111] = "cgply05a", 292 | [112] = "cgply05b", 293 | [113] = "cgply06a1", 294 | [114] = "cgply06b1", 295 | [115] = "cgply06a2", 296 | [116] = "cgply06b2",//冰冻5-7(冰的声音先出 然后是这个) 297 | [117] = "cgply07a", 298 | [118] = "cgply07b", 299 | [131] = "cgply06a2", 300 | [132] = "cgply06b2", 301 | [133] = "cgply11a", 302 | [134] = "cgply11b", 303 | [135] = "cgply12a", 304 | [136] = "cgply12b", 305 | [137] = "cgply13a", 306 | [138] = "cgply13b", 307 | [139] = "cgply14a", 308 | [140] = "cgply14b", 309 | [141] = "cgply15", 310 | [142] = "cgply16", 311 | [143] = "cgply17", 312 | [147] = "cgply00a", 313 | [150] = "cgply11b", 314 | [151] = "cgmon00a", 315 | [152] = "cgmon00b", 316 | [153] = "cgmon01", 317 | [154] = "cgmon02a", 318 | [155] = "cgmon02b", 319 | [156] = "cgmon03b", 320 | [157] = "cgmon10", 321 | [158] = "cgmon20", 322 | [159] = "cgmon24", 323 | [160] = "cgmon30", 324 | [161] = "cgmon31", 325 | [162] = "cgmon41", 326 | [163] = "cgmon43", 327 | [164] = "cgmon50a", 328 | [165] = "cgmon50b", 329 | [166] = "cgmon51", 330 | [167] = "cgmon52", 331 | [168] = "cgmon60", 332 | [169] = "cgmon61", 333 | [171] = "cgmon63", 334 | [172] = "cgmon90", 335 | [173] = "cgmon91", 336 | [174] = "cgmon92", 337 | [175] = "cgmon93", 338 | [180] = "cgmon_bs1", 339 | [181] = "cgmon_bs2", 340 | [182] = "cgmon_bs3", 341 | [183] = "cgmon_bs4", 342 | [184] = "cgmon_bh1", 343 | [185] = "cgmon_bh2", 344 | [186] = "cgmon_bh3", 345 | [187] = "cgmon_bh4", 346 | [190] = "cgmon_m00", 347 | [191] = "cgmon_m01", 348 | [192] = "cgmon_m02", 349 | [198] = "cgmon_sample01", 350 | [199] = "cgmon_sample02", 351 | [200] = "cgmon_sample03", 352 | [201] = "cgbtl00",//遇敌进入战斗 353 | [202] = "cgbtl01",//倒数快到时 354 | [204] = "cgbtl03",//召唤宠物 355 | [205] = "cgbtl04",//收回宠物 356 | [206] = "cgbtl05",//战斗中技能升级 357 | [207] = "cgbtl06",//击飞 358 | [208] = "cgbtl07",//击飞过程碰壁 359 | [209] = "cgbtl08",//战斗中换武器 360 | [210] = "cgbtl09",//战斗中换位置 361 | [211] = "cgbtl10",//逃跑 362 | [212] = "cgbtl11",//封印扔卡 363 | [213] = "cgbtl12",//封印捕捉中 364 | [214] = "cgbtl13",//装备击碎 365 | [215] = "cgbtl14",//死亡 366 | [216] = "cgbtl15",//未知 367 | [217] = "cgbtl16",//使用道具前置 368 | [218] = "cgbtl17",//怪物死亡气泡 369 | [251] = "cgefc00",//物理技能使用前置(绿光) 370 | [252] = "cgefc01",//未知 371 | [253] = "cgefc02",//反击 372 | [254] = "cgefc03",//气功弹飞的过程中 373 | [255] = "cgefc04",//气功弹打到身上 374 | [256] = "cgefc05",//明镜止水出恢复数字时 375 | [257] = "cgefc06",//偷窃成功 376 | [258] = "cgefc07",//偷窃失败 377 | [259] = "cgefc08",//魔法施法 378 | [260] = "cgefc09",//状态技能 各种吸无反施法 379 | [261] = "cgefc10",//传教施法 380 | [262] = "cgefc11",//陨石魔法下落 381 | [263] = "cgefc12",//10级陨石打身上时 382 | [264] = "cgefc13",//冰冻魔法为造成伤害的前置动画声音 383 | [266] = "cgefc15",//1-4火 384 | [267] = "cgefc16",//5-7火 385 | [268] = "cgefc17",//1-4风 386 | [269] = "cgefc18",//5-7风 387 | [270] = "cgefc19",//吸血造成伤害时 388 | [271] = "cgefc20",//吸血回复血量时 389 | [272] = "cgefc21",//咒术怪物时气泡 390 | [273] = "cgefc22",//毒咒掉血时 391 | [274] = "cgefc23",//酒醉掉魔时 392 | [275] = "cgefc24",//祈祷魔封动画展开时 393 | [276] = "cgefc25",//属性反转 394 | [277] = "cgefc26",//功无攻反等套身上时 395 | [278] = "cgefc27",//补血魔法补血时 396 | [279] = "cgefc28",//恢复魔法恢复时 397 | [280] = "cgefc29",//气绝 398 | [281] = "cgefc30",//洁净 399 | [282] = "cgefc31",//10火 400 | [283] = "cgefc32",//跳舞10级 401 | [284] = "cgefc33",//祭死 402 | [285] = "cgefc34",//未知 403 | [286] = "cgefc35",//功无魔无抵挡时 404 | [287] = "cgefc36",//正常反击 405 | [288] = "cgefc37a",//自爆变大中 406 | [289] = "cgefc37b",//自爆准备爆炸 407 | [290] = "cgefc37c",//自爆爆炸 408 | [291] = "cgefc38",//恢复套的过程 409 | [296] = "v2monex1", 410 | [297] = "v2monex2", 411 | [298] = "v2monex3", 412 | [300] = "v2mon100", 413 | [301] = "v2mon110", 414 | [302] = "v2mon111a", 415 | [303] = "v2mon111b", 416 | [304] = "v2mon120", 417 | [305] = "v2mon121a", 418 | [306] = "v2mon121b", 419 | [307] = "v2mon121c", 420 | [308] = "v2mon130", 421 | [309] = "v2mon140", 422 | [310] = "v2mon150a", 423 | [311] = "v2mon150b", 424 | [312] = "v2mon161", 425 | [313] = "v2mon170a", 426 | [314] = "v2mon170b", 427 | [315] = "v2mon171a", 428 | [316] = "v2mon171b", 429 | [317] = "v2mon190", 430 | [318] = "v2mon191", 431 | [319] = "v2monex0", 432 | [400] = "01small_amae_new", 433 | [401] = "02small_normal", 434 | [402] = "02small_normal_new", 435 | [403] = "03small_iyaiya", 436 | [404] = "03small_iyaiya_new", 437 | [405] = "04fish_normal", 438 | [406] = "05fish_shout", 439 | [407] = "06fish_amae", 440 | [408] = "09kame_amae", 441 | [409] = "10yagi_shout", 442 | [410] = "11yagi_normal", 443 | [411] = "12yagi_amae", 444 | [412] = "13bird_normal", 445 | [413] = "14bird_shout", 446 | [414] = "15bird_amae", 447 | [415] = "16fish_normal", 448 | [416] = "17fish_shout", 449 | [417] = "18kame_normal", 450 | [418] = "19kame_shout", 451 | [419] = "20animal_normal", 452 | [420] = "21animal_shout", 453 | [421] = "22bird_normal", 454 | [422] = "23bird_shout", 455 | [423] = "24Monstor", 456 | [424] = "25_1_off", 457 | [425] = "26ground_on", 458 | [426] = "27ground_off", 459 | [427] = "28_water_on", 460 | [428] = "29_water_of", 461 | [429] = "30fire_on", 462 | [430] = "31fire_of", 463 | [431] = "32_wind_on", 464 | [432] = "32_wind_on2", 465 | [433] = "33_wind_off", 466 | [435] = "36wind", 467 | [436] = "37bird", 468 | [437] = "38make_gild",//升级 469 | [438] = "39levelup", 470 | [500] = "cgply10a", 471 | [501] = "cgply10b", 472 | }; 473 | } 474 | } -------------------------------------------------------------------------------- /CrossgateToolkit/DynamicGraphic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using UnityEngine; 8 | using Debug = UnityEngine.Debug; 9 | using Object = UnityEngine.Object; 10 | 11 | namespace CrossgateToolkit 12 | { 13 | // 针对网游设置的可扩展动态图集 14 | // 包含图集建立、自动维护和清理 15 | public class DynamicGraphic 16 | { 17 | // 动态图集数据 18 | public class DynamicData 19 | { 20 | // 图集高度 21 | public int Width; 22 | // 图集宽度 23 | public int Height; 24 | // 图集Texture 25 | public Texture2D Texture2D; 26 | // 图集Sprite引用及编号银映射 27 | // public List RefSpriteList = new List(); 28 | // public Dictionary RefSpriteMap = new Dictionary(); 29 | // public Dictionary PrimaryColor = new Dictionary(); 30 | // 二维数组存储当前所有像素点可用位置 - 此数组在4096*4096情况下,占用约16MB内存 31 | // public bool[,] PixelAvaliable; 32 | // 在二维空间中,记录当前可用的矩形区域 33 | public List AvaliableRect = new List(); 34 | public bool avaliable = true; 35 | public bool CompressWhenFull = false; 36 | 37 | public void Init(bool Linear = false) 38 | { 39 | // 初始化时填补List的0位,避免序列号为0的图像无法获取 40 | // RefSpriteList.Add(null); 41 | AvaliableRect.Add(new Rect(0, 0, Width, Height)); 42 | float time = Time.realtimeSinceStartup; 43 | Texture2D = new Texture2D(Width, Height, TextureFormat.RGBA4444, false); 44 | Texture2D.name = "DynamicGraphicTexture"; 45 | Texture2D.filterMode = Linear ? FilterMode.Bilinear : FilterMode.Point; 46 | Texture2D.wrapMode = TextureWrapMode.Clamp; 47 | // Texture2D.Compress(true); 48 | // Texture2d填充透明像素 49 | // Color32[] transColor = new Color32[Width * Height]; 50 | // for (int i = 0; i < Width * Height; i++) 51 | // { 52 | // transColor[i] = Color.clear; 53 | // } 54 | // Texture2D.SetPixels32(transColor); 55 | // Texture2D.Apply(); 56 | // transColor = null; 57 | } 58 | 59 | private int bestLongSideFit; 60 | private int bestShortSideFit; 61 | 62 | // 查找最佳位置 63 | public Rect FindBestFitRect(int width, int height) 64 | { 65 | Rect bestRect = default; 66 | bestShortSideFit = int.MaxValue; 67 | bool hasAvaliable = false; 68 | for (int i = 0; i < AvaliableRect.Count; ++i) 69 | { 70 | if(AvaliableRect[i].width>64 && AvaliableRect[i].height>48) hasAvaliable = true; 71 | if (AvaliableRect[i].width >= width && AvaliableRect[i].height >= height) 72 | { 73 | int leftoverHoriz = Mathf.Abs((int)AvaliableRect[i].width - width); 74 | int leftoverVert = Mathf.Abs((int)AvaliableRect[i].height - height); 75 | int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert); 76 | int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert); 77 | 78 | if (shortSideFit < bestShortSideFit || (shortSideFit == bestShortSideFit && longSideFit < bestLongSideFit)) 79 | { 80 | bestRect.x = AvaliableRect[i].x; 81 | bestRect.y = AvaliableRect[i].y; 82 | bestRect.width = width; 83 | bestRect.height = height; 84 | bestShortSideFit = shortSideFit; 85 | bestLongSideFit = longSideFit; 86 | } 87 | } 88 | 89 | } 90 | // 检测过程中判断是否还有有效空间 91 | avaliable = hasAvaliable; 92 | if (!avaliable) 93 | { 94 | // 当有效空间为0时,对texture压缩 95 | if(CompressWhenFull) Texture2D.Compress(true); 96 | } 97 | return bestRect; 98 | } 99 | 100 | // 插入位置 101 | public void InsertRect (Rect node) 102 | { 103 | // float time = Time.time; 104 | // Stopwatch stopwatch = new Stopwatch(); 105 | // stopwatch.Start(); 106 | int numRectanglesToProcess = AvaliableRect.Count; 107 | for (int i = 0; i < numRectanglesToProcess; ++i) 108 | { 109 | if (SplitFreeRect(AvaliableRect[i], ref node)) 110 | { 111 | AvaliableRect.RemoveAt(i); 112 | --i; 113 | --numRectanglesToProcess; 114 | } 115 | } 116 | 117 | // 重新整理可用区域,去除重叠区域 118 | OptFreeList(); 119 | // stopwatch.Stop(); 120 | // Debug.Log("[CGTool] 插入位置耗时: " + stopwatch.ElapsedMilliseconds + "ms"); 121 | } 122 | 123 | // 分割区域 124 | bool SplitFreeRect (Rect freeRect, ref Rect useRect) 125 | { 126 | Rect rect = default; 127 | if (useRect.x >= freeRect.x + freeRect.width || useRect.x + useRect.width <= freeRect.x || 128 | useRect.y >= freeRect.y + freeRect.height || useRect.y + useRect.height <= freeRect.y) 129 | return false; 130 | 131 | if (useRect.x < freeRect.x + freeRect.width && useRect.x + useRect.width > freeRect.x) 132 | { 133 | if (useRect.y > freeRect.y && useRect.y < freeRect.y + freeRect.height) 134 | { 135 | rect = freeRect; 136 | rect.height = useRect.y - rect.y; 137 | AvaliableRect.Add(rect); 138 | } 139 | 140 | if (useRect.y + useRect.height < freeRect.y + freeRect.height) 141 | { 142 | rect = freeRect; 143 | rect.y = useRect.y + useRect.height; 144 | rect.height = freeRect.y + freeRect.height - (useRect.y + useRect.height); 145 | AvaliableRect.Add(rect); 146 | } 147 | } 148 | 149 | if (useRect.y < freeRect.y + freeRect.height && useRect.y + useRect.height > freeRect.y) 150 | { 151 | if (useRect.x > freeRect.x && useRect.x < freeRect.x + freeRect.width) 152 | { 153 | rect = freeRect; 154 | rect.width = useRect.x - rect.x; 155 | AvaliableRect.Add(rect); 156 | } 157 | 158 | if (useRect.x + useRect.width < freeRect.x + freeRect.width) 159 | { 160 | rect = freeRect; 161 | rect.x = useRect.x + useRect.width; 162 | rect.width = freeRect.x + freeRect.width - (useRect.x + useRect.width); 163 | AvaliableRect.Add(rect); 164 | } 165 | } 166 | 167 | return true; 168 | } 169 | 170 | // 重新整理可用区域,去除重叠区域 171 | void OptFreeList () 172 | { 173 | for (int i = 0; i < AvaliableRect.Count; ++i) 174 | for (int j = i + 1; j < AvaliableRect.Count; ++j) 175 | { 176 | if (IsIntersect(AvaliableRect[i], AvaliableRect[j])) 177 | { 178 | AvaliableRect.RemoveAt(i); 179 | --i; 180 | break; 181 | } 182 | if (IsIntersect(AvaliableRect[j], AvaliableRect[i])) 183 | { 184 | AvaliableRect.RemoveAt(j); 185 | --j; 186 | } 187 | } 188 | } 189 | 190 | // 比对两个矩形是否重叠 191 | bool IsIntersect (Rect a, Rect b) 192 | { 193 | return a.x >= b.x && a.y >= b.y 194 | && a.x + a.width <= b.x + b.width 195 | && a.y + a.height <= b.y + b.height; 196 | } 197 | } 198 | 199 | private class ClearMono:MonoBehaviour 200 | { 201 | public void Clear() 202 | { 203 | Destroy(gameObject); 204 | } 205 | } 206 | 207 | // 动态图集最大宽度 208 | public int MaxGraphicWidth; 209 | // 动态图集最大高度 210 | public int MaxGraphicHeight; 211 | // 动态图集内部间隔 212 | public int Padding; 213 | // 动态图集是否使用线性采样 214 | public bool Linear; 215 | // 动态图集是否使用100ppu 216 | public bool PPU100; 217 | // 当动态图档无可用空间时进行压缩 218 | public bool CompressWhenFull; 219 | // 使用调色板编号 220 | public int PaletIndex; 221 | // 动态图集固定图像尺寸 222 | public Vector2Int FixedSize = default; 223 | // 当前动态图集包含的图集数据 224 | public List DynamicDatas = new List(); 225 | // Sprite缓存 226 | public Dictionary SpriteCache = new Dictionary(); 227 | // 主色缓存 228 | public Dictionary PrimaryColorCache = new Dictionary(); 229 | 230 | private static ClearMono clearMono; 231 | 232 | /// 233 | /// 创建动态图集 234 | /// 235 | /// 图集最大宽度 236 | /// 图集最大高度 237 | /// 图集各图档间隔 238 | /// 调色板编号 239 | /// 线性过滤 240 | /// 以100的PPU方式生成Sprite对象 241 | /// 当图集对象无可用空间时,对Texture进行压缩 242 | public DynamicGraphic(int GraphicWidth, int GraphicHeight, int GraphicPadding = 0,int palet = 0,bool linear = false,bool ppu100 = false,bool compressWhenFull = false) 243 | { 244 | MaxGraphicWidth = GraphicWidth; 245 | MaxGraphicHeight = GraphicHeight; 246 | Padding = GraphicPadding; 247 | PaletIndex = palet; 248 | Linear = linear; 249 | PPU100 = ppu100; 250 | CompressWhenFull = compressWhenFull; 251 | if (clearMono == null) clearMono = new GameObject("DynamicGraphicClear").AddComponent(); 252 | } 253 | 254 | 255 | // 清理图集图像 256 | public void Clear(bool autoGC = false) 257 | { 258 | // clearMono.StartCoroutine(ClearCoroutine(DynamicDatas, autoGC)); 259 | ClearCoroutine(DynamicDatas, autoGC); 260 | DynamicDatas = new List(); 261 | } 262 | 263 | // 获取图像 264 | public Sprite GetSprite(uint Serial) 265 | { 266 | Sprite sprite = null; 267 | // 检查缓存 268 | SpriteCache.TryGetValue(Serial, out sprite); 269 | if (sprite != null) return sprite; 270 | 271 | // 获取图档数据 272 | GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(Serial); 273 | if (graphicInfoData == null) 274 | { 275 | Debug.LogError("[CGTool] 无法获取图档数据: " + Serial); 276 | return null; 277 | } 278 | // Debug.Log("[CGTool] 获取图档数据: " + Serial + " " + graphicInfoData.Width + "x" + graphicInfoData.Height); 279 | 280 | // 更新尺寸,增加Padding 281 | int width = (int)graphicInfoData.Width + Padding; 282 | int height = (int)graphicInfoData.Height + Padding; 283 | 284 | // 首先检查最新的图集数据是否有空间 285 | DynamicData lastDynamicData = null; 286 | bool avaliable = true; 287 | Rect avaliableRect = default; 288 | 289 | // 检测是否有图集数据 290 | if (DynamicDatas.Count > 0) 291 | { 292 | for (var i = 0; i < DynamicDatas.Count; i++) 293 | { 294 | lastDynamicData = DynamicDatas[i]; 295 | if (!lastDynamicData.avaliable) 296 | { 297 | lastDynamicData = null; 298 | continue; 299 | } 300 | avaliableRect = lastDynamicData.FindBestFitRect(width, height); 301 | if (avaliableRect != default) break; 302 | } 303 | // lastDynamicData = DynamicDatas[^1]; 304 | // avaliableRect = lastDynamicData.FindBestFitRect(width, height); 305 | } 306 | else avaliable = false; 307 | 308 | 309 | 310 | // 如果没有可用数据集或没有空间则创建新的图集 311 | if (!avaliable || avaliableRect==default) 312 | { 313 | DynamicData newDynamicData = new DynamicData(); 314 | newDynamicData.Width = MaxGraphicWidth; 315 | newDynamicData.Height = MaxGraphicHeight; 316 | 317 | // 初始化 318 | newDynamicData.Init(Linear); 319 | newDynamicData.CompressWhenFull = CompressWhenFull; 320 | DynamicDatas.Add(newDynamicData); 321 | lastDynamicData = newDynamicData; 322 | avaliableRect = lastDynamicData.FindBestFitRect(width, height); 323 | Debug.Log("[CGTool] 创建新图集: " + newDynamicData.Width + "x" + newDynamicData.Height + " 当前图集数量: " + 324 | DynamicDatas.Count); 325 | } 326 | 327 | 328 | // 获取图档像素 329 | List color32s; 330 | Color PrimaryColor = Color.clear; 331 | Texture texture = null; 332 | bool useCache = true; 333 | 334 | // 填充图集,填充方式为可用区域的左下角开始 335 | if (useCache) 336 | { 337 | // 二级缓存模式 338 | GraphicDetail graphicDetail = GraphicData.GetGraphicDetail(graphicInfoData, PaletIndex, -1, Linear, true); 339 | if (graphicDetail == null) return null; 340 | texture = graphicDetail.Sprite.texture; 341 | PrimaryColor = graphicDetail.PrimaryColor; 342 | Graphics.CopyTexture(texture, 0, 0, 0,0, 343 | (int)graphicInfoData.Width, (int)graphicInfoData.Height, lastDynamicData.Texture2D, 0, 0, (int)avaliableRect.x, (int)avaliableRect.y); 344 | } 345 | else 346 | { 347 | // 非缓存模式 348 | color32s = GraphicData.UnpackGraphic(graphicInfoData, PaletIndex); 349 | if (color32s == null || color32s.Count == 0) return null; 350 | 351 | // 去除最后一位主色 352 | // lastDynamicData.PrimaryColor[Serial] = color32s[^1]; 353 | PrimaryColor = color32s[^1]; 354 | color32s.RemoveAt(color32s.Count - 1); 355 | lastDynamicData.Texture2D.SetPixels32((int)avaliableRect.x, (int)avaliableRect.y, 356 | (int)graphicInfoData.Width, (int)graphicInfoData.Height, color32s.ToArray(), 0); 357 | lastDynamicData.Texture2D.Apply(false, false); 358 | color32s = null; 359 | } 360 | 361 | //直接通过Texture2D做偏移,并转为Sprite的偏移量 362 | Vector2 offset = new Vector2(0f, 1f); 363 | offset.x += -(graphicInfoData.OffsetX * 1f) / graphicInfoData.Width; 364 | offset.y -= (-graphicInfoData.OffsetY * 1f) / graphicInfoData.Height; 365 | 366 | // 创建Sprite 367 | sprite = Sprite.Create(lastDynamicData.Texture2D, 368 | new Rect(avaliableRect.x, avaliableRect.y, graphicInfoData.Width, graphicInfoData.Height), 369 | offset, PPU100 ? 100 : 1, 0, SpriteMeshType.FullRect); 370 | sprite.name = "DG-" + Serial; 371 | 372 | SpriteCache[Serial] = sprite; 373 | PrimaryColorCache[Serial] = PrimaryColor; 374 | 375 | // 更新当前可用区域 376 | lastDynamicData.InsertRect(avaliableRect); 377 | return sprite; 378 | } 379 | 380 | public IEnumerator GetSpriteSync(uint Serial, Action callback) 381 | { 382 | Sprite sprite = null; 383 | SpriteCache.TryGetValue(Serial, out sprite); 384 | if (sprite!=null) 385 | { 386 | callback?.Invoke(sprite); 387 | yield break; 388 | } 389 | yield return null; 390 | sprite = GetSprite(Serial); 391 | callback?.Invoke(sprite); 392 | } 393 | 394 | // 获取主色 395 | public Color GetPrimaryColor(uint Serial) 396 | { 397 | SpriteCache.TryGetValue(Serial, out var sprite); 398 | if(sprite==null) clearMono.StartCoroutine(GetSpriteSync(Serial, s => sprite = s)); 399 | PrimaryColorCache.TryGetValue(Serial, out var color); 400 | // if(color==null) color = Color.clear; 401 | return color; 402 | } 403 | 404 | private void ClearCoroutine(List dynamicDatas, bool autoGC = false) 405 | { 406 | PrimaryColorCache.Clear(); 407 | Dictionary spriteCache = SpriteCache; 408 | SpriteCache = new Dictionary(); 409 | 410 | List textures = new List(); 411 | 412 | foreach (var keyValuePair in spriteCache) 413 | { 414 | Sprite sprite = keyValuePair.Value; 415 | if (sprite == null) continue; 416 | if(!textures.Contains(sprite.texture)) textures.Add(sprite.texture); 417 | Object.Destroy(sprite); 418 | sprite = null; 419 | GraphicData.ClearCache(keyValuePair.Key); 420 | } 421 | foreach (var texture in textures) 422 | { 423 | Object.Destroy(texture); 424 | // Resources.UnloadAsset(texture); 425 | } 426 | 427 | DynamicDatas.Clear(); 428 | if (autoGC) 429 | { 430 | Resources.UnloadUnusedAssets(); 431 | // System.GC.Collect(); 432 | } 433 | } 434 | 435 | // 协程清理有可能导致无法清除干净,暂时不用 436 | // IEnumerator ClearCoroutine(List dynamicDatas, bool autoGC = false) 437 | // { 438 | // PrimaryColorCache.Clear(); 439 | // Dictionary spriteCache = SpriteCache; 440 | // SpriteCache = new Dictionary(); 441 | // 442 | // List textures = new List(); 443 | // 444 | // foreach (var keyValuePair in spriteCache) 445 | // { 446 | // Sprite sprite = keyValuePair.Value; 447 | // if (sprite == null) continue; 448 | // if(!textures.Contains(sprite.texture)) textures.Add(sprite.texture); 449 | // spriteCache.Remove(keyValuePair.Key); 450 | // sprite = null; 451 | // // Resources.UnloadAsset(sprite); 452 | // } 453 | // yield return null; 454 | // foreach (var texture in textures) 455 | // { 456 | // Object.Destroy(texture); 457 | // yield return null; 458 | // } 459 | // 460 | // DynamicDatas.Clear(); 461 | // yield return null; 462 | // if (autoGC) 463 | // { 464 | // Resources.UnloadUnusedAssets(); 465 | // // System.GC.Collect(); 466 | // } 467 | // } 468 | } 469 | } -------------------------------------------------------------------------------- /CrossgateToolkit/Map.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * 魔力宝贝图档解析脚本 - CGTool 3 | * 4 | * @Author HonorLee (dev@honorlee.me) 5 | * @Version 1.0 (2023-04-15) 6 | * @License GPL-3.0 7 | * 8 | * Map.cs 服务端地图解析类 9 | */ 10 | 11 | using System; 12 | using System.Collections.Generic; 13 | using System.IO; 14 | using System.Linq; 15 | using System.Text.RegularExpressions; 16 | using UnityEngine; 17 | using Object = System.Object; 18 | 19 | namespace CrossgateToolkit 20 | { 21 | //地图文件信息 22 | public class MapFileInfo 23 | { 24 | public uint Serial; 25 | public string Name; 26 | public string FileName; 27 | } 28 | //地图块数据 29 | public class MapBlockData 30 | { 31 | public GraphicInfoData GraphicInfo; 32 | public int MapIndex; 33 | public uint MapSerial; 34 | public float ObjectZIndex = 0; 35 | public int x; 36 | public int y; 37 | } 38 | //地图信息 39 | public class MapInfo 40 | { 41 | //地图编号 42 | public uint Serial; 43 | //地图宽度 44 | public int Width; 45 | //地图高度 46 | public int Height; 47 | // 地图名称 48 | public string Name; 49 | // 调色板号 - 默认 -1 表示自动 50 | public int Palet = -1; 51 | //未知数据 52 | public byte[] Unknow; 53 | //地面数据 54 | public List GroundDatas = new List(); 55 | //地表数据 56 | public List ObjectDatas = new List(); 57 | public bool[] BlockedIndexs; 58 | public float[] FixPlayerZs; 59 | //地图坐标二维数组,用以记录可行走区域并作为自动寻路的数据参考 60 | public bool[,] MapNodes; 61 | } 62 | 63 | 64 | public class Map 65 | { 66 | //缓存数据 67 | private static Dictionary _cache = new Dictionary(); 68 | private static Dictionary _mapIndexFiles = new Dictionary(); 69 | 70 | private static Dictionary> _mapGroundGraphicBatch = new Dictionary>(); 71 | private static Dictionary> _mapObjectGraphicBatch = new Dictionary>(); 72 | 73 | //初始化地图文件列表 74 | public static void Init() 75 | { 76 | DirectoryInfo mapDirectory = new DirectoryInfo(CGTool.PATH.MAP); 77 | FileInfo[] mapFiles = mapDirectory.GetFiles(); 78 | string match = @"^(\d+)_?(.+)?$"; 79 | foreach (var fileInfo in mapFiles) 80 | { 81 | string filename = fileInfo.Name; 82 | Match matchRet = Regex.Match(filename, match); 83 | if(!matchRet.Success) continue; 84 | 85 | MapFileInfo _file = new MapFileInfo(); 86 | _file.Serial = uint.Parse(matchRet.Groups[1].Value); 87 | if(matchRet.Groups.Count > 1) _file.Name = matchRet.Groups[1].Value; 88 | _file.FileName = filename; 89 | _mapIndexFiles.Add(_file.Serial, _file); 90 | } 91 | Debug.Log("[CGTool] 地图列表初始化完成,共" + _mapIndexFiles.Count + "个地图文件"); 92 | } 93 | 94 | //获取全部地图列表 95 | public static List GetMapList() 96 | { 97 | List _list = new List(); 98 | foreach (var mapIndexFile in _mapIndexFiles) 99 | { 100 | _list.Add(mapIndexFile.Value); 101 | } 102 | 103 | return _list; 104 | } 105 | //获取地图数据 106 | public static MapInfo GetMap(uint serial) 107 | { 108 | 109 | //返回缓存数据 110 | if (_cache.ContainsKey(serial)) return _cache[serial]; 111 | //加载数据 112 | MapInfo mapInfo = _loadMap(serial); 113 | return mapInfo; 114 | } 115 | 116 | // 地面数据合批 117 | public static Dictionary BakeGrounds(uint mapID,List graphicInfoDatas,int palet = 0,int subPalet = 0,bool linear = false) 118 | { 119 | _mapGroundGraphicBatch.TryGetValue(mapID, out var graphicDataDict); 120 | if (graphicDataDict == null) 121 | { 122 | graphicDataDict = GraphicData.BakeGraphics(graphicInfoDatas, true, palet, subPalet, linear, 2048, 0); 123 | _mapGroundGraphicBatch[mapID] = graphicDataDict; 124 | } 125 | return graphicDataDict; 126 | } 127 | 128 | // 物件数据合批 129 | public static Dictionary BakeObjects(uint mapID,List graphicInfoDatas,int palet = 0,int subPalet = 0,bool linear = false) 130 | { 131 | _mapObjectGraphicBatch.TryGetValue(mapID, out var graphicDataDict); 132 | if (graphicDataDict == null) 133 | { 134 | graphicDataDict = GraphicData.BakeGraphics(graphicInfoDatas, true, palet, subPalet, linear, 4096, 0); 135 | _mapObjectGraphicBatch[mapID] = graphicDataDict; 136 | } 137 | return graphicDataDict; 138 | } 139 | 140 | public static void ClearMapBatch(uint mapID) 141 | { 142 | Dictionary graphicDataDict; 143 | List graphicDetails; 144 | List textures = new List(); 145 | _mapGroundGraphicBatch.TryGetValue(mapID, out graphicDataDict); 146 | if (graphicDataDict != null) 147 | { 148 | graphicDetails = graphicDataDict.Values.ToList(); 149 | foreach (var graphicDetail in graphicDetails) 150 | { 151 | Texture texture = graphicDetail.Sprite.texture; 152 | if (!textures.Contains(texture)) textures.Add(graphicDetail.Sprite.texture); 153 | graphicDetail.SpritePPU100 = null; 154 | graphicDetail.Sprite = null; 155 | } 156 | } 157 | _mapObjectGraphicBatch.TryGetValue(mapID, out graphicDataDict); 158 | if (graphicDataDict != null) 159 | { 160 | graphicDetails = graphicDataDict.Values.ToList(); 161 | foreach (var graphicDetail in graphicDetails) 162 | { 163 | Texture texture = graphicDetail.Sprite.texture; 164 | if (!textures.Contains(texture)) textures.Add(graphicDetail.Sprite.texture); 165 | graphicDetail.SpritePPU100 = null; 166 | graphicDetail.Sprite = null; 167 | } 168 | } 169 | foreach (var texture in textures) 170 | { 171 | Resources.UnloadAsset(texture); 172 | } 173 | 174 | _mapGroundGraphicBatch.Remove(mapID); 175 | _mapObjectGraphicBatch.Remove(mapID); 176 | } 177 | 178 | //加载地图数据 179 | private static MapInfo _loadMap(uint serial) 180 | { 181 | // CGTool.Logger.Write("开始加载时间:" + DateTime.Now); 182 | if (!_mapIndexFiles.ContainsKey(serial)) return null; 183 | 184 | // print("找到地图文件: " + mapFileInfo.Name); 185 | FileStream mapFileStream = new FileStream(CGTool.PATH.MAP + "/" + _mapIndexFiles[serial].FileName, FileMode.Open); 186 | BinaryReader mapFileReader = new BinaryReader(mapFileStream); 187 | 188 | MapInfo mapInfo = new MapInfo(); 189 | mapInfo.Serial = serial; 190 | 191 | bool isClientMapFile = false; 192 | 193 | //地图文件头 194 | byte[] mapHeader = mapFileReader.ReadBytes( 6); 195 | if(mapHeader[0]==0x4C && mapHeader[1]==0x53 && mapHeader[2]==0x32 && mapHeader[3]==0x4D && mapHeader[4]==0x41 && mapHeader[5]==0x50){ 196 | isClientMapFile = false; 197 | Debug.Log("[CGTool] 地图文件头: 服务端地图"); 198 | }else if (mapHeader[0]==0x4D && mapHeader[1]==0x41 && mapHeader[2]==0x50){ 199 | isClientMapFile = true; 200 | Debug.Log("[CGTool] 地图文件头: 客户端地图"); 201 | } 202 | else 203 | { 204 | Debug.LogError("[CGTool] 地图文件头错误: " + _mapIndexFiles[serial].FileName); 205 | return null; 206 | } 207 | byte[] bytes; 208 | if (isClientMapFile) 209 | { 210 | // 无用信息 211 | mapFileReader.ReadBytes(6); 212 | //读取地图宽度 213 | bytes = mapFileReader.ReadBytes(4); 214 | mapInfo.Width = BitConverter.ToUInt16(bytes,0); 215 | //读取地图高度 216 | bytes = mapFileReader.ReadBytes(4); 217 | mapInfo.Height = BitConverter.ToUInt16(bytes,0); 218 | if (MapExtra.ClientMapExtraDatas.ContainsKey(serial)) 219 | { 220 | mapInfo.Name = MapExtra.ClientMapExtraDatas[serial].Name; 221 | mapInfo.Palet = MapExtra.ClientMapExtraDatas[serial].Palet; 222 | } 223 | else 224 | { 225 | mapInfo.Name = "未知领域"; 226 | mapInfo.Palet = -1; 227 | } 228 | } 229 | else 230 | { 231 | // 无用信息 232 | mapFileReader.ReadBytes(2); 233 | //地图名称 234 | byte[] mapNameBytes = mapFileReader.ReadBytes(32); 235 | string[] mapHead = System.Text.Encoding.GetEncoding("GBK").GetString(mapNameBytes).Split('|'); 236 | mapInfo.Name = mapHead[0]; 237 | 238 | // 调色板 239 | if (mapHead.Length>1){ 240 | if(mapHead[1] != null || mapHead[1] != "") mapInfo.Palet = int.Parse(mapHead[1]); 241 | } 242 | 243 | //读取地图宽度 244 | bytes = mapFileReader.ReadBytes(2); 245 | Array.Reverse(bytes); 246 | mapInfo.Width = BitConverter.ToUInt16(bytes,0); 247 | //读取地图高度 248 | bytes = mapFileReader.ReadBytes(2); 249 | Array.Reverse(bytes); 250 | mapInfo.Height = BitConverter.ToUInt16(bytes,0); 251 | } 252 | 253 | 254 | 255 | byte[] mapBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2)); 256 | byte[] mapCoverBytes = mapFileReader.ReadBytes((int) (mapInfo.Width * mapInfo.Height * 2)); 257 | 258 | mapFileReader.Dispose(); 259 | mapFileReader.Close(); 260 | mapFileStream.Close(); 261 | 262 | // print(JsonUtility.ToJson(mapInfo)); 263 | 264 | BinaryReader mapReader = new BinaryReader(new MemoryStream(mapBytes)); 265 | BinaryReader mapCoverReader = new BinaryReader(new MemoryStream(mapCoverBytes)); 266 | // BinaryReader mapInfoReader = new BinaryReader(new MemoryStream(mapInfoBytes)); 267 | 268 | List tempGroundTiles = new List(); 269 | List tempObjectTiles = new List(); 270 | 271 | // CGTool.Logger.Write("开始解析时间:" + DateTime.Now); 272 | //原始数据为反转数据,即坐标起点为 1,1 排序方向为 y : 1=>0 x: 1=>0 273 | int len = mapInfo.Width * mapInfo.Height; 274 | for (int i = 0; i < len; i++) 275 | { 276 | //地面数据 277 | MapBlockData mapTile = null; 278 | bytes = mapReader.ReadBytes(2); 279 | if(!isClientMapFile) Array.Reverse(bytes); 280 | uint mapGraphicSerial = BitConverter.ToUInt16(bytes,0); 281 | GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(mapGraphicSerial); 282 | if (graphicInfoData != null) 283 | { 284 | mapTile = new MapBlockData(); 285 | mapTile.GraphicInfo = graphicInfoData; 286 | mapTile.MapSerial = mapGraphicSerial; 287 | } 288 | tempGroundTiles.Add(mapTile); 289 | 290 | MapBlockData mapCoverTile = null; 291 | bytes = mapCoverReader.ReadBytes(2); 292 | if(!isClientMapFile) Array.Reverse(bytes); 293 | 294 | uint mapCoverGraphicSerial = BitConverter.ToUInt16(bytes,0); 295 | graphicInfoData = GraphicInfo.GetGraphicInfoData(mapCoverGraphicSerial); 296 | if (graphicInfoData != null) 297 | { 298 | mapCoverTile = new MapBlockData(); 299 | mapCoverTile.GraphicInfo = graphicInfoData; 300 | mapCoverTile.MapSerial = mapCoverGraphicSerial; 301 | } 302 | tempObjectTiles.Add(mapCoverTile); 303 | } 304 | 305 | MapBlockData[] GroundTiles = new MapBlockData[len]; 306 | MapBlockData[] ObjectTiles = new MapBlockData[len]; 307 | bool[] blockedIndexs = new bool[len]; 308 | bool[,] nodes = new bool[mapInfo.Width, mapInfo.Height]; 309 | mapInfo.FixPlayerZs = new float[len]; 310 | 311 | // CGTool.Logger.Write("开始排序时间:" + DateTime.Now); 312 | //重新排序 313 | for (int y = 0; y < mapInfo.Height; y++) 314 | { 315 | for (int x = 0; x < mapInfo.Width; x++) 316 | { 317 | // int index = i * (int) mapInfo.Width + ((int) mapInfo.Width - j - 1); 318 | int _tmpindex = x + (mapInfo.Height - y - 1) * mapInfo.Width; 319 | int index = x + y * mapInfo.Width; 320 | 321 | MapBlockData mapTile = tempGroundTiles[_tmpindex]; 322 | MapBlockData ObjectTile = tempObjectTiles[_tmpindex]; 323 | 324 | GroundTiles[index] = mapTile; 325 | ObjectTiles[index] = ObjectTile; 326 | 327 | if (mapTile==null || mapTile.GraphicInfo.Blocked) blockedIndexs[index] = true; 328 | 329 | //角色默认层级 330 | float Z = x * 9 + y * 11; 331 | mapInfo.FixPlayerZs[index] = Z; 332 | 333 | if (ObjectTile != null) 334 | { 335 | ObjectTile.MapIndex = index; 336 | if (!ObjectTile.GraphicInfo.AsGround) 337 | { 338 | ObjectTile.ObjectZIndex = Z + Math.Min(ObjectTile.GraphicInfo.East,ObjectTile.GraphicInfo.South) * 10 - 10; 339 | ObjectTile.x = x; 340 | ObjectTile.y = y; 341 | 342 | if(ObjectTile.GraphicInfo !=null && ObjectTile.GraphicInfo.Blocked) blockedIndexs[index] = true; 343 | } 344 | } 345 | 346 | nodes[x, y] = !blockedIndexs[index]; 347 | } 348 | } 349 | 350 | // Z轴修正 351 | void resetObjectZ(MapBlockData blockData,float Z = 0f) 352 | { 353 | if (!blockData.GraphicInfo.Blocked) 354 | { 355 | blockData.ObjectZIndex = blockData.ObjectZIndex + 0.1f; 356 | return; 357 | } 358 | int x = blockData.x; 359 | int y = blockData.y; 360 | if (Z != 0f) 361 | { 362 | mapInfo.FixPlayerZs[(int)(y * mapInfo.Width + x)] = Z; 363 | blockData.ObjectZIndex = Z; 364 | } 365 | else 366 | { 367 | Z = blockData.ObjectZIndex; 368 | } 369 | int ox = x - 1; 370 | if (ox >= 0 && (blockData.GraphicInfo.South>2 || blockData.GraphicInfo.Serial==17644)) 371 | { 372 | int maxHeight = Math.Min(y + blockData.GraphicInfo.South, mapInfo.Height); 373 | float leftZ = Z - 10f; 374 | for(int n = y;n= 0 && (blockData.GraphicInfo.East>2 || blockData.GraphicInfo.Serial==17644)) 384 | { 385 | int maxWidth = Math.Min(x + blockData.GraphicInfo.East, mapInfo.Width); 386 | float rightZ = Z - 10f; 387 | for(int n = x;n 1 || ObjectTile.GraphicInfo.South > 1)) 421 | { 422 | for (int i = x; i < (x + ObjectTile.GraphicInfo.East); i++) 423 | { 424 | for (int j = y; j < (y+ ObjectTile.GraphicInfo.South); j++) 425 | { 426 | if(i>=mapInfo.Width || j>=mapInfo.Height) continue; 427 | int _index = (int) (j * mapInfo.Width + i); 428 | blockedIndexs[_index] = true; 429 | nodes[i, j] = false; 430 | } 431 | } 432 | } 433 | } 434 | } 435 | 436 | mapInfo.GroundDatas = GroundTiles.ToList(); 437 | mapInfo.ObjectDatas = ObjectTiles.ToList(); 438 | mapInfo.BlockedIndexs = blockedIndexs; 439 | mapInfo.MapNodes = nodes; 440 | _cache[serial] = mapInfo; 441 | 442 | Debug.Log("[CGTool] 读取地图: " + mapInfo.Name); 443 | Debug.Log("地图宽度: " + mapInfo.Width + " 地图高度: " + mapInfo.Height); 444 | // CGTool.Logger.Write("地图解析完成时间:" + DateTime.Now); 445 | return mapInfo; 446 | } 447 | 448 | } 449 | } 450 | -------------------------------------------------------------------------------- /example/Script/Util.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using CrossgateToolkit; 5 | 6 | public class Util 7 | 8 | { 9 | public static void Init() 10 | { 11 | Application.targetFrameRate = 60; 12 | CGTool.PATH = new CGTool.CGPath() 13 | { 14 | BIN = Application.persistentDataPath + "/bin", 15 | PAL = Application.persistentDataPath + "/pal", 16 | MAP = Application.persistentDataPath + "/map", 17 | BGM = Application.persistentDataPath + "/bgm", 18 | AUDIO = Application.persistentDataPath + "/se" 19 | }; 20 | CGTool.Init(); 21 | } 22 | // 获取距离目标单位直线方向一定距离的位置 23 | public static Vector2 GetTargetNearPosition(Vector2 fromPosition,Vector2 targetPosition,float distance) 24 | { 25 | Vector2 direction = targetPosition - fromPosition; 26 | Vector2 normalizedDirection = direction.normalized; 27 | 28 | // Vector2 point = targetPosition - normalizedDirection * distance; 29 | 30 | // 移动 C 点到圆上,使得 C 到 A 的距离等于半径 X 31 | // float distanceToMove = Vector2.Distance(point, fromPosition) - distance; 32 | Vector2 adjustedC = targetPosition - normalizedDirection * distance; 33 | 34 | return adjustedC; 35 | } 36 | 37 | //获取方向增量 38 | public static Vector2Int GetDirectionVector(Anime.DirectionType direction) 39 | { 40 | Vector2Int vector2 = Vector2Int.zero; 41 | switch (direction) 42 | { 43 | case Anime.DirectionType.North: 44 | vector2.x = -1; 45 | vector2.y = 1; 46 | break; 47 | case Anime.DirectionType.NorthEast: 48 | vector2.x = 0; 49 | vector2.y = 1; 50 | break; 51 | case Anime.DirectionType.East: 52 | vector2.x = 1; 53 | vector2.y = 1; 54 | break; 55 | case Anime.DirectionType.SouthEast: 56 | vector2.x = 1; 57 | vector2.y = 0; 58 | break; 59 | case Anime.DirectionType.South: 60 | vector2.x = 1; 61 | vector2.y = -1; 62 | break; 63 | case Anime.DirectionType.SouthWest: 64 | vector2.x = 0; 65 | vector2.y = -1; 66 | break; 67 | case Anime.DirectionType.West: 68 | vector2.x = -1; 69 | vector2.y = -1; 70 | break; 71 | case Anime.DirectionType.NorthWest: 72 | vector2.x = -1; 73 | vector2.y = 0; 74 | break; 75 | } 76 | 77 | return vector2; 78 | } 79 | 80 | // 获取方向上某距离的点 81 | public static Vector2 GetDirectionPoint(Vector2 fromPosition,Anime.DirectionType directionType,float distance) 82 | { 83 | Vector2 vector2 = GetDirectionVector(directionType); 84 | vector2 = vector2.normalized; 85 | Vector2 point = fromPosition + vector2 * distance; 86 | return point; 87 | } 88 | 89 | // 获取目标单位方向角度 90 | public static float GetTargetAngle(Vector2 fromPosition,Vector2 targetPosition) 91 | { 92 | Vector2 diff = targetPosition - fromPosition; 93 | float angle = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg; 94 | angle = angle - 90; 95 | return angle; 96 | } 97 | 98 | // 获取目标单位方向 99 | public static Anime.DirectionType GetTargetDirection(Vector2 fromPosition,Vector2 targetPosition) 100 | { 101 | Vector2 diff = targetPosition - fromPosition; 102 | float angle = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg; 103 | angle = angle - 90; 104 | 105 | if (angle <= 25 && angle > -25) return Anime.DirectionType.NorthEast; 106 | if (angle <= -25 && angle > -75) return Anime.DirectionType.East; 107 | if (angle <= -75 && angle > -105) return Anime.DirectionType.SouthEast; 108 | if (angle <= -105 && angle > -155) return Anime.DirectionType.South; 109 | if (angle <= -155 && angle > -205) return Anime.DirectionType.SouthWest; 110 | if (angle <= -205 && angle > -255) return Anime.DirectionType.West; 111 | if (angle <= -255 && angle > -285) return Anime.DirectionType.NorthWest; 112 | if (angle <= -285 && angle > -335) return Anime.DirectionType.North; 113 | if (angle <= -335 && angle > -385) return Anime.DirectionType.NorthEast; 114 | 115 | if (angle > 25 && angle < 75) return Anime.DirectionType.North; 116 | if (angle > 75 && angle < 105) return Anime.DirectionType.NorthWest; 117 | if (angle > 105 && angle < 155) return Anime.DirectionType.West; 118 | if (angle > 155 && angle < 205) return Anime.DirectionType.SouthWest; 119 | if (angle > 205 && angle < 255) return Anime.DirectionType.South; 120 | if (angle > 255 && angle < 285) return Anime.DirectionType.SouthEast; 121 | if (angle > 285 && angle < 335) return Anime.DirectionType.East; 122 | if (angle > 335 && angle < 385) return Anime.DirectionType.NorthEast; 123 | 124 | return Anime.DirectionType.East; 125 | } 126 | 127 | // 获取反方向 128 | public static Anime.DirectionType GetReverseDirection(Anime.DirectionType directionType) 129 | { 130 | switch (directionType) 131 | { 132 | case Anime.DirectionType.North: 133 | return Anime.DirectionType.South; 134 | case Anime.DirectionType.NorthEast: 135 | return Anime.DirectionType.SouthWest; 136 | case Anime.DirectionType.East: 137 | return Anime.DirectionType.West; 138 | case Anime.DirectionType.SouthEast: 139 | return Anime.DirectionType.NorthWest; 140 | case Anime.DirectionType.South: 141 | return Anime.DirectionType.North; 142 | case Anime.DirectionType.SouthWest: 143 | return Anime.DirectionType.NorthEast; 144 | case Anime.DirectionType.West: 145 | return Anime.DirectionType.East; 146 | case Anime.DirectionType.NorthWest: 147 | return Anime.DirectionType.SouthEast; 148 | default: 149 | return Anime.DirectionType.East; 150 | } 151 | } 152 | 153 | public static Anime.DirectionType GetRandomDirection() 154 | { 155 | int random = Random.Range(0, 8); 156 | switch (random) 157 | { 158 | case 0: 159 | return Anime.DirectionType.North; 160 | case 1: 161 | return Anime.DirectionType.NorthEast; 162 | case 2: 163 | return Anime.DirectionType.East; 164 | case 3: 165 | return Anime.DirectionType.SouthEast; 166 | case 4: 167 | return Anime.DirectionType.South; 168 | case 5: 169 | return Anime.DirectionType.SouthWest; 170 | case 6: 171 | return Anime.DirectionType.West; 172 | case 7: 173 | return Anime.DirectionType.NorthWest; 174 | default: 175 | return Anime.DirectionType.East; 176 | } 177 | } 178 | 179 | // 获取上一个方向 左旋 180 | public static Anime.DirectionType GetPrevDirection(Anime.DirectionType directionType) 181 | { 182 | switch (directionType) 183 | { 184 | case Anime.DirectionType.North: 185 | return Anime.DirectionType.NorthWest; 186 | case Anime.DirectionType.NorthEast: 187 | return Anime.DirectionType.North; 188 | case Anime.DirectionType.East: 189 | return Anime.DirectionType.NorthEast; 190 | case Anime.DirectionType.SouthEast: 191 | return Anime.DirectionType.East; 192 | case Anime.DirectionType.South: 193 | return Anime.DirectionType.SouthEast; 194 | case Anime.DirectionType.SouthWest: 195 | return Anime.DirectionType.South; 196 | case Anime.DirectionType.West: 197 | return Anime.DirectionType.SouthWest; 198 | case Anime.DirectionType.NorthWest: 199 | return Anime.DirectionType.West; 200 | default: 201 | return Anime.DirectionType.East; 202 | } 203 | } 204 | 205 | public static Anime.DirectionType GetDoublePrevDirection(Anime.DirectionType directionType) 206 | { 207 | switch (directionType) 208 | { 209 | case Anime.DirectionType.North: 210 | return Anime.DirectionType.West; 211 | case Anime.DirectionType.NorthEast: 212 | return Anime.DirectionType.NorthWest; 213 | case Anime.DirectionType.East: 214 | return Anime.DirectionType.North; 215 | case Anime.DirectionType.SouthEast: 216 | return Anime.DirectionType.NorthEast; 217 | case Anime.DirectionType.South: 218 | return Anime.DirectionType.East; 219 | case Anime.DirectionType.SouthWest: 220 | return Anime.DirectionType.SouthEast; 221 | case Anime.DirectionType.West: 222 | return Anime.DirectionType.South; 223 | case Anime.DirectionType.NorthWest: 224 | return Anime.DirectionType.SouthWest; 225 | default: 226 | return Anime.DirectionType.East; 227 | } 228 | } 229 | 230 | // 获取下一个方向 右旋 231 | public static Anime.DirectionType GetNextDirection(Anime.DirectionType directionType) 232 | { 233 | switch (directionType) 234 | { 235 | case Anime.DirectionType.North: 236 | return Anime.DirectionType.NorthEast; 237 | case Anime.DirectionType.NorthEast: 238 | return Anime.DirectionType.East; 239 | case Anime.DirectionType.East: 240 | return Anime.DirectionType.SouthEast; 241 | case Anime.DirectionType.SouthEast: 242 | return Anime.DirectionType.South; 243 | case Anime.DirectionType.South: 244 | return Anime.DirectionType.SouthWest; 245 | case Anime.DirectionType.SouthWest: 246 | return Anime.DirectionType.West; 247 | case Anime.DirectionType.West: 248 | return Anime.DirectionType.NorthWest; 249 | case Anime.DirectionType.NorthWest: 250 | return Anime.DirectionType.North; 251 | default: 252 | return Anime.DirectionType.East; 253 | } 254 | } 255 | 256 | // 获取下第二个方向 257 | public static Anime.DirectionType GetDoubleNextDirection(Anime.DirectionType directionType) 258 | { 259 | switch (directionType) 260 | { 261 | case Anime.DirectionType.North: 262 | return Anime.DirectionType.East; 263 | case Anime.DirectionType.NorthEast: 264 | return Anime.DirectionType.SouthEast; 265 | case Anime.DirectionType.East: 266 | return Anime.DirectionType.South; 267 | case Anime.DirectionType.SouthEast: 268 | return Anime.DirectionType.SouthWest; 269 | case Anime.DirectionType.South: 270 | return Anime.DirectionType.West; 271 | case Anime.DirectionType.SouthWest: 272 | return Anime.DirectionType.NorthWest; 273 | case Anime.DirectionType.West: 274 | return Anime.DirectionType.North; 275 | case Anime.DirectionType.NorthWest: 276 | return Anime.DirectionType.NorthEast; 277 | default: 278 | return Anime.DirectionType.East; 279 | } 280 | } 281 | 282 | public static List TestSerial = new List() 283 | { 284 | // 旧版单位 285 | // 100000, 100001, 100002, 100003, 100004, 100005, 100006, 100007, 100008, 100009, 100010, 100011, 100012, 286 | // 100013, 100014, 100015, 100016, 100017, 100018, 100019, 100020, 100021, 100022, 100023, 100025, 100026, 287 | // 100027, 100028, 100029, 100030, 100031, 100032, 100033, 100034, 100035, 100036, 100037, 100038, 100039, 288 | // 100040, 100041, 100042, 100043, 100044, 100045, 100046, 100047, 100048, 100050, 100051, 100052, 100053, 289 | // 100054, 100055, 100056, 100057, 100058, 100059, 100060, 100061, 100062, 100063, 100064, 100065, 100066, 290 | // 100067, 100068, 100069, 100070, 100071, 100072, 100073, 100075, 100076, 100077, 100078, 100079, 100080, 291 | // 100081, 100082, 100083, 100084, 100085, 100086, 100087, 100088, 100089, 100090, 100091, 100092, 100093, 292 | // 100094, 100095, 100096, 100097, 100098, 100100, 100101, 100102, 100103, 100104, 100105, 100106, 100107, 293 | // 100108, 100109, 100110, 100111, 100112, 100113, 100114, 100115, 100116, 100117, 100118, 100119, 100120, 294 | // 100121, 100122, 100123, 100125, 100126, 100127, 100128, 100129, 100130, 100131, 100132, 100133, 100134, 295 | // 100135, 100136, 100137, 100138, 100139, 100140, 100141, 100142, 100143, 100144, 100145, 100146, 100147, 296 | // 100148, 100150, 100151, 100152, 100153, 100154, 100155, 100156, 100157, 100158, 100159, 100160, 100161, 297 | // 100162, 100163, 100164, 100165, 100166, 100167, 100168, 100169, 100170, 100171, 100172, 100173, 100250, 298 | // 100251, 100252, 100253, 100254, 100255, 100256, 100257, 100258, 100259, 100260, 100261, 100262, 100263, 299 | // 100264, 100265, 100266, 100267, 100268, 100269, 100270, 100271, 100272, 100273, 100275, 100276, 100277, 300 | // 100278, 100279, 100280, 100281, 100282, 100283, 100284, 100285, 100286, 100287, 100288, 100289, 100290, 301 | // 100291, 100292, 100293, 100294, 100295, 100296, 100297, 100298, 100300, 100301, 100302, 100303, 100304, 302 | // 100305, 100306, 100307, 100308, 100309, 100310, 100311, 100312, 100313, 100314, 100315, 100316, 100317, 303 | // 100318, 100319, 100320, 100321, 100322, 100323, 100325, 100326, 100327, 100328, 100329, 100330, 100331, 304 | // 100332, 100333, 100334, 100335, 100336, 100337, 100338, 100339, 100340, 100341, 100342, 100343, 100344, 305 | // 100345, 100346, 100347, 100348, 100350, 100351, 100352, 100353, 100354, 100355, 100356, 100357, 100358, 306 | // 100359, 100360, 100361, 100362, 100363, 100364, 100365, 100366, 100367, 100368, 100369, 100370, 100371, 307 | // 100372, 100373, 100375, 100376, 100377, 100378, 100379, 100380, 100381, 100382, 100383, 100384, 100385, 308 | // 100386, 100387, 100388, 100389, 100390, 100391, 100392, 100393, 100394, 100395, 100396, 100397, 100398, 309 | // 100400, 100401, 100402, 100403, 100404, 100405, 100406, 100407, 100408, 100409, 100410, 100411, 100412, 310 | // 100413, 100414, 100415, 100416, 100417, 100418, 100419, 100420, 100421, 100422, 100423, 100425, 100426, 311 | // 100427, 100428, 100429, 100430, 100450, 100451, 100452, 100453, 100454, 100455, 100475, 100476, 100477, 312 | // 100478, 100479, 100480, 100500, 100501, 100502, 100503, 100504, 100505, 100525, 100526, 100527, 100528, 313 | // 100529, 100530, 100550, 100551, 100552, 100553, 100554, 100555, 100575, 100576, 100577, 100578, 100579, 314 | // 100580, 100600, 100601, 100602, 100603, 100604, 100605, 100625, 100626, 100627, 100628, 100629, 100630, 315 | // 100650, 100651, 100652, 100653, 100654, 100655, 100675, 100676, 100677, 100678, 100679, 100680, 100700, 316 | // 100701, 100702, 100703, 100704, 100705, 100725, 100726, 100727, 100728, 100729, 100730, 100750, 100751, 317 | // 100752, 100753, 100754, 100755, 100800, 100801, 100802, 100803, 100804, 100805, 100900, 100901, 318 | 319 | // 新版单位 320 | 105000, 105001, 105002, 105003, 105004, 105005, 105006, 105007, 105008, 105009, 105010, 105011, 105012, 321 | 105013, 105014, 105014, 105016, 105017, 105018, 105019, 105020, 105021, 105022, 105023, 105025, 105026, 322 | 105027, 105028, 105029, 105030, 105031, 105032, 105033, 105034, 105035, 105036, 105037, 105038, 105039, 323 | 105040, 105041, 105042, 105043, 105044, 105045, 105046, 105047, 105048, 105050, 105051, 105052, 105053, 324 | 105054, 105055, 105056, 105057, 105058, 105059, 105060, 105061, 105062, 105063, 105064, 105065, 105066, 325 | 105067, 105068, 105069, 105070, 105071, 105072, 105073, 105075, 105076, 105077, 105078, 105079, 105080, 326 | 105081, 105082, 105083, 105084, 105085, 105086, 105087, 105088, 105089, 105090, 105091, 105092, 105093, 327 | 105094, 105095, 105096, 105097, 105098, 105100, 105101, 105102, 105103, 105104, 105105, 105106, 105107, 328 | 105108, 105109, 105110, 105111, 105112, 105113, 105114, 105115, 105116, 105117, 105118, 105119, 105120, 329 | 105121, 105122, 105123, 105125, 105126, 105127, 105128, 105129, 105130, 105131, 105132, 105133, 105134, 330 | 105135, 105136, 105137, 105138, 105139, 105140, 105141, 105142, 105143, 105144, 105145, 105146, 105147, 331 | 105148, 105150, 105151, 105152, 105153, 105154, 105155, 105156, 105157, 105158, 105159, 105160, 105161, 332 | 105162, 105163, 105164, 105165, 105166, 105167, 105168, 105169, 105170, 105171, 105172, 105173, 105250, 333 | 105251, 105252, 105253, 105254, 105255, 105256, 105257, 105258, 105259, 105260, 105261, 105262, 105263, 334 | 105264, 105265, 105266, 105267, 105268, 105269, 105270, 105271, 105272, 105273, 105275, 105276, 105277, 335 | 105278, 105279, 105280, 105281, 105282, 105283, 105284, 105285, 105286, 105287, 105288, 105289, 105290, 336 | 105291, 105292, 105293, 105294, 105295, 105296, 105297, 105298, 105300, 105301, 105302, 105303, 105304, 337 | 105305, 105306, 105307, 105308, 105309, 105310, 105311, 105312, 105313, 105314, 105315, 105316, 105317, 338 | 105318, 105319, 105320, 105321, 105322, 105323, 105325, 105326, 105327, 105328, 105329, 105330, 105331, 105332, 339 | 105333, 105334, 105335, 105336, 105337, 105338, 105339, 105340, 105341, 105342, 105343, 105344, 105345, 340 | 105346, 105347, 105348, 105350, 105351, 105352, 105353, 105354, 105355, 105356, 105357, 105358, 105359, 341 | 105360, 105361, 105362, 105363, 105364, 105365, 105366, 105367, 105368, 105369, 105370, 105371, 105372, 342 | 105373, 105375, 105376, 105377, 105378, 105379, 105380, 105381, 105382, 105383, 105384, 105385, 105386, 343 | 105387, 105388, 105389, 105390, 105391, 105392, 105393, 105394, 105395, 105396, 105397, 105398, 105400, 344 | 105401, 105402, 105403, 105404, 105405, 105406, 105407, 105408, 105409, 105410, 105411, 105412, 105413, 345 | 105414, 105415, 105416, 105417, 105418, 105419, 105420, 105421, 105422, 105423, 106000, 106001, 106002, 346 | 106003, 106004, 106005, 106006, 106007, 106008, 106009, 106010, 106011, 106012, 106013, 106014, 106015, 347 | 106016, 106017, 106018, 106019, 106020, 106021, 106022, 106023, 106025, 106026, 106027, 106028, 106029, 348 | 106030, 106031, 106032, 106033, 106034, 106035, 106036, 106037, 106038, 106039, 106040, 106041, 106042, 349 | 106043, 106044, 106045, 106046, 106047, 106048, 106050, 106051, 106052, 106053, 106054, 106055, 106056, 350 | 106057, 106058, 106059, 106060, 106061, 106062, 106063, 106064, 106065, 106066, 106067, 106068, 106069, 351 | 106070, 106071, 106072, 106073, 106075, 106076, 106077, 106078, 106079, 106080, 106081, 106082, 106083, 352 | 106084, 106085, 106086, 106087, 106088, 106089, 106090, 106091, 106092, 106093, 106094, 106095, 106096, 353 | 106097, 106098, 106100, 106101, 106102, 106103, 106104, 106105, 106106, 106107, 106108, 106109, 106110, 354 | 106111, 106112, 106113, 106114, 106115, 106116, 106117, 106118, 106119, 106120, 106121, 106122, 106123, 355 | 106125, 106126, 106127, 106128, 106129, 106130, 106131, 106132, 106133, 106134, 106135, 106136, 106137, 356 | 106138, 106139, 106140, 106141, 106142, 106143, 106144, 106145, 106146, 106147, 106148, 106150, 106151, 357 | 106152, 106153, 106154, 106155, 106156, 106157, 106158, 106159, 106160, 106161, 106162, 106163, 106164, 358 | 106165, 106166, 106167, 106168, 106169, 106170, 106171, 106172, 106173, 106250, 106251, 106252, 106253, 359 | 106254, 106255, 106256, 106257, 106258, 106259, 106260, 106261, 106262, 106263, 106264, 106265, 106266, 360 | 106267, 106268, 106269, 106270, 106271, 106272, 106273, 106275, 106276, 106277, 106278, 106279, 106280, 361 | 106281, 106282, 106283, 106284, 106285, 106286, 106287, 106288, 106289, 106290, 106291, 106292, 106293, 362 | 106294, 106295, 106296, 106297, 106298, 106300, 106301, 106302, 106303, 106304, 106305, 106306, 106307, 363 | 106308, 106309, 106310, 106311, 106312, 106313, 106314, 106315, 106316, 106317, 106318, 106319, 106320, 364 | 106321, 106322, 106323, 106325, 106326, 106327, 106328, 106329, 106330, 106331, 106332, 106333, 106334, 365 | 106335, 106336, 106337, 106338, 106339, 106340, 106341, 106342, 106343, 106344, 106345, 106346, 106347, 366 | 106348, 106350, 106351, 106352, 106353, 106354, 106355, 106356, 106357, 106358, 106359, 106360, 106361, 367 | 106362, 106363, 106364, 106365, 106366, 106367, 106368, 106369, 106370, 106371, 106372, 106373, 106375, 368 | 106376, 106377, 106378, 106379, 106380, 106381, 106382, 106383, 106384, 106385, 106386, 106387, 106388, 369 | 106389, 106390, 106391, 106392, 106393, 106394, 106395, 106396, 106397, 106398, 106400, 106401, 106402, 370 | 106403, 106404, 106405, 106406, 106407, 106408, 106409, 106410, 106411, 106412, 106413, 106414, 106415, 371 | 106416, 106417, 106418, 106419, 106420, 106421, 106422, 106423, 106425, 106426, 106427, 106428, 106429, 372 | 106430, 106450, 106451, 106452, 106453, 106454, 106455, 106475, 106476, 106477, 106478, 106479, 106480, 373 | 106500, 106501, 106502, 106503, 106504, 106505, 106525, 106526, 106527, 106528, 106529, 106530, 106550, 374 | 106551, 106552, 106553, 106554, 106555, 106575, 106576, 106577, 106578, 106579, 106580, 106600, 106601, 375 | 106602, 106603, 106604, 106605, 106625, 106626, 106627, 106628, 106629, 106630, 106650, 106651, 106652, 376 | 106653, 106654, 106655, 106675, 106676, 106677, 106678, 106679, 106680, 106700, 106701, 106702, 106703, 377 | 106704, 106705, 106725, 106726, 106727, 106728, 106729, 106730, 106750, 106751, 106752, 106753, 106754, 378 | 106755 379 | }; 380 | public static uint GetRandomSerial() 381 | { 382 | int random = Random.Range(0, TestSerial.Count); 383 | return TestSerial[random]; 384 | } 385 | 386 | public static Anime.ActionType GetNextAction(Anime.ActionType actionType) 387 | { 388 | int action = (int)actionType; 389 | action++; 390 | if (action > 20) action = 0; 391 | return (Anime.ActionType)action; 392 | } 393 | } 394 | --------------------------------------------------------------------------------