3D游戏编程与设计-井字棋
目录
A. 简答题
1. 解释游戏对象(GameObjects)和资源(Assets)的区别与联系
① 游戏对象
游戏对象是在游戏中真实存在一个物体
是可以进行选中操作的对象
一个能够容纳实现实际功能的组件
② 资源
是对游戏对象的一个修饰
指的是在游戏中可能用到的各种东西
比如模型、声音文件、贴图文件等等
2. 下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
资源的目录组织结构基本包括
Prefabs预设,resources动态加载的资源文件
Scenes场景文件,Scenes场景文件
Scripts脚本代码文件,Sounds音效文件,Textures所有的贴图等等
而游戏对象树类似于多个父子继承关系,一个游戏对象往往是包括了多个子对象
3. 编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript1 : MonoBehaviour {
void Awake()
{
Debug.Log("Awake!");
}
void Start()
{
Debug.Log("Start!");
}
void Update()
{
Debug.Log("Update!");
}
void FixedUpdate()
{
Debug.Log("FixedUpdate!");
}
void LateUpdate()
{
Debug.Log("LateUpdate!");
}
void Reset()
{
Debug.Log("Reset!");
}
void OnGUI()
{
Debug.Log("onGUI!");
}
void OnDisable()
{
Debug.Log("onDisable!");
}
void OnDestroy()
{
Debug.Log("onDestroy!");
}
}
4. 查找脚本手册,了解 GameObject,Transform,Component 对象
① 分别翻译官方对三个对象的描述(Description)
GameObject: 游戏中的每个对象都是一个游戏对象(GameObject)。然而,游戏对象(GameObjects)本身不做任何事情。它们需要特殊属性(special properties)才能成为一个角色、一种环境或者一种特殊效果。
Transform:变换(Transforms)是每个游戏对象(GameObject)的关键组件(Component)。它们决定游戏对象 (GameObject)的位置、旋转方式及缩放。
Reset:在游戏中,组件(Components)就是对象和行为的螺栓与螺母,它们是每个游戏对象 (GameObject)的功能零件。
② 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
table 的对象是GameObject
第一个选择框是 activeSelf属性
第二个选择框是Transform属性
第三个选择框是Mesh Filter筛网过滤器属性
第四个选择框是Box Collider属性
第五个选择框是Mesh Renderer筛网渲染器属性
第六个选择框是Default-Material属性。
③ 用 UML 图描述三者的关系
5. 资源预设(Prefabs)与 对象克隆 (clone)
① 预设(Prefabs)有什么好处?
预设是一个非常容易复用的类模板
可以迅速方便创建大量相同属性的对象
好处是操作简单,代码量少,减少出错概率
② 预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?
预设可以使修改的复杂度降低
一旦需要修改所有相同属性的对象,只需要修改预设即可
所有通过预设实例化的对象都会做出相应变化
而克隆只是复制一个一模一样的对象
这个对象独立于原来的对象
在修改的过程中不会影响原有的对象
这样不方便整体改动
③ 制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象
void Start()
{
Debug.Log("Start!");
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.name = "a cube";
cube.transform.position = new Vector3(0, 1, 2);
cube.transform.parent = this.transform;
}
B. 井字棋的设计
1. 核心脚本
变量
public Texture2D img1;//棋子图片
public Texture2D img2;//同上
public Texture2D imgBack;//背景图片
private int player;//用奇偶决定当前是哪个玩家下棋
private int result;//胜负结果
private int [,] matrix2D;//棋盘
private int [] repent;//记录上一步棋子,用来悔棋
Start函数:调用Reset函数
void Start()
{
Reset();
}
Reset函数:重启
void Reset()
{
player = 0;
result = 0;
matrix2D = new int [3,3]
{
{0,0,0},
{0,0,0},
{0,0,0}
};
repent = new int [2] {0,0};
}
Repent函数:悔棋操作
void Repent()
{
player ++;//+1和-1都一样
matrix2D[repent[0],repent[1]] = 0;
}
check函数:检测是否有玩家胜出
int check()
{
for(int i = 0;i < 3;i ++)
{
if(matrix2D[i,0] == matrix2D[i,1] && matrix2D[i,1]== matrix2D[i,2] && matrix2D[i,0] != 0)
return matrix2D[i,0];
if(matrix2D[0,i] == matrix2D[1,i] && matrix2D[1,i]== matrix2D[2,i] && matrix2D[0,i] != 0)
return matrix2D[0,i];
}
if(matrix2D[0,0] == matrix2D[1,1] && matrix2D[1,1] ==matrix2D[2,2])
return matrix2D[1,1];
if(matrix2D[0,2] == matrix2D[1,1] && matrix2D[1,1] ==matrix2D[2,0])
return matrix2D[1,1];
return 0;
}
OnGUI函数:UI界面
void OnGUI()
{
GUI.Label(new Rect(600,300,150,150),"");
if (GUI.Button(new Rect(600, 0, 150, 150), "restart"))
Reset();
if ( result == 0 && GUI.Button(new Rect(600, 150, 150, 150), "repent"))
Repent();
else
;
GUIStyle fontStyle = new GUIStyle();
fontStyle.normal.background = null;
fontStyle.normal.textColor= new Color(1, 1, 1);
fontStyle.fontSize = 15;
for(int i = 0;i < 3;i ++ )
{
for(int j = 0;j < 3;++ j)
{
if(matrix2D[i,j] == 1)
GUI.Button(new Rect(150*i, 150*j, 150, 150), img1);
else if(matrix2D[i,j] == 2)
GUI.Button(new Rect(150*i, 150*j, 150, 150), img2);
else if(result != 0)
{
if(GUI.Button(new Rect(150*i, 150*j, 150, 150), imgBack))
;
}
else
{
if(GUI.Button(new Rect(150*i, 150*j, 150, 150), imgBack))
{
matrix2D[i,j] = 1 + player % 2;
repent[0] = i; repent[1] = j;
result = check();
player ++;
}
}
}
}
if (result == 1)
{
GUI.Label (new Rect (600, 300, 150, 150), "Player1 wins!", fontStyle);
}
else if (result == 2)
{
GUI.Label (new Rect (600, 300, 150, 150), "Player2 wins!", fontStyle);
}
else
{
GUI.Label (new Rect (600, 300, 150, 150), "Playing...", fontStyle);
}
}
完整脚本代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UI : MonoBehaviour
{
public Texture2D img1;
public Texture2D img2;
public Texture2D imgBack;
private int player;
private int result;
private int [,] matrix2D;
private int [] repent;
void OnGUI()
{
GUI.Label(new Rect(600,300,150,150),"");
if (GUI.Button(new Rect(600, 0, 150, 150), "restart"))
Reset();
if ( result == 0 && GUI.Button(new Rect(600, 150, 150, 150), "repent"))
Repent();
else
;
GUIStyle fontStyle = new GUIStyle();
fontStyle.normal.background = null;
fontStyle.normal.textColor= new Color(1, 1, 1);
fontStyle.fontSize = 15;
for(int i = 0;i < 3;i ++ )
{
for(int j = 0;j < 3;++ j)
{
if(matrix2D[i,j] == 1)
GUI.Button(new Rect(150*i, 150*j, 150, 150), img1);
else if(matrix2D[i,j] == 2)
GUI.Button(new Rect(150*i, 150*j, 150, 150), img2);
else if(result != 0)
{
if(GUI.Button(new Rect(150*i, 150*j, 150, 150), imgBack))
;
}
else
{
if(GUI.Button(new Rect(150*i, 150*j, 150, 150), imgBack))
{
matrix2D[i,j] = 1 + player % 2;
repent[0] = i; repent[1] = j;
result = check();
player ++;
}
}
}
}
if (result == 1)
{
GUI.Label (new Rect (600, 300, 150, 150), "Player1 wins!", fontStyle);
}
else if (result == 2)
{
GUI.Label (new Rect (600, 300, 150, 150), "Player2 wins!", fontStyle);
}
else
{
GUI.Label (new Rect (600, 300, 150, 150), "Playing...", fontStyle);
}
}
void Start()
{
Reset();
}
void Reset()
{
player = 0;
result = 0;
matrix2D = new int [3,3]
{
{0,0,0},
{0,0,0},
{0,0,0}
};
repent = new int [2] {0,0};
}
void Repent()
{
player ++;
matrix2D[repent[0],repent[1]] = 0;
}
int check()
{
for(int i = 0;i < 3;i ++)
{
if(matrix2D[i,0] == matrix2D[i,1] && matrix2D[i,1]== matrix2D[i,2] && matrix2D[i,0] != 0)
return matrix2D[i,0];
if(matrix2D[0,i] == matrix2D[1,i] && matrix2D[1,i]== matrix2D[2,i] && matrix2D[0,i] != 0)
return matrix2D[0,i];
}
if(matrix2D[0,0] == matrix2D[1,1] && matrix2D[1,1] ==matrix2D[2,2])
return matrix2D[1,1];
if(matrix2D[0,2] == matrix2D[1,1] && matrix2D[1,1] ==matrix2D[2,0])
return matrix2D[1,1];
return 0;
}
void Update(){
}
}
脚本挂在创建的一个Empty游戏对象。
2. 棋子与背景图片
棋子1号
棋子2号
背景图片
挂在脚本位置