活动介绍
file-type

矢量字体战斗:Vector Battle的字体解析

RAR文件

下载需积分: 5 | 13KB | 更新于2025-08-30 | 176 浏览量 | 0 下载量 举报 收藏
download 立即下载
从给定的文件信息来看,"Vector Battle"作为标题和描述可能指向一个与向量图形相关的项目或者游戏。而标签"字体"以及提供的文件列表暗示这个项目涉及到特定的字体文件Vectorbattle.ttf,以及一个可能是该字体在游戏或项目中应用的示例图形文件vectorbattle1.gif。 1. **向量图形基础** 向量图形使用点、线、曲线和多边形这些几何对象来描述图像。这些对象组成的数学方程定义了它们在空间中的位置和形状,因此向量图形可以无限放大或缩小而不失真。这与位图图像形成对比,位图是通过像素阵列来表示的,放大后容易出现锯齿状边缘。 2. **字体文件格式** 在描述中提及的文件Vectorbattle.ttf是一个字体文件,具体来说它属于TrueType字体格式。TrueType字体是由苹果公司和微软公司共同开发的一种字体技术,广泛用于个人计算机和操作系统的图形用户界面中。TrueType字体具有很高的可扩展性,并且它们能够提供比其他字体格式更精确的字体轮廓渲染。 3. **TrueType字体的特点** TrueType字体格式的核心优势包括:可以在不同的分辨率下都能保持优秀的打印质量;支持复杂的书写系统,如阿拉伯文和印度文;它们包含字体设计者的布局和格式设置指令,使得在屏幕显示时字体能够保持良好的可读性和美观度。 4. **图形文件格式简介(GIF)** 文件列表中的vectorbattle1.gif,是一个GIF(图形交换格式)文件。GIF是一种无损的、8位色的图像文件格式,它支持动画,并且被广泛用于网页图像上。GIF使用调色板的颜色索引来减少文件大小,使得它在20世纪90年代网络连接速度较慢时非常流行。GIF格式支持最多8位色(即256色),使用LZW(Lempel-Ziv-Welch)压缩算法,这种算法可以帮助减少文件大小,尤其适用于动画制作,因为它在存储多帧图像时只保存颜色的变化,而不是每一帧的完整图像数据。 5. **GIF动画原理** GIF动画通过一系列图像帧来实现动画效果,每帧都是一个独立的图像,GIF格式文件将这些图像帧顺序存储并以一定速度循环播放,从而达到动画的效果。由于GIF文件的这种特性,它被广泛用于网络上制作简单的动画效果和表情包。 6. **项目中的应用** 综合标题、描述、标签和文件列表,可以推测"Vector Battle"可能是一个涉及到向量图形和自定义字体设计的应用或游戏。这可能意味着用户或玩家在使用该应用或游戏的过程中会接触到带有Vectorbattle.ttf字体文字的游戏界面或元素,并且可能会看到包含向量图形的GIF动画展示。这在游戏设计中很常见,因为它允许开发者创建视觉效果丰富且可调整大小的图形界面,同时也能保证在不同平台上的兼容性和输出质量。 综上所述,"Vector Battle"这个项目通过结合向量图形和定制字体,旨在提供一种视觉效果丰富且具有高度可定制的界面和动画体验。这种设计思路在现代游戏设计、应用程序开发和网络动画制作中变得越来越受欢迎,因为它能够提供清晰的图形质量,同时在不同的显示设备和分辨率下保持视觉一致性和可读性。

相关推荐

filetype

using System.Collections; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; public enum Battle { Start, PlayerTurn, EnemyTurn, Lose, Win } public class BattleSystem : MonoBehaviour { public enum gameover{win,lose} public Battle State; public float typingSpeed = 0.05f; private bool isTyping = false; public GameObject PlayerPrefeb; public GameObject EnemyPrefeb; public Transform PlayerPosition; public Transform EnemyPosition; private Playermessage playerpeople; private Enemymessage emenypeople; public EnemyBattleHUD enemyHUD; public PlayerBattleHUD playerHUD; public TextMeshProUGUI Text; public GameObject F; public GameObject m; public GameObject back; public GameObject select1; public GameObject select2; public Color flash; private Color Originalcolor; public float Time; public UnityEngine.UI.Image image; public Animator animator; private Camera mainCamera; private Vector3 originalCameraPosition; public UnityEngine.UI.Image attackphoto; public UnityEngine.UI.Image attackphoto2; void Start() { mainCamera = Camera.main; if (mainCamera != null) { originalCameraPosition = mainCamera.transform.localPosition; } State = Battle.Start; StartCoroutine(SetupBattle()); } private IEnumerator SetupBattle() { GameObject player = Instantiate(PlayerPrefeb, PlayerPosition); playerpeople = player.GetComponent<Playermessage>(); GameObject emeny = Instantiate(EnemyPrefeb, EnemyPosition); emenypeople = emeny.GetComponent<Enemymessage>(); playerHUD.SetHUD(playerpeople); enemyHUD.SetHUD(emenypeople); // 显示开场信息(带打字效果) yield return StartCoroutine(TypeText("Let me feel your power now, don't make me bored^_^", 0.5f)); yield return new WaitForSeconds(0.5f); if (F != null) F.SetActive(false); if (m != null) m.SetActive(true); yield return StartCoroutine(TypeText("I can't lose here", 0.5f)); yield return new WaitForSeconds(0.5f); if (m != null) m.SetActive(false); yield return StartCoroutine(TypeText("--Please consider your decision--", 2f)); State = Battle.PlayerTurn; PlayerTurn(); } // 玩家回合逻辑 private void PlayerTurn() { StartCoroutine(TypeText("Choose your action...", 0f)); } public void OnAttackButton() { if (State != Battle.PlayerTurn) return; StartCoroutine(PlayerAttack()); } private IEnumerator PlayerAttack() { yield return StartCoroutine(TypeText("Get out of my way!!!", 0f)); yield return new WaitForSeconds(1f); attackphoto.gameObject.SetActive(true); yield return new WaitForSeconds(0.5f); float damageDealt = GetComponent<SpeacialAttack>().GetDamage(); yield return StartCoroutine(TypeText($"Dealt {damageDealt} damage!", 0f)); yield return new WaitForSeconds(1f); attackphoto.gameObject.SetActive(false); bool IsDead = emenypeople.TakeDamage((int)playerpeople.atk, (int)emenypeople.def); enemyHUD.SetHUD(emenypeople); // 显示伤害数值 if (IsDead) { State = Battle.Win; EndBattle(); } else { State = Battle.EnemyTurn; StartCoroutine(EnemyTurn()); } } private IEnumerator EnemyTurn() { yield return StartCoroutine(TypeText("Looking my eyes...", 0f)); yield return new WaitForSeconds(0.5f); attackphoto2.gameObject.SetActive(true); yield return new WaitForSeconds(0.5f);animator.SetTrigger("shake"); StartCoroutine(ShakeCamera(0.4f, 0.4f)); Originalcolor = image.color; StartCoroutine(flashboom()); attackphoto2.gameObject.SetActive(false); float damageDealt = GetComponent<SpeacialAttack>().GetDamage(); yield return StartCoroutine(TypeText($"Took {damageDealt} damage!", 0f)); bool IsDead = playerpeople.TakeDamage(); playerHUD.SetHUD(playerpeople); yield return new WaitForSeconds(1f); if (IsDead) { State = Battle.Lose; EndBattle(); } else { State = Battle.PlayerTurn; PlayerTurn(); } } private void EndBattle() { if (State == Battle.Win) { StartCoroutine(TypeText("Victory is mine!", 0f)); EndBattle(true); } else if (State == Battle.Lose) { StartCoroutine(TypeText("Defeat... I'll be back!", 0f)); EndBattle(false); } select1.SetActive(false); select2.SetActive(false); back.SetActive(true); } const string BATTLE_RESULT_KEY = "LastBattleResult"; public void EndBattle(bool isWin) { PlayerPrefs.SetInt(BATTLE_RESULT_KEY, isWin ? 1 : 0); PlayerPrefs.Save(); SceneManager.LoadScene("Traning"); } IEnumerator flashboom()//受击红屏效果 { image.color = flash; yield return new WaitForSeconds(Time); image.color = Originalcolor; } private IEnumerator ShakeCamera(float duration = 0.5f, float magnitude = 0.4f) { Vector3 originalPos = mainCamera.transform.localPosition; float elapsed = 0f; AnimationCurve attenuationCurve = AnimationCurve.EaseInOut(0, 1, 1, 0); while (elapsed < duration) { float attenuation = attenuationCurve.Evaluate(elapsed / duration); float x = Mathf.PerlinNoise(UnityEngine.Time.time * 30f, 0) * 2 - 1; float y = Mathf.PerlinNoise(0, UnityEngine.Time.time * 30f) * 2 - 1; // 5. 应用衰减后的震动幅度 Vector3 shakeOffset = new Vector3(x, y, 0) * magnitude * attenuation; mainCamera.transform.localPosition = originalPos + shakeOffset; // 6. 使用unscaledDeltaTime确保时间精确 elapsed += UnityEngine.Time.unscaledDeltaTime; yield return null; } // 7. 平滑回归原位 float returnDuration = 0.2f; float returnElapsed = 0f; Vector3 currentPos = mainCamera.transform.localPosition; while (returnElapsed < returnDuration) { mainCamera.transform.localPosition = Vector3.Lerp( currentPos, originalPos, returnElapsed / returnDuration ); returnElapsed += UnityEngine.Time.unscaledDeltaTime; yield return null; } mainCamera.transform.localPosition = originalPos; } public IEnumerator TypeText(string sentence, float initialDelay = 0f) { if (Text == null) yield break; isTyping = true; yield return new WaitForSeconds(initialDelay); Text.text = ""; foreach (char letter in sentence.ToCharArray()) { Text.text += letter; yield return new WaitForSeconds(typingSpeed); } isTyping = false; } }using UnityEngine; public class Playermessage : MonoBehaviour { public string Name; public int LV; public float atk; public float def; public float defens; public float maxHP; public float currentHP; // Start is called before the first frame update public bool TakeDamage() { float damageDealt = GetComponent<SpeacialAttack>().GetDamage(); currentHP -= damageDealt ; if (currentHP <= 0) return true; else return false; } void Start() { } // Update is called once per frame void Update() { } } 报错NullReferenceException: Object reference not set to an instance of an object Playermessage.TakeDamage () (at Assets/Playermessage.cs:15) BattleSystem+<EnemyTurn>d__32.MoveNext () (at Assets/BattleSystem.cs:139) UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at /Volumes/jenkins1/sharedspace/ra_2022.3/Runtime/Export/Scripting/Coroutines.cs:17)

filetype

using UnityEngine; using System; using System.Collections; using XLua; namespace LuaFramework { [LuaCallCSharp] public class ResourceManager : Manager { public static ResourceManager _instance; public LuaFunction onDestroy; private WWW _www; private LuaFunction onProgress; void Awake() { _instance = this; } // 修复1: 使用传统属性语法替代表达式体属性 public static ResourceManager Instance { get { return _instance; } } public void CreatUIObject(string UIPath, string objname, LuaFunction callBack = null) { #if UNITY_EDITOR if (!AppConst.UpdateMode) { string path = "datingui_" + AppConst.UIVersion.ToString() + "/" + UIPath + objname; UnityEngine.Object prefab = Resources.Load(path, typeof(GameObject)); if (prefab != null) { GameObject obj = Instantiate(prefab) as GameObject; obj.transform.localScale = Vector3.one; obj.transform.localPosition = Vector3.zero; if (callBack != null) { callBack.Call(obj); } } else { if (callBack != null) { callBack.Call(null); } } } else { StartCoroutine(LoadObj(AppConst.FrameworkRoot + "/datingui_" + AppConst.UIVersion + "/" + UIPath + objname + ".u3d", objname, callBack)); } #else StartCoroutine(LoadObj(AppConst.FrameworkRoot + "/datingui_" + AppConst.UIVersion + "/" + UIPath + objname + ".u3d", objname, callBack)); #endif } public void CreatGameObject(string GameName, string path, string objname, LuaFunction callBack = null) { #if UNITY_EDITOR if (!AppConst.UpdateMode) { GameObject obj = Instantiate(Resources.Load<GameObject>("gameui" + AppConst.UIVersion + "/" + GameName + "/" + path + objname)); if (obj != null) { obj.transform.localScale = Vector3.one; obj.transform.localPosition = Vector3.zero; } if (callBack != null) { callBack.Call(obj); } } else { string path_ = AppConst.FrameworkRoot + "/gameui" + AppConst.UIVersion + "/" + GameName + "/" + path + objname + ".u3d"; StartCoroutine(LoadObj(path_, objname, callBack)); } #else string path_ = AppConst.FrameworkRoot + "/gameui"+AppConst.UIVersion +"/" + GameName + "/" + path + objname + ".u3d"; StartCoroutine(LoadObj(path_, objname, callBack)); #endif } public void setProgressUpdate(LuaFunction callback) { onProgress = callback; } public void resetProgressUpdate() { onProgress = null; _www = null; } float jindus = 0.0f; void Update() { #if UNITY_ANDROID if (_www != null && onProgress != null) { onProgress.Call(_www.progress); } #else if (onProgress != null) { onProgress.Call(jindus); } #endif } IEnumerator LoadObj(string bundlePath, string ObjName, LuaFunction callBack = null) { AssetBundle built = null; #if UNITY_ANDROID string path_2 = "file:///" + bundlePath; WWW www = new WWW(@path_2); if (onProgress != null) { _www = www; } yield return www; if (www.error == null) { built = www.assetBundle; } else { Debug.Log("www error: " + www.error + " at path: " + path_2); } #else string path_ = bundlePath; byte[] data = null; if (System.IO.File.Exists(path_)) { System.IO.FileStream file_ = new System.IO.FileStream(path_, System.IO.FileMode.Open, System.IO.FileAccess.Read); data = new byte[file_.Length]; int redline = 0; int allnum = 0; while (true) { byte[] reddata = new byte[1024000]; redline = file_.Read(reddata, 0, reddata.Length); if (redline <= 0) { jindus = 1.0f; break; } else { System.Array.Copy(reddata, 0, data, allnum, redline); allnum += redline; jindus = (float)allnum / (float)data.Length; } yield return null; } file_.Close(); file_.Dispose(); } if (data != null) { built = AssetBundle.LoadFromMemory(data); } #endif GameObject obj = null; if (built != null) { UnityEngine.Object asset = built.LoadAsset(ObjName); if (asset != null) { obj = Instantiate(asset) as GameObject; if (obj != null) { obj.transform.localScale = Vector3.one; obj.transform.localPosition = Vector3.zero; } } built.Unload(false); } if (callBack != null) { callBack.Call(obj); } #if UNITY_ANDROID www.Dispose(); #endif yield break; } void OnDestroy() { if (onDestroy != null) { onDestroy.Call(); } } } }这个是Unity5.3.8版本,在不影响兼容的情况帮我优化代码,并且把新代码完整版生成文件可以直接保存使用

filetype

using System.Collections.Generic; using UnityEngine; using TMPro; using System.Collections; public class DialogueManager : MonoBehaviour { public enum DialogueState { Before, Win, Lost } public static DialogueManager Instance; [Header("UI Elements")] public TextMeshProUGUI tmpText; public float typingSpeed = 0.05f; [Header("Dialogue Content")] public List<string> beforeBattleDialogues = new List<string>(); public List<string> winDialogues = new List<string>(); public List<string> lostDialogues = new List<string>(); private bool isTyping = false; private Coroutine typingCoroutine; private string currentSentence; private DialogueState currentState = DialogueState.Before; private int currentDialogueIndex = 0; private List<string> currentDialogueList; void Start() { int result = PlayerPrefs.GetInt("LastBattleResult", -1); if(result == 1) { Debug.Log("你赢了"); // 胜利处理 } else if(result == 0) { Debug.Log("你失败了"); // 失败处理 } else { Debug.Log("战斗前"); } // 清除状态 PlayerPrefs.DeleteKey("LastBattleResult"); } void Awake() { if (Instance == null) { Instance = this; } else { Destroy(gameObject); } // 初始化当前对话列表 currentDialogueList = beforeBattleDialogues; } void Update() { // 添加跳过功能:按E键跳过当前打字效果 if (Input.GetKeyDown(KeyCode.E) && isTyping) { SkipTyping(); } // 按E键继续下一句对话 else if (Input.GetKeyDown(KeyCode.E) && !isTyping && tmpText.gameObject.activeSelf) { NextSentence(); } } // 设置当前对话状态 public void SetDialogueState(DialogueState newState) { currentState = newState; currentDialogueIndex = 0; switch (newState) { case DialogueState.Before: currentDialogueList = beforeBattleDialogues; break; case DialogueState.Win: currentDialogueList = winDialogues; break; case DialogueState.Lost: currentDialogueList = lostDialogues; break; } // 自动开始新状态的对话 StartStateDialogue(); Debug.Log("已完成最新的更新"); } // 启动当前状态的对话 public void StartStateDialogue() { if (currentDialogueList == null || currentDialogueList.Count == 0) return; // 如果正在显示其他文本,先停止 if (isTyping) { StopCoroutine(typingCoroutine); } // 确保索引在有效范围内 currentDialogueIndex = Mathf.Clamp(currentDialogueIndex, 0, currentDialogueList.Count - 1); currentSentence = currentDialogueList[currentDialogueIndex]; // 暂停玩家移动 playercontrol player = FindObjectOfType<playercontrol>(); if (player != null) player.canMove = false; // 锁定玩家输入 Cursor.lockState = CursorLockMode.None; Cursor.visible = true; // 显示对话框UI tmpText.gameObject.SetActive(true); // 启动打字效果协程 typingCoroutine = StartCoroutine(TypeSentence(currentSentence)); } // 显示下一句对话 public void NextSentence() { currentDialogueIndex++; if (currentDialogueIndex < currentDialogueList.Count) { StartStateDialogue(); } else { // 对话结束 EndDialogue(); } } IEnumerator TypeSentence(string sentence) { isTyping = true; tmpText.text = ""; // 逐字显示 foreach (char letter in sentence.ToCharArray()) { tmpText.text += letter; yield return new WaitForSeconds(typingSpeed); } isTyping = false; } // 跳过当前打字效果 public void SkipTyping() { if (isTyping) { StopCoroutine(typingCoroutine); tmpText.text = currentSentence; isTyping = false; } } public void EndDialogue() { // 如果还在打字,先停止打字 if (isTyping) { StopCoroutine(typingCoroutine); } // 恢复玩家移动 playercontrol player = FindObjectOfType<playercontrol>(); if (player != null) player.canMove = true; // 恢复输入锁定 Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; tmpText.gameObject.SetActive(false); } } using System.Collections; using UnityEngine; using UnityEngine.UI; using TMPro; using UnityEngine.SceneManagement; public class BattleSystem : MonoBehaviour { public enum BattleState { Start, PlayerTurn, EnemyTurn, Win, Lose } public BattleState state; // 角色引用 public GameObject playerPrefab; public GameObject enemyPrefab; public Transform playerBattleStation; public Transform enemyBattleStation; private Playermessage playerUnit; private Enemymessage enemyUnit; // UI组件 public PlayerBattleHUD playerHUD; public EnemyBattleHUD enemyHUD; public TMP_Text dialogueText; // 战斗效果 public Image attackphoto; public Image attackphoto2; public Image image; public Animator animator; public Camera mainCamera; public Image image1; // 颜色变量 private Color Originalcolor; // 战斗开始 void Start() { state = BattleState.Start; StartCoroutine(SetupBattle()); } // 初始化战斗 IEnumerator SetupBattle() { // 实例化角色 GameObject playerGO = Instantiate(playerPrefab, playerBattleStation); playerUnit = playerGO.GetComponent<Playermessage>(); GameObject enemyGO = Instantiate(enemyPrefab, enemyBattleStation); enemyUnit = enemyGO.GetComponent<Enemymessage>(); // 设置HUD playerHUD.SetHUD(playerUnit); enemyHUD.SetHUD(enemyUnit); // 开场对话 yield return StartCoroutine(TypeText($"Let me feel your power now, don't make me bored^_^", 0.05f)); yield return new WaitForSeconds(0.5f); image1.gameObject.SetActive(false); // 省略部分对话... yield return StartCoroutine(TypeText("--Please consider your decision--", 0.05f)); yield return new WaitForSeconds(0.5f); state = BattleState.PlayerTurn; PlayerTurn(); } // 玩家回合 private void PlayerTurn() { StartCoroutine(TypeText("Choose your action...", 0f)); } // 玩家攻击 public void OnAttackButton() { if (state != BattleState.PlayerTurn) return; StartCoroutine(PlayerAttack()); } // 玩家攻击协程 private IEnumerator PlayerAttack() { yield return StartCoroutine(TypeText("Get out of my way!!!", 0f)); yield return new WaitForSeconds(1f); // 显示攻击特效 attackphoto.gameObject.SetActive(true); yield return new WaitForSeconds(0.2f); // 计算伤害 float damageDealt = playerUnit.CalculateDamage(); // 显示伤害文本 yield return StartCoroutine(TypeText($"Dealt {damageDealt:F1} damage!", 0f)); yield return new WaitForSeconds(1f); // 隐藏攻击特效 attackphoto.gameObject.SetActive(false); // 敌人承受伤害 bool isDead = enemyUnit.TakeDamage(damageDealt); enemyHUD.SetHP(enemyUnit.CurrentHealth); if (isDead) { state = BattleState.Win; StartCoroutine(EndBattle()); } else { state = BattleState.EnemyTurn; StartCoroutine(EnemyTurn()); } } // 敌人回合 private IEnumerator EnemyTurn() { yield return StartCoroutine(TypeText("Looking my eyes...", 0f)); yield return new WaitForSeconds(0.5f); // 显示攻击特效 attackphoto2.gameObject.SetActive(true); yield return new WaitForSeconds(0.2f); // 屏幕震动效果 animator.SetTrigger("shake"); StartCoroutine(ShakeCamera(0.4f, 0.4f)); // 闪光效果 Originalcolor = image.color; StartCoroutine(FlashBoom()); // 计算伤害 float damageDealt = enemyUnit.CalculateDamage(); yield return StartCoroutine(TypeText($"Took {damageDealt:F1} damage!", 0f)); // 隐藏攻击特效 attackphoto2.gameObject.SetActive(false); yield return new WaitForSeconds(0.5f); // 玩家承受伤害 bool isDead = playerUnit.TakeDamage(damageDealt); playerHUD.SetHP(playerUnit.CurrentHealth); yield return new WaitForSeconds(1f); if (isDead) { state = BattleState.Lose; StartCoroutine(EndBattle()); } else { state = BattleState.PlayerTurn; PlayerTurn(); } } // 结束战斗 private IEnumerator EndBattle() { if (state == BattleState.Win) { yield return StartCoroutine(TypeText("Victory is mine!", 0f)); } else if (state == BattleState.Lose) { yield return StartCoroutine(TypeText("Defeat... I'll be back!", 0f)); } // 返回游戏场景 yield return new WaitForSeconds(2f); SceneManager.LoadScene("Traning"); } // 文本显示效果 IEnumerator TypeText(string text, float delay) { dialogueText.text = ""; foreach (char letter in text.ToCharArray()) { dialogueText.text += letter; yield return new WaitForSeconds(delay); } } // 相机震动效果 IEnumerator ShakeCamera(float duration, float magnitude) { Vector3 originalPos = mainCamera.transform.localPosition; float elapsed = 0f; while (elapsed < duration) { float x = Random.Range(-1f, 1f) * magnitude; float y = Random.Range(-1f, 1f) * magnitude; mainCamera.transform.localPosition = new Vector3(x, y, originalPos.z); elapsed += Time.deltaTime; yield return null; } mainCamera.transform.localPosition = originalPos; } // 闪光效果 IEnumerator FlashBoom() { image.color = Color.white; yield return new WaitForSeconds(0.1f); image.color = Originalcolor; } } 这是两个sence下的代码我现在需要制作战斗前后的不同对话

filetype

资源分类bin目录 本文解析的是图库类型,配置没什么必要性,在做特效时自行修改就可以了。图库总共7个(有一个重复,实际只有6个) 类型 名字 对应索引 动画配置 Anime_3 AnimeInfo_3 动画配置 Anime_Joy_13 AnimeInfo_Joy_13 动画配置 AnimeEx_1 AnimeInfoEx_1 动画配置 AnimeV3_7 AnimeInfoV3_7 动画配置 Puk2\Anime_PUK2_4 Puk2\AnimeInfo_PUK2_4 动画配置 Puk3\Anime_PUK3_2 Puk3\AnimeInfo_PUK3_2 ??动画配置 AnimeAp AnimeApdd ??战斗调色板 battle_4 battletxt_4 坐标信息 coordinatev3_2 coordinateinfov3_2 声音配置 sound_1 soundaddr_1 图库 Graphic_20 GraphicInfo_20 图库 GraphicEx_4 GraphicInfoEx_4 图库 Graphic_Joy_22 GraphicInfo_20 图库 GraphicV3_18 GraphicInfoV3_18 图库 Puk2\Graphic_PUK2_2 Puk2\GraphicInfo_PUK2_2 图库同Puk2 Puk3\Graphic_PUK2_2 Puk3\GraphicInfo_PUK2_2 图库 Puk3\Graphic_PUK3_1 Puk3\GraphicInfo_PUK3_1 调色板 bin\pal\*.cgp 无 调色板格式 调色板文件固定长度708字节,每个颜色3个字节,总共236个颜色。 游戏中0-15号,240-255号颜色有固定的默认值。调色板实际占据的是16-239号 例如图片使用的调色板为16号颜色,也就是对应调色板文件中的0号颜色。取出字节1(Blue)、字节2(Green)、字节3(Red),自行拼配颜色即可。 本程序默认使用palet_08调色板。 ———————————————— // 索引文件数据块 struct imgInfoHead { unsigned int id; unsigned int addr; // 在图像文件中的偏移 unsigned int len; // 长度 long xOffset; // 在游戏内的偏移量x long yOffset; // 在游戏内的偏移量y unsigned int width; unsigned int height; unsigned char tileEast; // 地图上横向几格 unsigned char tileSouth;// 竖向几格 unsigned char flag; unsigned char unKnow[5]; long tileId; // 所属的地图tile的id }; 索引文件每一张图片包含40个字节的字段。索引文件/40就是总图片数。实际上读取这个索引文件对图片提取没有太大意义,里面的几个字段主要是用于地图的拼接。 图库格式 // 图像bin 文件格式 struct imgData { unsigned char cName[2]; unsigned char cVer; // 1压缩 unsigned char cUnknow; unsigned int width; unsigned int height; unsigned int len; // 包含自身头的总长度,后续跟char数组 }; // + char* len = size - 16 每一张图片都有数据头,而且因为是顺序存储,实际上可以不使用索引文件的。 一张完整的图片包含 数据头+图片数据。 cVer说明: 0:未压缩,后续的数据就是图片数据 1:压缩,需要对后续数据进行解压 3:带调色板的压缩。在读取文件头后,还需要再读入4个字节,这4个字节代表调色板解压后的长度。 取图步骤 读取索引数据 FILE *pFile = nullptr; std::string strPath = _strPath + "\\bin\\"; if (0 == fopen_s(&pFile, (strPath + strInfo).c_str(), "rb")) { imgInfoHead tHead = { 0 }; int len = sizeof(imgInfoHead); while (len == fread_s(&tHead, len, 1, len, pFile)) _vecImginfo.push_back(tHead); } if (pFile) fclose(pFile); ———————————————— 遍历索引读取对应图库数据头 imgData tHead = { 0 }; int len = sizeof(imgData); if (len == fread_s(&tHead, len, 1, len, pFile)) { // 这种是错误的图 if (tHead.width > 5000 || tHead.height > 5000) { saveLog(LOG_ERROR, strErrorFile, strName, "img w or h error", imgHead, tHead); return false; } _cgpLen = 0; // 调色板长度 if (tHead.cVer == 3) { // 多读取4个字节,代表的是调色板的长度 if (4 != fread_s(&_cgpLen, 4, 1, 4, pFile)) { saveLog(LOG_ERROR, strErrorFile, strName, "read cgpLen error", imgHead, tHead); return false; } len += 4; } .... } ———————————————— 解密后续数据 if (imgLen == fread_s(_imgEncode, imgLen, 1, imgLen, pFile)) { if (tHead.cVer == 0) { // 未压缩图片 _imgDataIdx = imgLen; memcpy(_imgData, _imgEncode, imgLen); } else if (tHead.cVer == 1 || tHead.cVer == 3) { // 压缩的图片 _imgDataIdx = decodeImgData(_imgEncode, imgLen); if (_imgDataIdx != tHead.width * tHead.height + _cgpLen) { // 这种情况按说是错的 if (_imgDataIdx < tHead.width * tHead.height + _cgpLen) { saveLog(LOG_ERROR, strErrorFile, strName, "decode len more", imgHead, tHead); return false; } else { // 大于的话应该算是不够严谨 saveLog(LOG_INFO, strErrorFile, strName, "decode len less", imgHead, tHead); } } } } ———————————————— 填充像素 // 默认使用palet_08.cgp(白天) 调色版 unsigned char *pCgp = _uMapCgp.begin()->second.data(); strCgpName = _uMapCgp.begin()->first; // 使用图片自带调色板 if (_cgpLen > 0 && (int)_imgDataIdx >= w * h + _cgpLen) { pCgp = _imgData + (_imgDataIdx - _cgpLen); strCgpName = "self"; } // 图片数据,竖向方向是反的,从最后一行开始 int imgLen = w * h; for (int i = 0; i < imgLen; ++i) { // 调色板编号 int cIdx = _imgData[i] * 3; int idx = (h - i / w - 1) * w + i % w; _imgPixel[idx] = (pCgp[cIdx]) + (pCgp[cIdx + 1] << 8) + (pCgp[cIdx + 2] << 16); if (pCgp[cIdx] != 0 || pCgp[cIdx + 1] != 0 || pCgp[cIdx + 2] != 0) _imgPixel[idx] |= 0xff000000; } ———————————————— 生成图片 Gdiplus::Bitmap bmp(w, h, PixelFormat32bppARGB); int idx = 0; for (int row = 0; row < h; ++row) { for (int col = 0; col < w; ++col) { bmp.SetPixel(col, row, p[idx++]); } } CLSID encoderClsid; std::wstring s = L"image/" + wstrExt; if (!GetEncoderClsid(s.c_str(), &encoderClsid)) { return false; } std::wstring sName = wstrName + L"." + wstrExt; bmp.Save(sName.c_str(), &encoderClsid, nullptr); ———————————————— 依照內容生成BIN檔提取圖片工具 魔力宝贝高清单机计划(一) 图库提取 https://blog.csdn.net/qq_37543025/article/details/88377553

weixin_38743481
  • 粉丝: 702
上传资源 快速赚钱