经过一阵子的学习,再次上传一份小游戏,叫“抓住神经猫”的游戏,通过二维数组,实例化出场景并进行游戏,直到围住神经猫或者让它逃脱为止。
首先呢,我把用到的图片上传,然后感兴趣的朋友可以保存图片然后复制代码进行游戏,各种函数都有介绍,希望大家能够喜欢以及支持我,以后会更新更多的自己学会的游戏并上传代码进行解说的,谢谢。
首先,我们打开Unity创建好2D 工程之后,建立一个空物体命名为GameController,然后添加场景,把背景图片拖入GameController中,如下,是一张背景图片:
1.1 游戏背景图片
这是游戏开始、游戏胜利、游戏失败、游戏重新开始的图片,我们把它也作为GameController的子物体拖入:
1.2 游戏开始图片
1.3 游戏胜利图片
1.4 游戏失败图片
1.5 游戏重新开始的图片
把这些图片都拖入GameController之后,我们把上面出背景之外的所有对象全部取消渲染,然后添加两个预设体pot1和pot2,(在2D工程中设置预设体的方法:把图片先从文件夹拖入场景中,然后设置完毕之后再把场景中的图片拖入工程文件夹里,这样就能得到预设体了)。
1.6 pot1图片 1.7 pot2图片
之后对我们的主角神经猫进行图片的切割,然后制作成动画Animation,然后把神经猫也设置成预设体:
1.8 神经猫图片
之后,我们就可以开始编码啦,首先,编写控制pot的类脚本Item,来控制游戏场景中的位移与pot的被点击事件,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Item : MonoBehaviour
{
public GameController gameController;
public int rowIndex;
public int columnIndex;
//po1t的偏移量
public float xoff = -2.65f;
public float yoff = -3.3f;
public bool moveAble = true; //用于检验是否可以移动
//更新位置
private void UpdatePosition()
{
Vector3 v = new Vector3(0, 0, 0);
v.x = xoff + 0.6f * columnIndex;
if (rowIndex % 2 == 0)
v.x = xoff + 0.6f * columnIndex + 0.25f;
v.y = yoff + 0.5f * rowIndex;
transform.position = v;
}
//移动的函数,把对象移动到形参设置的位置上
public void Goto(int rowIndex,int columnIndex)
{
this.rowIndex = rowIndex;
this.columnIndex = columnIndex;
UpdatePosition();
}
//鼠标点击后执行Select函数
private void OnMouseDown()
{
gameController.Select(this);
}
}
之后,再通过每次的点击事件来执行GameController脚本中的函数来实现游戏效果,脚本中都有注释,如果有问题的朋友可以提出来大家一起探讨,我就不一一解释了。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameController : MonoBehaviour
{
public GameObject pot1;
public GameObject pot2;
public GameObject cat; //神经猫
public GameObject startScreen; //开始按钮
public GameObject victory; //胜利图标
public GameObject failed; //失败图标
public GameObject replay; //重玩图标
//可点击的矩阵大小
public int rowNum = 9;
public int columnNum = 9;
//设置两个储存pot1和pot2的数组
private ArrayList potArr;
private ArrayList pot2Arr;
//两个判断游戏是否开始与结束的bool变量
private bool started = false;
private bool gameOver = false;
// 初始化pot1,建立二维数组
void Start()
{
startScreen.GetComponent<StartGame>().gameControlller = this;
replay.GetComponent<StartGame>().gameControlller = this;
//初始化pot2的数组
pot2Arr = new ArrayList();
//初始化pot的数组
potArr = new ArrayList();
//建立一个pot的二维数组
for (int columnIndex = 0; columnIndex < columnNum; columnIndex++)
{
ArrayList temp = new ArrayList();
for (int rowIndex = 0; rowIndex < rowNum; rowIndex++)
{
Item item = CreatePot(pot1, rowIndex, columnIndex);
temp.Add(item);
}
potArr.Add(temp);
}
}
//游戏开始,设置游戏开始时的所有状态
public void StartGame()
{
//游戏开始的状态
started = true;
startScreen.SetActive(false);
//游戏结束的状态,关闭其他几个可视化窗口
failed.SetActive(false);
victory.SetActive(false);
replay.SetActive(false);
gameOver = false;
//初始化猫的位置
cat.SetActive(true);
MoveCat(Random.Range(3, rowNum - 3), Random.Range(3, columnNum - 3)); //随机设置神经猫的生成点
//恢复所有pot1的点
for(int rowIndex=0;rowIndex<rowNum;rowIndex++)
{
for(int columnIndex=0;columnIndex<columnNum;columnIndex++)
{
Item item = GetPot(rowIndex, columnIndex);
item.moveAble = true;
}
}
//移除所有的pot2
foreach(Item item2 in pot2Arr)
{
Destroy(item2.gameObject);
}
//清空pot2的所有实例化对象
pot2Arr.Clear();
}
//从potArr数组中获取点的Item信息
Item GetPot(int rowIndex,int columnIndex)
{
//判断pot是否超出了数组的范围,已经离开了游戏场景
if (rowIndex < 0 || rowIndex > rowNum - 1 || columnIndex < 0 || columnIndex > columnNum - 1)
return null;
ArrayList temp = potArr[rowIndex] as ArrayList;
Item item = temp[columnIndex] as Item;
return item;
}
//移动神经猫
void MoveCat(int rowIndex ,int columnIndex)
{
Item item = cat.GetComponent<Item>();
item.Goto(rowIndex, columnIndex);
}
//判断该坐标是否可以移动
bool MoveAble(Vector2 vec2)
{
Item item = GetPot((int)vec2.x, (int)vec2.y);
if (item == null)
return false;
return item.moveAble;
}
//判断神经猫是否逃离至边界
bool Escaped()
{
//获取神经猫的Item并取行列的值
Item item = cat.GetComponent<Item>();
int rowIndex = item.rowIndex;
int columnIndex = item.columnIndex;
//如果神经猫跑到边界了则返回真
if (rowIndex == 0 || rowIndex == rowNum - 1 || columnIndex == 0 || columnIndex == columnNum - 1)
return true;
return false;
}
//设置点击事件发生后的一系列相应事件
public void Select(Item item)
{
if (!started || gameOver) return; //如果游戏还没开始,则不能进行点击
if (item.moveAble)
{
//获取神经猫的Item并取行列的值
Item item2 = CreatePot(pot2, item.rowIndex, item.columnIndex);
pot2Arr.Add(item2);
item.moveAble = false;
ArrayList steps = FindSteps();
//如果神经猫还可以移动
if (steps.Count > 0)
{
//随机移动神经猫
int index = Random.Range(0, steps.Count);
Vector2 temp = (Vector2)steps[index];
MoveCat((int)temp.y, (int)temp.x);
//如果神经猫已经逃离到了边界
if (Escaped())
{
gameOver = true;
failed.SetActive(true);
replay.SetActive(true);
print("Escaped");
}
}
//如果神经猫已经没有可移动的pot了
else
{
gameOver = true;
victory.SetActive(true);
replay.SetActive(true);
}
}
}
//寻找神经猫周围的可移动点,并返回可移动的点的数组
ArrayList FindSteps()
{
//获取神经猫的Item并取行列的值
Item item = cat.GetComponent<Item>();
int rowIndex = item.rowIndex;
int columnIndex = item.columnIndex;
//用steps来储存可移动的pot,用vec2来储存可移动pot的行列值
ArrayList steps = new ArrayList();
Vector2 vec2 = new Vector2();
//left
vec2.y = rowIndex;
vec2.x = columnIndex - 1;
if (MoveAble(vec2))
{
steps.Add(vec2);
//print("LEFT:" + vec2.y + "," + vec2.x);
}
//right
vec2.y = rowIndex;
vec2.x = columnIndex + 1;
if (MoveAble(vec2))
{
steps.Add(vec2);
//print("RIGHT:" + vec2.y + "," + vec2.x);
}
//top
vec2.y = rowIndex + 1;
vec2.x = columnIndex;
if (MoveAble(vec2))
{
steps.Add(vec2);
//print("TOP:" + vec2.y + "," + vec2.x);
}
//bottom
vec2.y = rowIndex - 1;
vec2.x = columnIndex;
if (MoveAble(vec2))
{
steps.Add(vec2);
//print("BOTTOM:" + vec2.y + "," + vec2.x);
}
//奇数行 topLeft 偶数行 topRight
vec2.y = rowIndex + 1;
if (rowIndex % 2 == 1)
vec2.x = columnIndex - 1;
else
vec2.x = columnIndex + 1;
if (MoveAble(vec2))
{
steps.Add(vec2);
//print("TOPLEFT OR TOPRIGHT:" + vec2.y + "," + vec2.x);
}
//奇数行 bottomLeft 偶数行 bottomRight
vec2.y = rowIndex - 1;
if (rowIndex % 2 == 1)
vec2.x = columnIndex - 1;
else
vec2.x = columnIndex + 1;
if (MoveAble(vec2))
{
steps.Add(vec2);
//print("BOTTOMLEFT OR BOTTOMRIGHT:" + vec2.y + "," + vec2.x);
}
return steps;
}
//创建pot
Item CreatePot(GameObject pot, int rowIndex, int columnIndex)
{
GameObject obj = Instantiate(pot) as GameObject;
obj.transform.parent = this.transform; //放在同一个父物体下,方便管理
Item item = obj.GetComponent<Item>(); //获取实例化pot上的Item属性
item.Goto(rowIndex, columnIndex); //设置pot的位置
item.gameController = this; //令实例化的pot获取gameController属性,方便函数Select的调用
return item;
}
}
创作完毕之后我们再给游戏开始的图片和重新开始的图片添加BoxCollider2D来实现可点击效果,并添加下面这个脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StartGame : MonoBehaviour {
public GameController gameControlller;
public void OnMouseDown()
{
gameControlller.StartGame();
}
}
如此,我们的游戏功能就基本上都实现了,为了要让pot1可以被点击,记得给pot1添加碰撞体CircleCollider,并添加Item类脚本,为了让每一次实例化的pot都能够实现想要改变的功能,大家修改的时候可以直接修改预设体的信息。