上一篇文章实现了玩家移动跟随,现在需要添加地图跟随滚动功能:
玩家移动代码部分修改:
SpriteAnim脚本
修改部分区别在这里:
if (toy > MapMove.mapdata.GetLength(1) - 1 || tox > MapMove.mapdata.GetLength(0) - 1) return;
if (MapMove.mapdata[tox, toy] == 29) return;
if (MapMove.mapdata[tox, toy] == 7) return;//增加水上无法移动
if (MapMove.mapdata[tox, toy] == 0) return;//增加水上无法移动
animTimer = 0;
myCoordinate = new Vector2(tox, toy);
STEP++;
if (transform.GetComponent<MapMove>())
{
transform.GetComponent<MapMove>().UpdateMap(tox, toy);
}
transform.GetComponent().UpdateMap(tox, toy);
玩家每移动成功一步更新地图:
地图更新代码:
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class MapMove : MonoBehaviour
{
public Transform player;
public Transform mapLoader;
public GameObject cardPrefab; //预制体
public float tileSize; // 地图格子大小
public TextAsset json;
Sprite[] sprites;
public static int[,] mapdata;
int[,] mapUpdate;
void Start()
{
// 将JSON字符串转换为Jagged Array
int[][] jaggedArray = JsonConvert.DeserializeObject<int[][]>(json.ToString());
// 加载精灵图集
sprites = Resources.LoadAll<Sprite>("map");
int rows = jaggedArray.Length;
int cols = jaggedArray.Max(innerArray => innerArray.Length);
int[,] mapArray = new int[rows, cols];
mapdata = new int[cols, rows];//其他脚本引用使用
mapUpdate = new int[cols, rows];//其他脚本引用使用
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < jaggedArray[i].Length; j++)
{
mapArray[i, j] = jaggedArray[i][j];
}
}
LoadMap(mapArray);
}
void LoadMap(int[,] map)
{
//Debug.Log("列:"+map.GetLength(1) + "~~~" + "行:"+map.GetLength(0));
//反向映射地图障碍等,json数组从左上到右下计算下标,而地图左下到右上其初始位置(x=0,y=0)
for (int x = 0; x < map.GetLength(1); x++)
{
for (int y = 0; y < map.GetLength(0); y++)
{
mapdata[x, y] = map[map.GetLength(0) - y - 1, x];
}
}
mapUpdate = map;
UpdateMap(18, 9);
}
public void UpdateMap(int _x, int _y)
{
int index = -1;
int[,] map = mapUpdate;
for (int y = 0; y < map.GetLength(0); y++)
{
for (int x = 0; x < map.GetLength(1); x++)
{
int tileType = map[y, x];
//获取玩家遮罩内格子区域
if (_x >= 9 && _x <= map.GetLength(1) - 8 && _y >= 6 && _y <= map.GetLength(0) - 8)
{
if (x >= _x - 9 && x <= _x + 8 && y >= -_y + map.GetLength(0) - 9 && y <= -_y + map.GetLength(0) + 6)
{
Vector3 position = new Vector3(x, -y + map.GetLength(0) - 1, 0) * tileSize;
string str = "map_" + tileType.ToString();
index++;
mapLoader.GetChild(index).position = position;
foreach (Sprite s in sprites)
{
if (s.name == str)
{
SpriteRenderer spriteRenderer = mapLoader.GetChild(index).GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteRenderer.sprite = s;
}
break;
}
}
}
}
//以下可以删除,大地图用不到,玩家不会跑到距离地图边缘9格的位置
//最左边边缘上下移动
else if (_x <= 9 && _y >= 6 && _y <= map.GetLength(0) - 8)
{
if (x <= _x + 8 && y >= -_y + map.GetLength(0) - 9 && y <= -_y + map.GetLength(0) + 6)
{
Vector3 position = new Vector3(x, -y + map.GetLength(0) - 1, 0) * tileSize;
string str = "map_" + tileType.ToString();
index++;
mapLoader.GetChild(index).position = position;
foreach (Sprite s in sprites)
{
if (s.name == str)
{
SpriteRenderer spriteRenderer = mapLoader.GetChild(index).GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteRenderer.sprite = s;
}
break;
}
}
}
}
//最右边边缘上下移动
else if (_x >= map.GetLength(1) - 8 && _y >= 6 && _y <= map.GetLength(0) - 8)
{
if (x >= _x - 9 && y >= -_y + map.GetLength(0) - 9 && y <= -_y + map.GetLength(0) + 6)
{
Vector3 position = new Vector3(x, -y + map.GetLength(0) - 1, 0) * tileSize;
string str = "map_" + tileType.ToString();
index++;
mapLoader.GetChild(index).position = position;
foreach (Sprite s in sprites)
{
if (s.name == str)
{
SpriteRenderer spriteRenderer = mapLoader.GetChild(index).GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteRenderer.sprite = s;
}
break;
}
}
}
}
//最下边边缘左右移动
else if (_x >= 9 && _x <= map.GetLength(1) - 8 && _y <= 6)
{
if (x >= _x - 9 && x <= _x + 8 && y >= -_y + map.GetLength(0) - 9)
{
Vector3 position = new Vector3(x, -y + map.GetLength(0) - 1, 0) * tileSize;
string str = "map_" + tileType.ToString();
index++;
mapLoader.GetChild(index).position = position;
foreach (Sprite s in sprites)
{
if (s.name == str)
{
SpriteRenderer spriteRenderer = mapLoader.GetChild(index).GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteRenderer.sprite = s;
}
break;
}
}
}
}
//最上边边缘左右移动
else if (_x >= 9 && _x <= map.GetLength(1) - 8 && _y >= map.GetLength(0) - 8)
{
if (x >= _x - 9 && x <= _x + 8 && y >= -_y + map.GetLength(0) - 9)
{
Vector3 position = new Vector3(x, -y + map.GetLength(0) - 1, 0) * tileSize;
string str = "map_" + tileType.ToString();
index++;
mapLoader.GetChild(index).position = position;
foreach (Sprite s in sprites)
{
if (s.name == str)
{
SpriteRenderer spriteRenderer = mapLoader.GetChild(index).GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteRenderer.sprite = s;
}
break;
}
}
}
}
}
}
}
}
int index = -1;重新洗牌地图编号,
mapLoader.GetChild(index).position = position;更新地图坐标
之前使用的是GameObject go = Instantiate(cardPrefab, position, Quaternion.identity)方法来加载地图,后来发现如果地图json二维数组大小过了30*30(大体上)会卡死,所以取消了Instantiate方法,
使用了如图所示方法解决:
与预留的地图块数量是288个,为什么?
可见区域格子总共255个,但是地图更新时四面要多一行,不然会看到有一边在移动切换时为空白了,
背景玩家左边最多显示9个格子
背景玩家右边最多显示8个格子
背景玩家上边最多显示8个格子
背景玩家下边最多显示7个格子
所以要预留288个。
为了测试在大地图上是否能正常运行,我使用了大的json数据测试了:
已经到了350多行的地图了,运行非常流畅。
模拟了玩家传送后的地图更新,按下K键重置玩家和目标点,并且更新地图,没错,就是传真功能:
if (Input.GetKeyDown(KeyCode.K))
{
int posX = (int)transform.position.x;
int posY = (int)transform.position.y;
tox = posX;
toy = posY;
myCoordinate = new Vector2(tox, toy);
transform.GetComponent<MapMove>().UpdateMap(posX, posY);
}
运行效果:
重装机兵跟随更新地图
下一篇实现大地图整体加载和水资源动画效果,假设水在二维数组的编号为7,8,9,10等,间隔一秒切换一组对应水资源。