在Resources——Picture中新建Map文件夹,并将每个关卡的Map图片放在里面。每个Map图片都是上下无缝连接的。

在Game场景中新建SceneRoot空物体,并拿Main Camera和两张Map作为它的子物体,两张Map分别命名为map_0和map_1,并将两张Map上下无缝贴好,摄像机照向下面的Map。

我们想要Camera一直向Y轴正方向移动,而Camera的Postion和上面的Map重合时,下面的Map转到上面Map的上面,不断重复。

各种配置

将SceneRoot拉取到Resources——Prefab——Game文件夹内。

Consts中添加Map图片的名称前缀

1
public const string MAP_PREFIX = "map_level_";

修改GameStateModel中的Level,修改为PlaneLevel

GameModel中添加SelectedLevel属性,代表当前选择的关卡。

1
public int SelectedLevel { get; set; }

修改LevelItemController,设置每次选中的关卡

1
2
3
4
5
6
transform.ButtonAction("Enter", () =>
{
GameModel.Instance.SelectedLevel = _id;//+++
GameStateModel.Instance.TargetScene = SceneName.Game;
UIMgr.Instance.Show(Pathes.LOADING_VIEW);
});

在StreamingAssets——Config文件夹内,新建GameConfig.json

1
2
3
{
"cameraSpeed": 2
}

Pathes中配置它的路径以及Map图片文件夹的路径和GameConfig.json的路径

1
2
3
4
5
6
7
//游戏预制体路径
private const string PREFAB_GAME_FOLDER = "Prefab/Game/";
public const string PREFAB_SCENEROOT = PREFAB_GAME_FOLDER + "SceneRoot";
//...
public const string MAP_PICTURE_FOLDER = "Picture/Map/"
//...
public static readonly string GAME_CONFIG = CONFIG_FOLDER + "/GameConfig.json";

MapMgr

在Scripts——Logic文件夹下创建MapMgr脚本,这是需要动态挂载到SceneRoot的脚本,用来初始化地图的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using UnityEngine;

public class MapMgr : MonoBehaviour
{
public void Init()
{
Transform camera = transform.Find("Main Camera");
Transform map1 = transform.Find("map_1");
Transform map0 = transform.Find("map_0");
float offset = Mathf.Abs(map1.position.y - map0.position.y);
var item0 = map0.AddCo<MapItem>();
item0.Init(offset, camera);
var item1 = map1.AddCo<MapItem>();
item1.Init(offset, camera);
camera.AddCo<CameraMove>();
}
}

SceneConfig

SceneConfig中添加新的Game场景初始化逻辑。

1
2
3
4
5
6
7
8
9
10
11
private void AddLoaded()
{
SceneMgr.Instance.AddSceneLoaded(SceneName.Game, callback => PoolMgr.Instance.Init(callback));
SceneMgr.Instance.AddSceneLoaded(SceneName.Game, callback =>
{
var go = LoadMgr.Instance.LoadPrefabAndInstantiate(Pathes.PREFAB_SCENEROOT);
var mapMgr = go.AddComponent<MapMgr>();
mapMgr.Init();
callback?.Invoke();
});
}

MapItem

这是每个Map的GameObject需要挂载的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using UnityEngine;

public class MapItem : MonoBehaviour, IUpdate
{
private float _offset;
private Transform _cameraTrans;
private SpriteRenderer _spriteRenderer;
public void Init(float offset, Transform camTrans)
{
_offset = offset;
_cameraTrans = camTrans;
_spriteRenderer = GetComponent<SpriteRenderer>();
LifeCycleMgr.Instance.Add(LifeName.UPDATE, this);
SetSprite();
}
private void SetSprite()
{
int level = GameModel.Instance.SelectedLevel;
string name = Consts.MAP_PREFIX + level;
Sprite sprite = LoadMgr.Instance.Load<Sprite>(Pathes.MAP_PICTURE_FOLDER + name);
if(sprite == null)
{
sprite = LoadMgr.Instance.Load<Sprite>(Pathes.MAP_PICTURE_FOLDER + Consts.MAP_PREFIX + 0);
}
_spriteRenderer.sprite = sprite;
}

public void UpdateFun()
{
if (JudgeMove(_offset, _cameraTrans))
{
Move(_offset);
}
}

private bool JudgeMove(float offset, Transform camTrans)
{
return camTrans.position.y - transform.position.y >= offset;
}
private void Move(float offset)
{
var pos = transform.position;
pos.y += offset * 2;
transform.position = pos;
}
private void OnDestroy()
{
LifeCycleMgr.Instance.Remove(LifeName.UPDATE, this);
}
}

SerSprite方法:根据当前关卡Level加载不同的背景Sprite

CameraMove

动态挂载在Camera上,让它开始移动的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using UnityEngine;

public class CameraMove : MonoBehaviour, IUpdate
{
private float _speed;

private void Start()
{
_speed = 0;
var reader = ReaderMgr.Instance.GetReader(Pathes.GAME_CONFIG);
reader["cameraSpeed"].Get<float>(value =>
{
_speed = value;
});
LifeCycleMgr.Instance.Add(LifeName.UPDATE, this);
}
public void UpdateFun()
{
transform.Translate(0, _speed * Time.deltaTime, 0);
}
private void OnDestroy()
{
LifeCycleMgr.Instance.Remove(LifeName.UPDATE, this);
}
}