专门做拼花网站,影视公司网页设计,网站制作多少钱方案,wordpress管理员插件目录
一、玩家脚本Player
二、Canvas组件设置
三、小地图相关
四、GameLogicMap脚本修改 基于#xff1a;【Unity3D】Tilemap俯视角像素游戏案例-CSDN博客
2D玩家添加Dotween移动DOPath效果#xff0c;移动完成后进行刷新小地图#xff08;小地图会顺便刷新大地图…目录
一、玩家脚本Player
二、Canvas组件设置
三、小地图相关
四、GameLogicMap脚本修改 基于【Unity3D】Tilemap俯视角像素游戏案例-CSDN博客
2D玩家添加Dotween移动DOPath效果移动完成后进行刷新小地图小地图会顺便刷新大地图
一、玩家脚本Player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class Player : MonoBehaviour
{void Update(){if (Input.GetMouseButtonDown(0)){Vector2 pos Input.mousePosition;Ray ray Camera.main.ScreenPointToRay(pos);RaycastHit2D hit Physics2D.Raycast(ray.origin, ray.direction);if (hit.collider ! null){Vector2 hitPos hit.point;Vector3Int v3Int new Vector3Int(Mathf.FloorToInt(hitPos.x), Mathf.FloorToInt(hitPos.y), 0);ListVector3Int pathPointList GameLogicMap.Instance.PlayAstar(v3Int);Vector3[] pathArray new Vector3[pathPointList.Count];int offset pathPointList.Count - 1;for (int i pathPointList.Count - 1; i 0; i--){ Vector3Int pointPos pathPointList[i];Vector3 worldPos GameLogicMap.Instance.GetWorldPos(pointPos);pathArray[offset - i] worldPos;}transform.DOPath(pathArray, 1f).OnComplete(() {Debug.Log(移动完成 更新小地图);GameLogicMap.Instance.DrawSmallMap();}).SetAutoKill(true);}}}public Vector3Int GetPos(){Vector3 pos transform.position;return new Vector3Int(Mathf.FloorToInt(pos.x - 0.5f), Mathf.FloorToInt(pos.y - 0.5f), 0);}
}二、Canvas组件设置 三、小地图相关
原理利用2D游戏为了实现寻路而创建的二维数组去生成一张Texture2D纹理图大地图是直接用int[,]map二维数组去创建map[x,y]等于1是空地不等于1是障碍物或不可穿越地形 大地图上的玩家绿点是直接拿到玩家在map的坐标点直接绘制。
小地图是以玩家为中心的[-smallSize/2, smallSize/2]范围内进行绘制小地图上的玩家绿点是直接绘制到中心点(smallSize.x/2, smallSize.y/2)
注意绘制到Texture2D的像素点坐标是[0, size]范围的则小地图的绘制是SetPixel(i, j, color)传递i, j是[0,size]范围的而不要传递x, y这个x,y的取值是以玩家点为中心的[-size/2, size/2]范围坐标值如下取法
x 玩家点.x - size.x/2 i; y 玩家点.y - size.y/2 j;
用2层for遍历来看的话就是从(玩家点.x - size.x/2, 玩家点.y - size.y/2)坐标点从下往上从左往右依次遍历每个map[x,y]点生成对应颜色的像素点构成一张Texture2D图片。 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class SmallMapFor2D : MonoBehaviour
{public Image smallImage;public Vector2Int smallSize;private Vector2Int lastSmallSize;Texture2D smallImageTexture2D;public Image bigImage;Vector2Int bigSize;Texture2D bigImageTexture2D;private Vector3Int playerPoint;//环境二维数组地图[静态] 若是动态需改为自定义类数组此时是int值类型数组private int[,] map;//初始化大地图整体public void InitBigMap(int[,] map, Vector2Int size){//已初始化则直接退出if (bigImageTexture2D ! null)return;this.map map;this.bigSize size;bigImageTexture2D new Texture2D(bigSize.x, bigSize.y);bigImageTexture2D.filterMode FilterMode.Point;DrawBigMap();}public void DrawBigMap(){int mapWidth map.GetLength(0);int mapHeight map.GetLength(1);for (int i 0; i bigSize.x; i){for (int j 0; j bigSize.y; j){//判断是否在map范围内if (i mapWidth j mapHeight){if (map[i, j] 1) //空地{bigImageTexture2D.SetPixel(i, j, new Color(0.6f, 0.6f, 0.6f, 0.5f));}else //障碍物{bigImageTexture2D.SetPixel(i, j, new Color(0.3f, 0.3f, 0.3f, 0.5f));}}else{//非map范围内bigImageTexture2D.SetPixel(i, j, new Color(0.1f, 0.1f, 0.1f, 0.8f));}}}if (playerPoint ! null){//更新大地图玩家点bigImageTexture2D.SetPixel(playerPoint.x, playerPoint.y, Color.green);}bigImageTexture2D.Apply();//bigImage.material.SetTexture(_MainTex, bigImageTexture2D);bigImage.material.mainTexture bigImageTexture2D;bigImage.SetMaterialDirty();}//动态绘制小地图 时机:玩家移动完成后public void DrawSmallMap(Vector3Int playerPoint){//中途可换小地图大小if (this.lastSmallSize ! null this.lastSmallSize.x ! smallSize.x this.lastSmallSize.y ! smallSize.y){if (smallImageTexture2D ! null){Destroy(smallImageTexture2D);smallImageTexture2D null;}smallImageTexture2D new Texture2D(smallSize.x, smallSize.y);smallImageTexture2D.filterMode FilterMode.Point;}this.lastSmallSize smallSize;this.playerPoint playerPoint;int mapWidth map.GetLength(0);int mapHeight map.GetLength(1); for (int i 0; i smallSize.x; i){for (int j 0; j smallSize.y; j){//中心点是人物点 故绘制点为如下int x playerPoint.x - smallSize.x / 2 i;int y playerPoint.y - smallSize.y / 2 j;//判断是否在map范围内if (x 0 x mapWidth y 0 y mapHeight){if (map[x, y] 1) //空地{smallImageTexture2D.SetPixel(i, j, new Color(0.6f, 0.6f, 0.6f, 0.5f));}else //障碍物{smallImageTexture2D.SetPixel(i, j, new Color(0.3f, 0.3f, 0.3f, 0.5f));}}else{//非map范围内smallImageTexture2D.SetPixel(i, j, new Color(0.8f, 0f, 0f, 0.8f));}}}smallImageTexture2D.SetPixel(smallSize.x / 2, smallSize.y / 2, Color.green); smallImageTexture2D.Apply();//smallImage.material.SetTexture(_MainTex, smallImageTexture2D);smallImage.material.mainTexture smallImageTexture2D;smallImage.SetMaterialDirty();//更新大地图 因为玩家位置变化//(可优化 不需要重新整张地图再绘制 只更新上一个玩家点和新玩家点只是要保存的大地图原始数据、旧玩家点更新即可)DrawBigMap();}
}小地图2张Image图片的材质球要使用不同的材质球实例 四、GameLogicMap脚本修改
主要变化新增和修改
初始化绘制大地图和小地图 smallMapFor2D.InitBigMap(map, new Vector2Int(map.GetLength(0), map.GetLength(1))); DrawSmallMap();
A*寻路方法返回路径数组这是一个从终点到起点的数组所以使用时是倒序遍历的。 public ListVector3Int PlayAstar(Vector3Int endPos)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Tilemaps;
using UnityEngine.UI;public class GameLogicMap : MonoBehaviour
{public static GameLogicMap _instance;public static GameLogicMap Instance{get { return _instance; }}public Grid terrainGrid;private Tilemap terrainTilemap;public Grid buildGrid;private Tilemap buildTilemap;public Player player;public int[,] map;private Vector3Int mapOffset;public SmallMapFor2D smallMapFor2D;private const int ConstZ 0;public class Point{public Vector3Int pos;public Point parent;public float F { get { return G H; } } //F G Hpublic float G; //G parent.G Distance(parent,self)public float H; //H Distance(self, end)public string GetString(){return pos: pos ,F: F ,G: G ,H: H \n;}}private ListPoint openList new ListPoint();private ListPoint closeList new ListPoint();public LineRenderer lineRenderer;private void Awake(){_instance this;}void Start(){terrainTilemap terrainGrid.transform.Find(Tilemap).GetComponentTilemap();buildTilemap buildGrid.transform.Find(Tilemap).GetComponentTilemap();BoundsInt terrainBound terrainTilemap.cellBounds;BoundsInt buildBound buildTilemap.cellBounds;map new int[terrainBound.size.x, terrainBound.size.y];mapOffset new Vector3Int(-terrainBound.xMin, -terrainBound.yMin, 0);Debug.Log(mapOffset: mapOffset);foreach (var pos in terrainBound.allPositionsWithin){var sprite terrainTilemap.GetSprite(pos);if (sprite ! null){SetMapValue(pos.x, pos.y, 1); //空地1}}foreach (var pos in buildBound.allPositionsWithin){var sprite buildTilemap.GetSprite(pos);if (sprite ! null){SetMapValue(pos.x, pos.y, 2); //障碍2}}smallMapFor2D.InitBigMap(map, new Vector2Int(map.GetLength(0), map.GetLength(1)));DrawSmallMap();}//绘制小地图public void DrawSmallMap(){//传递玩家在Map的坐标smallMapFor2D.DrawSmallMap(ToMapPos(player.GetPos()));}private void SetMapValue(int x, int y, int value){map[x mapOffset.x, y mapOffset.y] value;}private Vector3Int ToMapPos(Vector3Int pos){return pos mapOffset;}public ListVector3Int PlayAstar(Vector3Int endPos){endPos ToMapPos(endPos);Debug.Log(endPos);openList.Clear();closeList.Clear();Vector3Int playerPos player.GetPos();playerPos ToMapPos(playerPos);openList.Add(new Point(){G 0f,H GetC(playerPos, endPos),parent null,pos playerPos,});ListVector3Int resultList CalculateAstar(endPos);if (resultList ! null){lineRenderer.positionCount resultList.Count;for (int i 0; i resultList.Count; i){Vector3Int pos resultList[i];lineRenderer.SetPosition(i, GetWorldPos(pos));}}else{Debug.LogError(寻路失败;);}return resultList;}public Vector3 GetWorldPos(Vector3Int pos){pos.x pos.x - mapOffset.x;pos.y pos.y - mapOffset.y;return terrainTilemap.GetCellCenterWorld(pos);}private ListVector3Int CalculateAstar(Vector3Int endPos){int cnt 0;while (true){//存在父节点说明已经结束 if (openList.Exists(x x.pos.Equals(endPos))){Debug.Log(找到父节点~ endPos ,迭代次数: cnt);ListVector3Int resultList new ListVector3Int();Point endPoint openList.Find(x x.pos.Equals(endPos));resultList.Add(endPoint.pos);Point parent endPoint.parent;while (parent ! null){resultList.Add(parent.pos);parent parent.parent;}return resultList;}cnt;if (cnt 100 * map.GetLength(0) * map.GetLength(1)){Debug.LogError(cnt);return null;}//从列表取最小F值的Point开始遍历Point currentPoint openList.OrderBy(x x.F).FirstOrDefault();string str ;foreach (var v in openList){str v.GetString();}Debug.Log(最小F currentPoint.GetString() \n str);Vector3Int pos currentPoint.pos;for (int i -1; i 1; i){for (int j -1; j 1; j){if (i 0 j 0){continue;}//过滤越界、墙体(map[x,y]不等于1)、已处理节点存在闭合列表的节点Vector3Int tempPos new Vector3Int(i pos.x, j pos.y, ConstZ);if (tempPos.x 0 || tempPos.x map.GetLength(0) || tempPos.y 0 || tempPos.y map.GetLength(1)|| map[tempPos.x, tempPos.y] ! 1|| closeList.Exists(x x.pos.Equals(tempPos))){continue;}//判断tempPos该节点是否已经计算, 在openList的就是已经计算的Point tempPoint openList.Find(x x.pos.Equals(tempPos));float newG currentPoint.G Vector3.Distance(currentPoint.pos, tempPos);if (tempPoint ! null){//H固定不变,因此判断旧的G值和当前计算出的G值如果当前G值更小需要改变节点数据的父节点和G值为当前的否则保持原样float oldG tempPoint.G;if (newG oldG){tempPoint.G newG;tempPoint.parent currentPoint;Debug.Log(更新节点: tempPoint.pos , newG: newG , oldG: oldG ,parent: tempPoint.parent.pos);}}else{tempPoint new Point(){G newG,H GetC(tempPos, endPos),pos tempPos,parent currentPoint};Debug.Log(新加入节点: tempPoint.pos , newG: newG , parent: currentPoint.pos);openList.Add(tempPoint);}}}//已处理过的当前节点从开启列表移除,并放入关闭列表openList.Remove(currentPoint);closeList.Add(currentPoint);}}private float GetC(Vector3Int a, Vector3Int b){return Math.Abs(a.x - b.x) Math.Abs(a.y - b.y);}
}