Unity 大地圖功能 離線瓦片地圖

不使用第二個攝像機實現類似開放世界的大地圖功能。

功能如下:

  • 按下M鍵打開/關閉大地圖功能
  • 打開大地圖時,默認玩家位置居中
  • 大地圖支持拖拽,可調節拖拽速度,支持XY軸翻轉
  • 支持大地圖設置邊緣偏移量
  • 可設置是否啟動拖拽邊界
  • 可調節縮放系數

?UGUI結構:

Canvas

? ? ? ? ---Root? (大地圖范圍)

? ? ? ? ? ? ? ? ---MapTiles (瓦片貼圖,可以像離線瓦片地圖那樣分層展示,尺寸:全局鋪滿)

? ? ? ? ? ? ? ? ---playerArrow? (玩家指示器,我用了個箭頭表示,設置大小,居中即可)

1.利用UI輔助地編標記范圍

?如果比例正確,大小不同可以微調縮放系數。

2.自動回正,在拖拽地圖后,再次進入會自動回正,讓玩家的位置處于屏幕中央

3.設置偏移,可以設計地圖邊緣樣式等

稍加修改可以改成小地圖,代碼里就不展示了。原理相同

?代碼如下:

using UnityEngine;
using Color = UnityEngine.Color;public class MapController : MonoBehaviour
{[Header("場景對象")]public Transform player; // 玩家對象public Transform plane;  // 場景中的比例尺平面[Header("地圖UI對象")]public RectTransform mapRoot; // 地圖UI的根節點public RectTransform arrowP1;    // 地圖上的箭頭[Header("縮放設置")][Tooltip("用于調整Plane大小的縮放系數")]public float scaleFactor = 10f;[Header("快捷鍵")]public KeyCode toggleMapKey = KeyCode.M; // 切換地圖的快捷鍵private MapDragHandler mapDragHandler;  // 用來訪問拖拽處理器void Start(){AdjustPlaneScale();mapDragHandler = mapRoot.GetComponent<MapDragHandler>();  // 獲取拖拽處理器組件}void Update(){UpdateArrow();ToggleMap();}/// <summary>/// 根據縮放系數調整Plane的Scale,使其覆蓋場景范圍并匹配MapRoot的比例/// </summary>private void AdjustPlaneScale(){float mapWidth = mapRoot.sizeDelta.x;float mapHeight = mapRoot.sizeDelta.y;float aspectRatio = mapWidth / mapHeight;plane.localScale = new Vector3(scaleFactor * aspectRatio, 1, scaleFactor);}/// <summary>/// 更新地圖上箭頭的位置和旋轉,以反映玩家的當前位置和朝向/// </summary>private void UpdateArrow(){Vector3 playerPos = player.position;float planeWidth = plane.localScale.x * 10f;float planeHeight = plane.localScale.z * 10f;float mapWidth = mapRoot.sizeDelta.x;float mapHeight = mapRoot.sizeDelta.y;float normalizedX = playerPos.x / planeWidth;float normalizedY = playerPos.z / planeHeight;float mapX = normalizedX * mapWidth;float mapY = normalizedY * mapHeight;arrowP1.anchoredPosition = new Vector2(mapX, mapY);float rotationZ = -player.eulerAngles.y;arrowP1.rotation = Quaternion.Euler(0, 0, rotationZ);}private void ToggleMap(){if (Input.GetKeyDown(toggleMapKey) && mapRoot.transform.parent != null){GameObject mapParent = mapRoot.transform.parent.gameObject;bool isActive = !mapParent.activeSelf;mapParent.SetActive(isActive);if (isActive)CenterPlayerOnMap(player);}}/// <summary>/// 調整地圖偏移量以盡量將玩家置于屏幕中心/// </summary>private void CenterPlayerOnMap(Transform player){// 獲取玩家在場景中的位置Vector3 playerPos = player.position;// 計算 Plane 的實際寬度(單位:場景單位)float planeWidth = plane.localScale.x * 10f;float planeHeight = plane.localScale.z * 10f;// 獲取 MapRoot 的實際尺寸(單位:像素)float mapWidth = mapRoot.sizeDelta.x;float mapHeight = mapRoot.sizeDelta.y;// 將場景坐標歸一化到 [-0.5, 0.5] 的比例范圍內float normalizedX = playerPos.x / planeWidth;float normalizedY = playerPos.z / planeHeight;// 將歸一化坐標轉換為 MapRoot 的像素坐標float mapX = normalizedX * mapWidth;float mapY = normalizedY * mapHeight;// 計算偏移量,讓玩家位置對齊到屏幕中心float centerX = 0f; // 中心點的 X 坐標float centerY = 0f; // 中心點的 Y 坐標float offsetX = centerX - mapX;float offsetY = centerY - mapY;if (mapDragHandler.useBoundary){offsetX = Mathf.Clamp(offsetX, mapDragHandler.minBoundary.x, mapDragHandler.maxBoundary.x);offsetY = Mathf.Clamp(offsetY, mapDragHandler.minBoundary.y, mapDragHandler.maxBoundary.y);}// 應用偏移量到地圖根節點mapRoot.anchoredPosition = new Vector2(offsetX, offsetY);}#if UNITY_EDITORprivate void OnValidate(){if (plane != null){AdjustPlaneScale();}}Vector3 center; // 平面的中心點Vector2 size;   // 平面的寬度和高度float heightSize = 2.0f; // 高void OnDrawGizmos(){if (plane != null){center = plane.position;size = new Vector2(plane.localScale.x * 10, plane.localScale.z * 10);}// Gizmos是繪制調試輔助圖形的簡單方法Gizmos.color = Color.blue;Vector3 halfSize = new Vector3(size.x / 2, 0, size.y / 2);Vector3 p1 = center + new Vector3(-halfSize.x, 0, -halfSize.z);Vector3 p2 = center + new Vector3(halfSize.x, 0, -halfSize.z);Vector3 p3 = center + new Vector3(halfSize.x, 0, halfSize.z);Vector3 p4 = center + new Vector3(-halfSize.x, 0, halfSize.z);Vector3 p5 = center + new Vector3(-halfSize.x, heightSize, -halfSize.z);Vector3 p6 = center + new Vector3(halfSize.x, heightSize, -halfSize.z);Vector3 p7 = center + new Vector3(halfSize.x, heightSize, halfSize.z);Vector3 p8 = center + new Vector3(-halfSize.x, heightSize, halfSize.z);Gizmos.DrawLine(p1, p2);Gizmos.DrawLine(p2, p3);Gizmos.DrawLine(p3, p4);Gizmos.DrawLine(p4, p1);Gizmos.DrawLine(p5, p6);Gizmos.DrawLine(p6, p7);Gizmos.DrawLine(p7, p8);Gizmos.DrawLine(p8, p5);Gizmos.DrawLine(p1, p5);Gizmos.DrawLine(p2, p6);Gizmos.DrawLine(p3, p7);Gizmos.DrawLine(p4, p8);}
#endif
}
using UnityEngine;
using UnityEngine.EventSystems;public class MapDragHandler : MonoBehaviour, IPointerDownHandler, IDragHandler
{[Header("方向取反設置")]public bool invertX = false; // X方向取反public bool invertY = false; // Y方向取反[Header("拖拽速度")]public float dragSpeed = 1f; // 拖拽速度[Header("拖拽邊界")]public bool useBoundary = false; // 是否使用邊界限制public Vector2 offsetBoundary;// 拖拽的邊界偏移量public Vector2 minBoundary; // 拖拽的最小邊界(左下角)public Vector2 maxBoundary; // 拖拽的最大邊界(右上角)private RectTransform mapRoot; // MapRoot 的 RectTransformprivate Vector2 previousPointerPosition; // 記錄上一次指針位置private void Awake(){// 獲取 RectTransform 組件mapRoot = GetComponent<RectTransform>();if (mapRoot == null){Debug.LogError("MapDragHandler 需要綁定一個具有 RectTransform 的對象!");}useBoundary = mapRoot.rect.width > Screen.width && mapRoot.rect.height > Screen.height;// 設置默認的邊界值,根據你的實際需求調整這些值minBoundary = new Vector2(-(mapRoot.rect.width / 2) + (Screen.width / 2) - offsetBoundary.x, -(mapRoot.rect.height / 2) + (Screen.height / 2) - offsetBoundary.y);maxBoundary = new Vector2((mapRoot.rect.width / 2) - (Screen.width / 2) + offsetBoundary.x, (mapRoot.rect.height / 2) - (Screen.height / 2) + offsetBoundary.y);}// 當指針按下時記錄初始位置public void OnPointerDown(PointerEventData eventData){RectTransformUtility.ScreenPointToLocalPointInRectangle(mapRoot.parent as RectTransform,eventData.position,eventData.pressEventCamera,out previousPointerPosition);}// 拖拽時計算位移public void OnDrag(PointerEventData eventData){Vector2 currentPointerPosition;RectTransformUtility.ScreenPointToLocalPointInRectangle(mapRoot.parent as RectTransform,eventData.position,eventData.pressEventCamera,out currentPointerPosition);// 計算拖拽的偏移量Vector2 delta = currentPointerPosition - previousPointerPosition;// 應用方向取反設置if (invertX) delta.x = -delta.x;if (invertY) delta.y = -delta.y;// 更新 MapRoot 的位置Vector2 newPosition = mapRoot.anchoredPosition + delta * dragSpeed;// 限制位置到指定邊界范圍內if (useBoundary){newPosition.x = Mathf.Clamp(newPosition.x, minBoundary.x, maxBoundary.x);newPosition.y = Mathf.Clamp(newPosition.y, minBoundary.y, maxBoundary.y);}// 設置新的位置mapRoot.anchoredPosition = newPosition;// 更新記錄的指針位置previousPointerPosition = currentPointerPosition;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/65875.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/65875.shtml
英文地址,請注明出處:http://en.pswp.cn/web/65875.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Bootstrap 前端 UI 框架

Bootstrap官網&#xff1a;Bootstrap中文網 鉑特優選 Bootstrap 下載 點擊進入中文文檔 點擊下載 生產文件是開發響應式網頁應用&#xff0c;源碼是底層邏輯代碼&#xff0c;因為是要制作響應式網頁&#xff0c;所以下載開發文件 引入 css 文件&#xff0c; bootstrap.css 和 …

記一次sealos部署k8s集群之delete了第一臺master如何恢復

記一次sealos部署k8s集群之delete了第一臺master如何恢復 一、背景描述 使用sealos部署了一套K8S集群 master信息:172.27.100.1、172.27.100.2、172.27.100.3 node信息:172.27.100.4、172.27.100.5 sealos安裝在172.27.100.1節點,根目錄下/root/.sealos/文件還在! [root…

error: linker `link.exe` not found

開始學習rust&#xff0c;安裝好rust的環境&#xff0c;開始從hello world開始&#xff0c;結果用在win10環境下&#xff0c;使用vs code或cmd窗口編譯rust報錯&#xff1a; PS E:\study_codes\rust-demo\chart01> rustc hello.rs error: linker link.exe not found| note:…

用 HTML5 Canvas 和 JavaScript 實現雪花飄落特效

這篇文章將帶您深入解析使用 HTML5 Canvas 和 JavaScript 實現動態雪花特效的代碼原理。 1,效果展示 該效果模擬了雪花從天而降的動態場景,具有以下特點: 雪花數量、大小、透明度和下落速度隨機。雪花會在屏幕底部重置到頂部,形成循環效果。隨窗口大小動態調整,始終覆蓋…

django基于Python的校園個人閑置物品換購平臺

Django 基于 Python 的校園個人閑置物品換購平臺 一、平臺概述 Django 基于 Python 的校園個人閑置物品換購平臺是專為校園師生打造的一個便捷、環保且充滿活力的線上交易場所。它借助 Django 這一強大的 Python Web 開發框架&#xff0c;整合了校園內豐富的閑置物品資源&…

【Vim Masterclass 筆記10】S06L23:Vim 核心操作訓練之 —— 文本的搜索、查找與替換操作(第二部分)

文章目錄 S06L23 Search, Find, and Replace - Part Two1 文本替換命令 :s/old/new/2 指定范圍的文本替換3 特例&#xff1a;路徑的替換4 文件行號的配置5 要點總結&#xff08;1&#xff09;搜索當前行&#xff08;Same Line Searching&#xff09;&#xff08;2&#xff09;跨…

【計算機網絡】課程 實驗五 靜態路由配置

實驗五 靜態路由配置 一、實驗目的 理解靜態路由的工作原理&#xff0c;掌握如何配置靜態路由。 二、實驗分析與設計 【背景描述】 假設校園網分為 2 個區域&#xff0c;每個區域內使用 1 臺路由器連接 2 個子網&#xff0c; 現要在路由器上 做適當配置&#xff0c;實現校…

Python 繼承示例:有與無 `super().__init__()` 的區別

文章目錄 Python 繼承示例&#xff1a;有與無 super().__init__() 的區別父類&#xff08;Parent&#xff09;子類&#xff08;Child&#xff09;不調用 super().__init__()子類&#xff08;Child&#xff09;調用 super().__init__() Python 繼承示例&#xff1a;有與無 super…

Linux下部署Redis(本地部署超詳細)

非docker 1、下載Redis 歷史版本&#xff1a; http://download.redis.io/releases 我的&#xff1a; http://download.redis.io/releases/redis-7.0.5.tar.gz 2.安裝教程 1.Redis是基于c語言編寫的需要安裝依賴&#xff0c;需要安裝gcc yum install gcc-c 2.查看gcc版…

Spring——幾個常用注解

環境配置 1.在配置文件中導入約束(context — 共三個)并添加一項配置( context:annotation-config/) 才能支持注解的使用 context 約束&#xff1a; xmlns:context“http://www.springframework.org/schema/context” 2.xsi:schemaLocation下的&#xff1a;" http://ww…

Oopsie【hack the box】

Oopsie 解題流程 文件上傳 首先開啟機器后&#xff0c;我們先使用 nmap -sC -SV來掃描一下IP地址&#xff1a; -sC&#xff1a;使用 Nmap 的默認腳本掃描&#xff08;通常是 NSE 腳本&#xff0c;Nmap Scripting Engine&#xff09;。這個選項會自動執行一系列常見的腳本&am…

單片機-定時器中斷

1、相關知識 振蕩周期1/12us; //振蕩周期又稱 S周期或時鐘周期&#xff08;晶振周期或外加振蕩周期&#xff09;。 狀態周期1/6us; 機器周期1us; 指令周期1~4us; ①51單片機有兩組定時器/計數器&#xff0c;因為既可以定時&#xff0c;又可以計數&#xff0c;故稱之為定時器…

【藍牙】win11 筆記本電腦連接 hc-06

文章目錄 前言步驟 前言 使用電腦通過藍牙添加串口 步驟 設置 -> 藍牙和其他設備 點擊 顯示更多設備 更多藍牙設置 COM 端口 -> 添加 有可能出現卡頓&#xff0c;等待一會 傳出 -> 瀏覽 點擊添加 hc-06&#xff0c;如果沒有則點擊 再次搜索 確定 添加成…

Android切換語言不退出App

1.需求 實現用戶選擇語言&#xff08;未點擊下一步&#xff09;&#xff0c;更新當前界面UI&#xff0c;點擊下一步后&#xff0c;更新App的語言&#xff0c;并進行保存。 實現目標&#xff1a; 1.設置App的語言&#xff0c;本地進行保存 2.updateResources更新本地語言配置…

一鍵獲取Linux主機配置信息shell腳本,含網卡詳情,網卡綁定等

cat > /tmp/get_os_info.sh <<"EOF"#!/bin/bashexport LANG=en_US.UTF-8# 如果 cat /proc/1/cgroup | grep docker | wc -l 大于0 或 systemd-detect-virt 返回 docker,則為 docker容器,# 如果 virt-what 返回 kvm或vmware或hyperv或xen、xen-hvm、lxc 或…

2 XDMA IP中斷

三種中斷 1. Legacy 定義&#xff1a;Legacy 中斷是傳統的中斷處理方式&#xff0c;使用物理中斷線&#xff08;例如 IRQ&#xff09;來傳遞中斷信號。缺點&#xff1a; 中斷線數量有限&#xff0c;通常為 16 條&#xff0c;限制了可連接設備的數量。中斷處理可能會導致中斷風…

【算法】時間復雜度以及O(N^2)的排序

目錄 1.常數時間的操作 2.時間復雜度 2.1.以選擇排序為例 2.2.O(n^2)從何而來 2.3.冒泡排序 2.3.1.抑或運算 2.4.插入排序 3.二分法 3.1.局部最小 4.遞歸 4.1.遞歸行為時間復雜度的估計 1.常數時間的操作 一個操作如果和樣本的數據量無關&#xff0c;每次都是固定時…

2021 年 3 月青少年軟編等考 C 語言五級真題解析

目錄 T1. 紅與黑思路分析T2. 密室逃脫思路分析T3. 求逆序對數思路分析T4. 最小新整數思路分析T1. 紅與黑 有一間長方形的房子,地上鋪了紅色、黑色兩種顏色的正方形瓷磚。你站在其中一塊黑色的瓷磚上,只能向相鄰的黑色瓷磚移動。請寫一個程序,計算你總共能夠到達多少塊黑色的…

C# 或 .NetCore 如何使用 NPOI 導出圖片到 Excel 文件

今天在本文中&#xff0c;我們將嘗試使用NPOI庫將圖像插入到 Excel 文件的特定位置。請將以下邏輯添加到您的寫作方法中&#xff0c;在 Excel 文件中添加圖像&#xff08;JPEG、PNG&#xff09;,我已經有一個示例 jpeg 文件 - Read-write-excel-npoi.jpg &#xff0c;我們將嘗試…

【學習筆記】理解深度學習的基礎:機器學習

1. 機器學習基礎 1.1 機器學習的定義與重要性 定義&#xff1a;深度學習是機器學習的一種特定形式。為了深入理解深度學習&#xff0c;必須牢固掌握機器學習的基本原理。機器學習算法是一種能夠從數據中學習的算法&#xff0c;通過經驗E在任務T上提高性能度量P&#xff08;Mi…