这是我学Unity3D的第一个小游戏,挺简单的,代码量也不多,参考博客是 UNITY3D学习(1)之GUI井字棋。对于Unity3D,想必大家都比较熟悉了的,我就不多作介绍了。需要了解Unity3D的,可以去这个博客——【Unity3D入门教程】Unity3D简介、安装和程序发布。
好了,闲话就不说了,先来看看成品:
首先就是游戏背景,在这次项目中呢,背景其实是有点水分的。就是Create一个plane,然后,用一张贴图贴在plane上,再将摄像机的镜头对准平面就好了,就这么伪装出了一个背景。当然,你要是觉得这样子操作麻烦,也可以用代码实现。代码如下:
public Texture2D img;
GUIStyle bground = new GUIStyle();
bground.normal.background = img;
GUI.Label(new Rect(0, 0, Screen.width, Screen.height), "", bground);
后面就都是代码实现就好了。先是在Asserts里面创建一个一个C#文件(最好还是讲将资源归类,即在Asserts下面创建一个Scripts文件夹,再将C#文件放在Scripts里面)。
下面对代码实现说明一下过程:
首先,就是实现一个ResetMap()函数,用于放在Start()中将棋盘初始化,同时也用在Reset按钮中,实现棋盘的初始化。代码实现很简单,就是开一个3*3的数组,将里面的元素全部初始化为0就好。如下:
/// <summary>
/// 重置地图(全为0)
/// </summary>
void ResetMap()
{
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
map[i, j] = 0;
}
}
}
其次,写一个WhetherWin()函数,用来判定游戏是否已经结束了,并且给出是蓝方赢了还是红方赢了。判定的方法也很简单,就判断数组行、列或对角是否三个数相等即可。具体代码如下:
/// 判断游戏是否结束
/// </summary>
/// <returns>1表示蓝方赢,2表示红方赢</returns>
private int WhetherWin()
{
for(int i = 0; i < 3; i++)
{
if(map[i, 0] == map[i, 1] && map[i, 1] == map[i, 2] && map[i, 0] != 0)
{
return map[i, 0];
}
}
for(int j = 0; j < 3; j++)
{
if(map[0, j] == map[1, j] && map[1, j] == map[2, j] && map[0, j] != 0)
{
return map[0, j];
}
}
if(map[0, 0] == map[1, 1] && map[1, 1] == map[2, 2] && map[0, 0] != 0)
{
return map[0, 0];
}
if(map[0, 2] == map[1, 1] && map[1, 1] == map[2, 0] && map[1, 1] != 0)
{
return map[1, 1];
}
return 0;
}
最后,就是完成OnGUI()方法就好了。主要的做法,就是做出一个由九个Label组装成的九宫格,每个Label分别对应map数组中的每个元素。例如,当map[0, 0]中的值为0时,表示这个地方还为被占领,当值为1时,表示已经被蓝方占领了,当值为2时,表示已经被红方占领了。每一次鼠标点击Label,若对应数组元素的值为0,就把该处的值赋值为1或者2,并在每帧图像中对已经被占领了的Label加上背景,作为占领的标志。具体的实现如下:
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
float x = midWidth - 1.5f * buttonEdge + j * buttonEdge;
float y = midHeight - 1.5f * buttonEdge + i * buttonEdge;
if ( map[i, j] == 1)
{
GUI.Button(new Rect(x, y, buttonEdge, buttonEdge), img_0);
}
else if(map[i, j] == 2)
{
GUI.Button(new Rect(x, y, buttonEdge, buttonEdge), img_1);
}
else
{
if(GUI.Button(new Rect(x, y, buttonEdge, buttonEdge), ""))
{
if(player % 2 == 0)
{
map[i, j] = 1;
}
else
{
map[i, j] = 2;
}
player = (player + 1) % 2;
}
}
}
在这次项目中,主要用到的是GUI控件中的Label和Button,关于这两个控件的具体用法,可参考这个博客——Unity3D入门篇——第三讲 GUI控件(一)。
核心的逻辑大概就是这些啦。至于具体的UI要设置成什么样子,可以在了解了这些控件的用法后,实现成自己想要的那个样子。
当然,既然是游戏,就肯定不能就这么一个画面,肯定要加一点声音上去的。找一个游戏对象(在这里就只有摄影机和平面了),然后,AddComponent -> Audio ->Audio Source。接下来,如图:
接着,在摄像机这个对象上,AddComponent -> Audio -> Audio Listener,游戏就会有背景音乐了。要是需要对音频有更高的要求,可以参考博客——关于Unity中3D声音的使用。
接下来就说一下贴图怎么放进去吧。虽然这个挺简单的,当时自己也找了挺久才知道怎么弄。由于我们把C#文件绑定在了摄像机上,在摄像机的C#文件组件中,我们可以看到下面这样:
然后,就是一样的套路,点击箭头所指的那里,添加textures就行了。
至此,我的第一个小项目就完成了,下面附上完成的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameScense : MonoBehaviour {
//地图。 0表示未被占据,1 表示蓝色方占据, 2表示红色方占据
private int[,] map = new int[3, 3];
private int player = 0;
public AudioClip audio; //开始的音乐
private AudioSource audioSource;
//玩家图片
public Texture2D img_0;
public Texture2D img_1;
/// <summary>
/// 重置地图(全为0)
/// </summary>
void ResetMap()
{
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
map[i, j] = 0;
}
}
audioSource.Play();
//startAudio.gameObject.GetComponent<AudioSource>().Play();
}
private void Awake()
{//设置AudioSource组件
audioSource = this.gameObject.GetComponent<AudioSource>();
audioSource.loop = false;
audioSource.volume = 1.0f;
audioSource.clip = audio;
}
// Use this for initialization
void Start () {
ResetMap();
}
/// <summary>
/// 判断游戏是否结束
/// </summary>
/// <returns>1表示蓝方赢,2表示红方赢</returns>
private int WhetherWin()
{
for(int i = 0; i < 3; i++)
{
if(map[i, 0] == map[i, 1] && map[i, 1] == map[i, 2] && map[i, 0] != 0)
{
return map[i, 0];
}
}
for(int j = 0; j < 3; j++)
{
if(map[0, j] == map[1, j] && map[1, j] == map[2, j] && map[0, j] != 0)
{
return map[0, j];
}
}
if(map[0, 0] == map[1, 1] && map[1, 1] == map[2, 2] && map[0, 0] != 0)
{
return map[0, 0];
}
if(map[0, 2] == map[1, 1] && map[1, 1] == map[2, 0] && map[1, 1] != 0)
{
return map[1, 1];
}
return 0;
}
//用屏幕的高度作为度量单位来处理屏幕大小不同而导致的问题
private void OnGUI()
{
int midWidth = Screen.width / 2;
int midHeight = Screen.height / 2;
int buttonEdge = Screen.height / 5;
GUIStyle fontStyle_0 = new GUIStyle();
fontStyle_0.fontSize = buttonEdge / 2;
fontStyle_0.fontStyle = FontStyle.Bold;
fontStyle_0.normal.textColor = Color.black;
GUIStyle fontStyle_1 = new GUIStyle();
fontStyle_1.fontSize = buttonEdge /2;
fontStyle_1.fontStyle = FontStyle.Bold;
fontStyle_1.normal.textColor = Color.blue;
GUIStyle fontStyle_2 = new GUIStyle();
fontStyle_2.fontSize = buttonEdge / 2;
fontStyle_2.fontStyle = FontStyle.Bold;
fontStyle_2.normal.textColor = Color.red;
GUI.Label(new Rect(midWidth - buttonEdge * 4, midHeight - 1.5f * buttonEdge, 1.5f * buttonEdge, 1.5f * buttonEdge), img_0);
GUI.Label(new Rect(midWidth - buttonEdge * 4, midHeight, 1.5f * buttonEdge, buttonEdge), "Blue", fontStyle_1);
GUI.Label(new Rect(midWidth + buttonEdge * 3, midHeight - 1.5f * buttonEdge, 1.5f * buttonEdge, 1.5f * buttonEdge), img_1);
GUI.Label(new Rect(midWidth + buttonEdge * 3, midHeight, 1.5f * buttonEdge, buttonEdge), "Red", fontStyle_2);
int winner = WhetherWin();
// Debug.Log(winner);
if(winner == 1)
{
if (GUI.Button(new Rect(midWidth - buttonEdge * 1.5f, 0.5f * buttonEdge, 3 * buttonEdge, 3.5f * buttonEdge), "Blue Win", fontStyle_1))
{
ResetMap();
}
}
else if(winner == 2)
{
if (GUI.Button(new Rect(midWidth - buttonEdge * 1.5f,0.5f * buttonEdge, 3 * buttonEdge, 3.5f * buttonEdge), "Red Win", fontStyle_2))
{
ResetMap();
}
}
else
{
GUI.Label(new Rect(midWidth - buttonEdge * 2.5f, buttonEdge / 4, buttonEdge * 2, buttonEdge), "Welcome To Tictactoe", fontStyle_0);
}
if(GUI.Button(new Rect(midWidth - 0.5f*buttonEdge, midHeight + 1.75f*buttonEdge, buttonEdge, 0.5f*buttonEdge), "Reset"))
{
ResetMap();
}
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
float x = midWidth - 1.5f * buttonEdge + j * buttonEdge;
float y = midHeight - 1.5f * buttonEdge + i * buttonEdge;
if ( map[i, j] == 1)
{
GUI.Button(new Rect(x, y, buttonEdge, buttonEdge), img_0);
}
else if(map[i, j] == 2)
{
GUI.Button(new Rect(x, y, buttonEdge, buttonEdge), img_1);
}
else
{
if(GUI.Button(new Rect(x, y, buttonEdge, buttonEdge), ""))
{
if(player % 2 == 0)
{
map[i, j] = 1;
}
else
{
map[i, j] = 2;
}
player = (player + 1) % 2;//改变玩家角色
}
}
}
}
}
}