复刻重装机兵玩家地图加载和移动及队列(队友战车)跟随,直接来吧!
移动测试
地图加载:
using Newtonsoft.Json;
using System;
using System.Linq;
using UnityEngine;
public class MapLoader : MonoBehaviour
{
public GameObject cardPrefab; //预制体
public float tileSize; // 地图格子大小
public TextAsset json;
Sprite[] sprites;
public static int[,] mapdata;
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];//其他脚本引用使用
for (int i = 0; i < rows; i++)
{
if (jaggedArray[i].Length > cols)
{
throw new InvalidOperationException("Jagged array has rows of different lengths.");
}
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));
for (int y = 0; y < map.GetLength(0); y++)
{
for (int x = 0; x < map.GetLength(1); x++)
{
int tileType = map[y, x];
//Vector3 position = new Vector3(x, -y, 0) * tileSize;
//让生成得地图坐标在第一象限
Vector3 position = new Vector3(x, -y + map.GetLength(0) - 1, 0) * tileSize;
string str = "map_"+ tileType.ToString();
GameObject go = Instantiate(cardPrefab, position, Quaternion.identity);
go.transform.SetParent(transform);
foreach (Sprite s in sprites)
{
if (s.name == str)
{
SpriteRenderer spriteRenderer = go.transform.GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteRenderer.sprite = s;
}
break;
}
}
go.SetActive(true);
}
}
//反向映射地图障碍等,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];
}
}
}
}
玩家移动:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpriteAnim : MonoBehaviour
{
public float moveSpeed = 3;
Sprite[] sprites;
string dir = "";//移动方向
string currentStr = "DOWN";//默认方向
public int tox = 1;
public int toy = 1;
Vector3 myCoordinate;//探路坐标
float animTimer = 0;//动画帧
bool isKeyUp = true;
bool isMoving = false;
int keyboard = 0;
int STEP = 0;//移动步数,预留遇敌功能
void Start()
{
transform.position = new Vector2(tox, toy);
myCoordinate = transform.position;
// 加载精灵图集
sprites = Resources.LoadAll<Sprite>("主角1");
transform.GetComponent<SpriteRenderer>().sprite = sprites[0];
//tox = (int)myCoordinate.x;
//toy = (int)myCoordinate.y;
}
void Update()
{
if (Input.GetKeyUp(KeyCode.S) || Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.D) || Input.GetKeyUp(KeyCode.W))
{
keyboard = 0;
isKeyUp = true;
}
if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.S)
|| Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.A)
|| Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.D)
|| Input.GetKey(KeyCode.S) && Input.GetKey(KeyCode.A)
|| Input.GetKey(KeyCode.S) && Input.GetKey(KeyCode.D)
|| Input.GetKey(KeyCode.A) && Input.GetKey(KeyCode.D))
{
isKeyUp = true;
keyboard = 2;//同时有两个按键则返回
}
if (!isMoving)
{
if (Input.GetKey(KeyCode.W))
{
isKeyUp = false;
dir = "UP";
}
else if (Input.GetKey(KeyCode.S))
{
isKeyUp = false;
dir = "DOWN";
}
else if (Input.GetKey(KeyCode.A))
{
isKeyUp = false;
dir = "LEFT";
}
else if (Input.GetKey(KeyCode.D))
{
isKeyUp = false;
dir = "RIGHT";
}
}
//多个方向同时按键则急停
switch (dir)
{
case "UP":
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D) || Input.GetKeyUp(KeyCode.W))
{
isKeyUp = true;
}
break;
case "LEFT":
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.D) || Input.GetKeyUp(KeyCode.A))
{
isKeyUp = true;
}
break;
case "RIGHT":
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.W) || Input.GetKeyUp(KeyCode.D))
{
isKeyUp = true;
}
break;
case "DOWN":
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D) || Input.GetKeyUp(KeyCode.S))
{
isKeyUp = true;
}
break;
}
if (myCoordinate == transform.position)
{
isMoving = false;
switch (dir)
{
case "UP":
tox = (int)myCoordinate.x;
toy = (int)myCoordinate.y + 1;
break;
case "LEFT":
tox = (int)myCoordinate.x - 1;
toy = (int)myCoordinate.y;
break;
case "RIGHT":
tox = (int)myCoordinate.x + 1;
toy = (int)myCoordinate.y;
break;
case "DOWN":
tox = (int)myCoordinate.x;
toy = (int)myCoordinate.y - 1;
break;
}
if (currentStr != dir)
{
if (keyboard < 2)
{
Debug.Log("方向不同");
PlayerAnim(0);
currentStr = dir;
}
}
//不可移动判断
if (isKeyUp) return;
//如果移动的范围超过地图的范围,则不可移动
if (toy < 0 || tox < 0) return;
if (toy > MapLoader.mapdata.GetLength(1) - 1 || tox > MapLoader.mapdata.GetLength(0) - 1) return;
if (MapLoader.mapdata[tox, toy] == 29) return;
if (MapLoader.mapdata[tox, toy] == 7) return;//增加水上无法移动
animTimer = 0;
myCoordinate = new Vector2(tox, toy);
STEP++;
}
else
{
isMoving = true;
transform.position = Vector2.MoveTowards(transform.position, myCoordinate, moveSpeed * Time.deltaTime);
if (animTimer < moveSpeed)
{
animTimer += moveSpeed * Time.deltaTime;
if (animTimer < 0.5f)
{
PlayerAnim(1);
}
else
{
PlayerAnim(0);
}
}
}
}
void PlayerAnim(int stage)
{
//stage为0,各方向第一张精灵图,非移动状态
//stage为1,各方向第二张精灵图,移动状态
switch (dir)
{
case "UP":
transform.GetComponent<SpriteRenderer>().sprite = sprites[12 + stage];
break;
case "LEFT":
transform.GetComponent<SpriteRenderer>().sprite = sprites[4 + stage];
break;
case "RIGHT":
transform.GetComponent<SpriteRenderer>().sprite = sprites[8 + stage];
break;
case "DOWN":
transform.GetComponent<SpriteRenderer>().sprite = sprites[0 + stage];
break;
}
}
}
队友跟随:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowHand : MonoBehaviour
{
Sprite[] sprites;//精灵动画
float animTimer = 0;//动画帧
public Transform followObj;//跟随目标
public float moveSpeed = 3;//这个速度和followObj的速度必须保持一致
Vector3 movePoint;//下一个移动点
Vector3 prevPos;//玩家移动插值帧
Vector3 prevSelfPos;//自身移动插值帧
string dir = "DOWN";//默认移动方向
bool startFollow = false;//第一次如果是重合防止移动
void Start()
{
// 加载精灵图集
sprites = Resources.LoadAll<Sprite>("主角1");
transform.GetComponent<SpriteRenderer>().sprite = sprites[0];
transform.position = followObj.position;
prevPos = followObj.position;
movePoint = transform.position;
}
private void Update()
{
Follow();
}
//精灵动画方向工具
void PlayerAnim(int stage)
{
switch (dir)
{
case "UP":
transform.GetComponent<SpriteRenderer>().sprite = sprites[12 + stage];
break;
case "LEFT":
transform.GetComponent<SpriteRenderer>().sprite = sprites[4 + stage];
break;
case "RIGHT":
transform.GetComponent<SpriteRenderer>().sprite = sprites[8 + stage];
break;
case "DOWN":
transform.GetComponent<SpriteRenderer>().sprite = sprites[0 + stage];
break;
}
}
void Follow()
{
if (Vector3.Distance(transform.position, followObj.position) >= 1)
{
startFollow = true;
}
if (followObj && startFollow)
{
transform.position = Vector3.MoveTowards(transform.position, movePoint, moveSpeed * Time.deltaTime);
float moveX = followObj.position.x - prevPos.x;
float moveY = followObj.position.y - prevPos.y;
float mX = transform.position.x - prevSelfPos.x;
float mY = transform.position.y - prevSelfPos.y;
if (mX > 0)
{
dir = "RIGHT";
}
if (mX < 0)
{
dir = "LEFT";
}
if (mY > 0)
{
dir = "UP";
}
if (mY < 0)
{
dir = "DOWN";
}
//跟随原理,unity玩家队列跟随
if (Vector3.Distance(movePoint, transform.position) == 0)
{
if (Vector3.Distance(transform.position, followObj.position) != 1)
{
animTimer = 0;
movePoint = new Vector3(Mathf.RoundToInt(prevPos.x), Mathf.RoundToInt(prevPos.y), 0);
}
if (Vector3.Distance(transform.position, followObj.position) > 1)
{
if (transform.position.x == followObj.position.x && moveX == 0)
{
if (transform.position.y < followObj.position.y)
{
transform.position = new Vector3(followObj.position.x, followObj.position.y - 1, 0);
}
else if (transform.position.y > followObj.position.y)
{
transform.position = new Vector3(followObj.position.x, followObj.position.y + 1, 0);
}
}
if (transform.position.y == followObj.position.y && moveY == 0)
{
if (transform.position.x < followObj.position.x)
{
transform.position = new Vector3(followObj.position.x - 1, followObj.position.y, 0);
}
else if (transform.position.x > followObj.position.x)
{
transform.position = new Vector3(followObj.position.x + 1, followObj.position.y, 0);
}
}
}
prevPos = followObj.position;
prevSelfPos = transform.position;
}
else
{
//移动就播放动画帧
if (animTimer < moveSpeed)
{
animTimer += moveSpeed * Time.deltaTime;
if (animTimer < 0.5f)
{
PlayerAnim(1);//移动中
}
else
{
PlayerAnim(0);//待机中
}
}
}
}
}
}
场景布局:
主角:
地图加载:
队列:
地图json二维数组:
主角精灵素材:
地图素材:
我切换了json脚本,使用拉多地图测试:
运行效果:
重装机兵
npc和玩家移动一格播放两张精灵图片,这个也适用于吞食天地2。
剩余部分就是显示玩家区域部分地图块了,大地图非常大,计算玩家坐标和区域范围,只加载玩家范围内地图,超出部分置为空减少消耗。
源码:
莫要客气
地图滚动在此文章:unity复刻重装机兵地图滚动