unity3d 开发入门_unity3d游戏开发入门教程 - CSDN
  • 经过前面《Unity3D入门教程》系列讲解,再加上我们自己的探索,相信大家已经掌握了Unity3D的相关知识和基本方法。本文将使用前面学到的知识,开发一款简单的五子棋程序。本文用到的东西其实不多,非常简单。在最后...

    前言

    经过前面《Unity3D入门教程》系列讲解,再加上我们自己的探索,相信大家已经掌握了Unity3D的相关知识和基本方法。本文将使用前面学到的知识,开发一款简单的五子棋程序。本文用到的东西其实不多,非常简单。在最后我们会把完整工程的源代码发布出来,以供初学者参考。先展示一下最后的运行效果吧。

    1 准备工作

    (1)开发环境:Win10 + Unity5.4.1

    (2)图片素材准备:

    黑棋子和白棋子

       

    棋盘


    获胜提示图片




    2 开发流程

    上文提到的素材可以直接下载我们给出的这些图,也可以自己制作。注意黑白棋子要做成PNG格式,以保证显示的时候棋子四个角是透明的。将用到的图片素材导入到工程当中。新建一个场景,创建一个Plane,作为MainCamera的子物体。将棋盘贴图拖动到Plane上,并且将Plane正面面向摄像机。


    再创建四个sphere,作为Plane的子物体,分别命名为LeftTop、RightTop、LeftBottom、RightBottom。然后把他们的MeshRenderer勾选掉。这些球是为了计算棋子落点所设置的,所以需要把它们与棋盘的四个角点对准。


    然后我们创建一个chess.cs脚本,绑定到MainCamera上。脚本中包含了所有的功能。需要绑定的一些物体如图所示。


    chess.cs脚本如下:

    using UnityEngine;
    using System.Collections;
    
    public class chess : MonoBehaviour {
    
    	//四个锚点位置,用于计算棋子落点
    	public GameObject LeftTop;
    	public GameObject RightTop;
    	public GameObject LeftBottom;
    	public GameObject RightBottom;
    	//主摄像机
    	public Camera cam;
    	//锚点在屏幕上的映射位置
    	Vector3 LTPos;
    	Vector3 RTPos;
    	Vector3 LBPos;
    	Vector3 RBPos;
    
    	Vector3 PointPos;//当前点选的位置
    	float gridWidth =1; //棋盘网格宽度
    	float gridHeight=1; //棋盘网格高度
    	float minGridDis;  //网格宽和高中较小的一个
    	Vector2[,] chessPos; //存储棋盘上所有可以落子的位置
    	int[,] chessState; //存储棋盘位置上的落子状态
    	enum turn {black, white } ;
    	turn chessTurn; //落子顺序
    	public Texture2D white; //白棋子
    	public Texture2D black; //黑棋子
    	public Texture2D blackWin; //白子获胜提示图
    	public Texture2D whiteWin; //黑子获胜提示图
    	int winner = 0; //获胜方,1为黑子,-1为白子
    	bool isPlaying = true; //是否处于对弈状态
    	void Start () {
    		chessPos = new Vector2[15, 15];
    		chessState =new int[15,15];
    		chessTurn = turn.black;
    
    	}
    
    	void Update () {
    
    		//计算锚点位置
    		LTPos = cam.WorldToScreenPoint(LeftTop.transform.position);
    		RTPos = cam.WorldToScreenPoint(RightTop.transform.position);
    		LBPos = cam.WorldToScreenPoint(LeftBottom.transform.position);
    		RBPos = cam.WorldToScreenPoint(RightBottom.transform.position);
    		//计算网格宽度
    		gridWidth = (RTPos.x - LTPos.x) / 14;
    		gridHeight = (LTPos.y - LBPos.y) / 14;
    		minGridDis = gridWidth < gridHeight ? gridWidth : gridHeight;
    		//计算落子点位置
    		for (int i = 0; i < 15; i++)
    		{
    			for (int j = 0; j < 15; j++)
    			{
    				chessPos[i, j] = new Vector2(LBPos.x + gridWidth * i, LBPos.y + gridHeight * j);
    			}
    		}
    		//检测鼠标输入并确定落子状态
    		if (isPlaying && Input.GetMouseButtonDown(0))
    		{
    			PointPos = Input.mousePosition;
    			for (int i = 0; i < 15; i++)
    			{
    				for (int j = 0; j < 15; j++)
    				{   
    					//找到最接近鼠标点击位置的落子点,如果空则落子
    					if (Dis(PointPos, chessPos[i, j]) < minGridDis / 2 && chessState[i,j]==0)
    					{
    						//根据下棋顺序确定落子颜色
    						chessState[i, j] = chessTurn == turn.black ? 1 : -1;
    						//落子成功,更换下棋顺序
    						chessTurn = chessTurn == turn.black ? turn.white : turn.black;                        
    					}
    				}
    			}
    			//调用判断函数,确定是否有获胜方
    			int re = result();
    			if (re == 1)
    			{
    				Debug.Log("黑棋胜");
    				winner = 1;
    				isPlaying = false;
    			}
    			else if(re==-1)
    			{
    				Debug.Log("白棋胜");
    				winner = -1;
    				isPlaying = false;
    			}            
    		}
    		//按下空格重新开始游戏
    		if (Input.GetKeyDown(KeyCode.Space))
    		{
    			for (int i = 0; i < 15; i++)
    			{
    				for (int j = 0; j < 15; j++)
    				{
    					chessState[i, j] = 0;
    				}
    			}
    			isPlaying = true;
    			chessTurn = turn.black;
    			winner = 0;
    		}     
    	}
    	//计算平面距离函数
    	float Dis(Vector3 mPos, Vector2 gridPos)
    	{
    		return Mathf.Sqrt(Mathf.Pow(mPos.x - gridPos.x, 2)+ Mathf.Pow(mPos.y - gridPos.y, 2));
    	}
    
    	void OnGUI()
    	{ 
    		//绘制棋子
    		for(int i=0;i<15;i++)
    		{
    			for (int j = 0; j < 15; j++)
    			{
    				if (chessState[i, j] == 1)
    				{
    					GUI.DrawTexture(new Rect(chessPos[i,j].x-gridWidth/2, Screen.height-chessPos[i,j].y-gridHeight/2, gridWidth,gridHeight),black);
    				}
    				if (chessState[i, j] == -1)
    				{
    					GUI.DrawTexture(new Rect(chessPos[i, j].x - gridWidth / 2, Screen.height - chessPos[i, j].y - gridHeight / 2, gridWidth, gridHeight), white);
    				}               
    			}
    		}
    		//根据获胜状态,弹出相应的胜利图片
    		if (winner ==  1)
    			GUI.DrawTexture(new Rect(Screen.width * 0.25f, Screen.height * 0.25f, Screen.width * 0.5f, Screen.height * 0.25f), blackWin);
    		if (winner == -1)
    			GUI.DrawTexture(new Rect(Screen.width * 0.25f, Screen.height * 0.25f, Screen.width * 0.5f, Screen.height * 0.25f), whiteWin);
    
    	}
    	//检测是够获胜的函数,不含黑棋禁手检测
    	int result()
    	{
    		int flag = 0;
    		//如果当前该白棋落子,标定黑棋刚刚下完一步,此时应该判断黑棋是否获胜
    		if(chessTurn == turn.white)
    		{
    			for (int i = 0; i < 11; i++)
    			{
    				for (int j = 0; j < 15; j++)
    				{
    					if (j < 4)
    					{
    						//横向
    						if (chessState[i, j] == 1 && chessState[i, j + 1] == 1 && chessState[i, j + 2] == 1 && chessState[i, j + 3] == 1 && chessState[i, j + 4] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    						//纵向
    						if (chessState[i, j] == 1 && chessState[i + 1, j] == 1 && chessState[i + 2, j] == 1 && chessState[i + 3, j] == 1 && chessState[i + 4, j] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    						//右斜线
    						if (chessState[i, j] == 1 && chessState[i + 1, j + 1] == 1 && chessState[i + 2, j + 2] == 1 && chessState[i + 3, j + 3] == 1 && chessState[i + 4, j + 4] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    						//左斜线
    						//if (chessState[i, j] == 1 && chessState[i + 1, j - 1] == 1 && chessState[i + 2, j - 2] == 1 && chessState[i + 3, j - 3] == 1 && chessState[i + 4, j - 4] == 1)
    						//{
    						//    flag = 1;
    						//    return flag;
    						//}
    					}
    					else if (j >= 4 && j < 11)
    					{
    						//横向
    						if (chessState[i, j] == 1 && chessState[i, j + 1] == 1 && chessState[i, j + 2] == 1 && chessState[i, j + 3] == 1 && chessState[i, j + 4] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    						//纵向
    						if (chessState[i, j] == 1 && chessState[i + 1, j] == 1 && chessState[i + 2, j] == 1 && chessState[i + 3, j] == 1 && chessState[i + 4, j] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    						//右斜线
    						if (chessState[i, j] == 1 && chessState[i + 1, j + 1] == 1 && chessState[i + 2, j + 2] == 1 && chessState[i + 3, j + 3] == 1 && chessState[i + 4, j + 4] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    						//左斜线
    						if (chessState[i, j] == 1 && chessState[i + 1, j - 1] == 1 && chessState[i + 2, j - 2] == 1 && chessState[i + 3, j - 3] == 1 && chessState[i + 4, j - 4] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    					}
    					else
    					{
    						//横向
    						//if (chessState[i, j] == 1 && chessState[i, j + 1] == 1 && chessState[i, j + 2] == 1 && chessState[i, j + 3] == 1 && chessState[i, j + 4] == 1)
    						//{
    						//    flag = 1;
    						//    return flag;
    						//}
    						//纵向
    						if (chessState[i, j] == 1 && chessState[i + 1, j] == 1 && chessState[i + 2, j] == 1 && chessState[i + 3, j] == 1 && chessState[i + 4, j] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    						//右斜线
    						//if (chessState[i, j] == 1 && chessState[i + 1, j + 1] == 1 && chessState[i + 2, j + 2] == 1 && chessState[i + 3, j + 3] == 1 && chessState[i + 4, j + 4] == 1)
    						//{
    						//    flag = 1;
    						//    return flag;
    						//}
    						//左斜线
    						if (chessState[i, j] == 1 && chessState[i + 1, j - 1] == 1 && chessState[i + 2, j - 2] == 1 && chessState[i + 3, j - 3] == 1 && chessState[i + 4, j - 4] == 1)
    						{
    							flag = 1;
    							return flag;
    						}
    					}
    
    				}
    			}
    			for (int i = 11; i < 15; i++) 
    			{
    				for (int j = 0; j < 11; j++) 
    				{
    					//只需要判断横向  
    					if (chessState[i, j] == 1 && chessState[i, j + 1] == 1 && chessState[i, j + 2] == 1 && chessState[i, j + 3] == 1 && chessState[i, j + 4] == 1)  
    					{  
    						flag = 1;  
    						return flag;  
    					}  
    				}
    			}
    		}
    		//如果当前该黑棋落子,标定白棋刚刚下完一步,此时应该判断白棋是否获胜
    		else if(chessTurn == turn.black)
    		{
    			for (int i = 0; i < 11; i++)
    			{
    				for (int j = 0; j < 15; j++)
    				{
    					if (j < 4)
    					{
    						//横向
    						if (chessState[i, j] == -1 && chessState[i, j + 1] == -1 && chessState[i, j + 2] == -1 && chessState[i, j + 3] == -1 && chessState[i, j + 4] == -1)
    						{
    							flag = -1;
    							return flag;
    						}
    						//纵向
    						if (chessState[i, j] == -1 && chessState[i + 1, j] == -1 && chessState[i + 2, j] == -1 && chessState[i + 3, j] == -1 && chessState[i + 4, j] == -1)
    						{
    							flag = -1;
    							return flag;
    						}
    						//右斜线
    						if (chessState[i, j] == -1 && chessState[i + 1, j + 1] == -1 && chessState[i + 2, j + 2] == -1 && chessState[i + 3, j + 3] == -1 && chessState[i + 4, j + 4] == -1)
    						{
    							flag = -1;
    							return flag;
    						}
    						//左斜线
    						//if (chessState[i, j] == -1 && chessState[i + 1, j - 1] == -1 && chessState[i + 2, j - 2] == -1 && chessState[i + 3, j - 3] == -1 && chessState[i + 4, j - 4] == -1)
    						//{
    						//    flag = -1;
    						//    return flag;
    						//}
    					}
    					else if (j >= 4 && j < 11)
    					{
    						//横向
    						if (chessState[i, j] == -1 && chessState[i, j + 1] == -1 && chessState[i, j + 2] == -1 && chessState[i, j + 3] == -1 && chessState[i, j + 4] ==- 1)
    						{
    							flag = -1;
    							return flag;
    						}
    						//纵向
    						if (chessState[i, j] == -1 && chessState[i + 1, j] == -1 && chessState[i + 2, j] == -1 && chessState[i + 3, j] == -1 && chessState[i + 4, j] == -1)
    						{
    							flag = -1;
    							return flag;
    						}
    						//右斜线
    						if (chessState[i, j] == -1 && chessState[i + 1, j + 1] == -1 && chessState[i + 2, j + 2] == -1 && chessState[i + 3, j + 3] == -1 && chessState[i + 4, j + 4] == -1)
    						{
    							flag = -1;
    							return flag;
    						}
    						//左斜线
    						if (chessState[i, j] == -1 && chessState[i + 1, j - 1] == -1 && chessState[i + 2, j - 2] == -1 && chessState[i + 3, j - 3] == -1 && chessState[i + 4, j - 4] == -1)
    						{
    							flag = -1;
    							return flag;
    						}
    					}
    					else
    					{
    						//横向
    						//if (chessState[i, j] == -1 && chessState[i, j + 1] ==- 1 && chessState[i, j + 2] == -1 && chessState[i, j + 3] == -1 && chessState[i, j + 4] == -1)
    						//{
    						//    flag = -1;
    						//    return flag;
    						//}
    						//纵向
    						if (chessState[i, j] == -1 && chessState[i + 1, j] ==- 1 && chessState[i + 2, j] ==- 1 && chessState[i + 3, j] ==- 1 && chessState[i + 4, j] == -1)
    						{
    							flag = -1;
    							return flag;
    						}
    						//右斜线
    						//if (chessState[i, j] == -1 && chessState[i + 1, j + 1] == -1 && chessState[i + 2, j + 2] == -1 && chessState[i + 3, j + 3] == -1 && chessState[i + 4, j + 4] == -1)
    						//{
    						//    flag = -1;
    						//    return flag;
    						//}
    						//左斜线
    						if (chessState[i, j] == -1 && chessState[i + 1, j - 1] == -1 && chessState[i + 2, j - 2] == -1 && chessState[i + 3, j - 3] == -1 && chessState[i + 4, j - 4] == -1)
    						{
    							flag = -1;
    							return flag;
    						}
    					}
    				}
    			}
    			for (int i = 11; i < 15; i++) 
    			{
    				for (int j = 0; j < 11; j++) 
    				{
    					//只需要判断横向  
    					if (chessState[i, j] == -1 && chessState[i, j + 1] == -1 && chessState[i, j + 2] == -1 && chessState[i, j + 3] == -1 && chessState[i, j + 4] == -1)  
    					{  
    						flag = -1;  
    						return flag;  
    					}  
    				}
    			}
    		}       
    		return flag;
    	}    
    }



    运行效果截图:



    小结

    本程序实现了五子棋的基本功能,纯属娱乐而作。暂时没有加入各种UI、网络模块等。本程序经过了简单的测试,没有什么问题,如果大家在使用的时候发现有什么Bug,请联系我改正,谢谢。

    *************************************************************************************

    下面是工程源码下载地址:

    https://github.com/zzlyw/FiveChess_Tutorial



    展开全文
  • 转自:https://www.jianshu.com/p/ccb491ed4260KSFramework是一个Unity 5 Asset Bundle开发框架和工具集,专注于运行时热重载,使用了SLua作为脚本引擎。https://github.com/mr-kelly/KSFrameworkKSFramework是一个...

    转自:https://www.jianshu.com/p/ccb491ed4260

    KSFramework是一个Unity 5 Asset Bundle开发框架和工具集,专注于运行时热重载,使用了SLua作为脚本引擎。
    https://github.com/mr-kelly/KSFramework

    KSFramework是一个整合KEngine、SLua和一些开发组件组成的全功能Unity 5开发框架,适合有一定规模的团队使用。

    热重载是KSFramework的开发重点——在不重启游戏的前提下,重载代码、配置表可立刻看到修改效果,最大限度的提升开发、调试的速度,并且在运营阶段方便的进行产品热更新。

    看看Demo!

    双击打开Assets/Game.unity场景,点击播放。

    开始Game.unity后的日志输出

    这时候KSFramework的默认Demo开始,做了这些事情:

    • 基础模块的启动
    • Lua模块的启动
    • 尝试读取并打印Excel表格GameConfig.xlsx内容
    • 加载UI界面Login
    • 执行UI界面Login的Lua脚本
    • Lua脚本绑定UI控件、设置UI控件
    • Lua脚本读取并打印Excel表格GameConfig.xlsx内容

    总而言之,这个Demo囊括了KSFramework中的几个核心模块的使用:

    • KEngine中的Setting模块的使用
    • KEngine中的UI的资源加载
    • SLua脚本引擎与UI的联合

    接下来,将模仿这个Demo,创建/加载一个新的UI界面、创建/读取一个新的配置表格。

    尝试做一个公告界面Billboard

    接下来,我们将创建一个UI公告牌(Billboard),使用Lua脚本,并从配置表读取公告内容。

    创建UI资源

    创建New Scene
    KEngine-UI-Create UI创建UI布局
    点击Create UI后,默认随机名字,把UI名字修改为Billboard
    修改UI名字为Billboard,UI界面右边带有黄色UI标识
    编辑一下UI场景,一个背景Image,两个Label
    保存一下场景,保存到Assets/BundleEditing/UI/Billboard.unity
    导出——打包AssetBundle,快捷键Ctrl+Alt+E

    加载UI界面

    好了,Billboard界面创建好了,也导出成了AssetBundle。
    接下来,我们通过代码打开界面。

    编辑Assets/Code/Game.cs

    在OnFinishInitModules函数的末端,加上这样的一句:

    // 开始加载我们的公告界面!
    UIModule.Instance.OpenWindow("Billboard");
    

    完成。 打开场景Assets/Game.unity,点击播放按钮:

    我们的UI通过AssetBundle打开了,弹出提示找不到UI Lua脚本,接下来我们创建Lua脚本吧

    [我们的UI通过AssetBundle打开了,弹出提示找不到UI Lua脚本,接下来我们创建Lua脚本吧。

    创建Lua脚本

    在目录Product/Lua/UI中新建一个lua文件
    写一段Lua代码:UIBillboard的执行逻辑
    local UIBase = import("KSFramework/UIBase")
    
    local UIBillboard = {}
    extends(UIBillboard, UIBase)
    
    function UIBillboard:OnInit(controller)
        self.Controller = controller
        self.TitleLabel = self:GetUIText('Title')
        self.ContentLabel = self:GetUIText('Content')
    end
    
    function UIBillboard:OnOpen()
        self.TitleLabel.text = "This is a title"
        self.ContentLabel.text = "Here is content!"
    end
    
    return UIBillboard
    

    这段lua中,创建了一个Table叫UIBillboard,这个table必须有OnInit(controller)函数。它通过代码设置了UI中的文字。

    好了,接下来,我们要为策划准备配置表了。

    创建配置表

    打开Product/SettingSource目录,复制一份StringsTable.xlsx,并改名叫Billboard.xlsx吧

    复制一份StringsTable.xlsx

    用Excel打开我们新的Billboard.xlsx,编辑我们的公告。我们大概定一下需求,我们假设写入3条公告,每次打开公告随机显示其中一条。每个公告,我们给它一个英文ID,一列中文标题,一列中文内容。

    Excel表修改如下:

    增加公告内容
    回到Unity,监测到Excel变动。点击OK。
    上一步监测到变动,只编译Excel表,手动执行一些重新编译,并生成配置表代码
    这时候,打开AppSettings.cs代码文件,我们可以发现,已经生成名叫BillboardSettings的类了
    因为我们要在Lua使用BillboardSettings读取配置表,这里需要重新生成一下SLua的静态代码
    接下来修改Lua代码,随机读取一条公告,并设置Content、Title
    运行播放Game.unity,我们的公告界面完成了

    公告界面完成了。我们创建了一个UI、写了C#和Lua代码加载它、然后创建了一张配置表,再从Lua读取配置表,设置UI的显示。

    玩玩热重载

    热重载Lua

    接着我们刚才运行的Game.unity。 我们尝试一下对Lua热重载:在不重启游戏的情况,快速重载Lua代码,方便程序调试。

    菜单KSFramework->UI->Reload+ReOpen:热重载Lua脚本,并重新打开目前处在打开状态的UI界面

    我们可以从菜单执行热重载并重新打开UI界面,或者使用快捷键Ctrl+Alt+Shift+R。
    由于我们的Lua脚本中,每次执行随机获取一条公告。因此可以看到公告内容在不停的变动着。

    热重载的实现,主要依赖于每个lua脚本的最后一行——return Table;C#层在执行完Lua脚本后,会把这个返回的Table缓存起来,每次需要使用table时,直接从缓存拿;而热重载,实际就是把这个缓存table删掉,这样当需要用到这个table时,就会重新执行Lua文件,来获取Table,这样就达到了热重载得目的。

    热重载Excel表格

    我们保持运行刚刚的Game.unity,不要停止掉。这时候我们去修改Excel表格。

    修改Excel表格

    保存后,回到Unity,提示表格有改动。

    发现表格有变动,点击OK编译表
    从菜单中心一下重载配置表格吧
    Ctrl+Alt+Shift+R刷新Lua

    重载Lua,我们的新修改的配置表内容生效了。

    至此,我们的Lua和配置表的改动,都可以在不重启、不重新转菊花的情况下快速修改。


    KEngine策划指南:配置表格的编辑与编译

    KEngine资源的打包、加载、调试监控





    展开全文
  • Unity3d入门(一)

    2019-09-13 22:18:01
    Unity3d作业一 ** 姓名:艾鹤轩 学号:17343001 1、简答题 1、解释游戏对象(GameObject)和资源(Asset)的区别和联系。 答:对象出现在游戏的场景中,是资源整合的具体表现; 资源可以被多个对象使用,有些可作为...

    **

    Unity3d作业一

    **

    1、简答题
    1、解释游戏对象(GameObject)和资源(Asset)的区别和联系。

    答:对象出现在游戏的场景中,是资源整合的具体表现;

    对象一般是指游戏中的某些元素,这些元素往往是游戏的主要个体,而资源则更多的讲究与游戏中的一些性质,它包含对象,是一个包含的关系。
    对象一般有玩家、敌人、环境、摄像机等非实体虚拟父类,但子类常为游戏内的实体。
    资源一般包含对象、材质、场景、声音、预设、贴图、脚本、动作等子文件夹,通常可进一步划分。
    

    2、

    • 下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
      首先我们进入资源商店之中下载free的游戏资源案例并导入,根据案例进行分析。
      在这里插入图片描述
      我们从项目中可以发现资源的根目录下,有Banckground、Chraacter、Chrarcter Animations、Ennmeies、Demo等16个文件夹和一个readme的txt文件;在这些文件夹中,我们可以找到这个游戏中的多个元素,例如,在enemies中我们可以看到游戏中的monster设计图像及其脚本,在一些文件夹中我们可以看到所有元素的动态的连续照片。在这些文件夹中分工明确。所以根据这些我们可以总结:资源是按照文件夹的形式来组织的,根目录一般是各种类型的资源目录以及说明文件,各资源目录下则是该类型的资源文件。游戏对象树由对象之间的父子关系构成的,父亲对象作为根节点,孩子对象作为子节点。

    • 编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件

    • 基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()常用事件包括 OnGUI() OnDisable() OnEnable()
      我们查询网上的官方指南:

    Awake() 在脚本实例被加载时即被调用
    Start() 仅在Update函数第一次被调用前调用
    Update() 每一帧触发一次
    FixedUpdate() 在自设定的帧频下,每一帧触发一次
    LateUpdate() 当Behaviour是enabled的情况下,在所有Update函数调用后被调用
    OnGUI() 当渲染和处理GUI事件时被调用
    OnDisable() 当行为变得无效的时候被调用
    OnEnable() 当对象启用并激活的时候被调用
    

    我们重新创建3D的cube对象,右击创建c#脚本。并使用visiualStdio2017编程

    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 OnGUI()
        {
            Debug.Log("OnGUI");
        }
        void OnDisable()
        {
            Debug.Log("OnDisable");
        }
        void OnEnable()
        {
            Debug.Log("OnEnable");
        }
    
    }
    

    运行过程如下图:
    在这里插入图片描述

    • 查找脚本手册,了解 GameObject,Transform,Component 对象

    • 分别翻译官方对三个对象的描述(Description)

    官方描述:

    GameObject:
    The GameObject is the most important concept in the Unity Editor.
    Every object in your game is a GameObject, from characters and collectible items to lights, cameras and special effects. However, a GameObject can’t do anything on its own; you need to give it properties before it can become a character, an environment, or a special effect.
    You can think of a GameObject as an empty cooking pot, and components as different ingredients that make up the recipe of your game.
    Transform:
    The Transform is used to store a GameObject’s position, rotation, scale and parenting state and is thus very important. A GameObject will always have a Transform component attached - it is not possible to remove a Transform or to create a GameObject without one.
    Components:
    Components are the nuts & bolts of objects and behaviors in a game. They are the functional pieces of every GameObject.
    A GameObject is a container for many different Components. By default, all GameObjects automatically have a Transform Component. This is because the Transform dictates where the GameObject is located, and how it is rotated and scaled. Without a Transform Component, the GameObject wouldn’t have a location in the world.
    Even empty GameObjects have a Transform Component
    Remember that you can always use the Inspector to see which Components are attached to the selected GameObject. As Components are added and removed, the Inspector will always show you which ones are currently attached. You will use the Inspector to change all the properties of any Component (including scripts).
    

    翻译:

    GameObject是Unity Editor中最重要的概念。
    游戏中的每个对象都是GameObject,从角色和收藏品到灯光,相机和特效。
     但是,GameObject本身无法做任何事情; 您需要先赋予它属性才能成为一个角色,一个环境或一个特殊的效果。
    您可以将GameObject视为一个空的烹饪锅,并将组件视为构成游戏配方的不同成分。
    
    Transform用于存储GameObject的位置,旋转,缩放和父亲状态,因此非常重要。 
    GameObject将始终附加一个Transform组件 - 
    无法删除该组件或创建没有该组件的GameObject。
    
    组件是游戏中对象和行为的基本要素。 它们是每个GameObject的功能部分。
    GameObject是许多不同组件的容器。 默认情况下,所有GameObjects都自动拥有一个Transform Component。 
    这是因为Transform指示了GameObject的位置,以及它是如何旋转和缩放的。 
    如果没有变换组件,GameObject将没有世界上的位置。
    即使是空的GameObject也有一个Transform Component
    请记住,您始终可以使用Inspector查看哪些组件附加到选定的GameObject。 
    随着组件的添加和删除,Inspector将始终显示当前连接的组件。 您将使用Inspector更改任何Component(包括脚本)的所有属性。
    
    • 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
      本题目要求是把可视化图形编程界面与 Unity API 对应起来,当你在 Inspector 面板上每一个内容,应该知道对应 API。
      例如:table 的对象是 GameObject,第一个选择框是 activeSelf 属性。
      在这里插入图片描述
    table对象的属性:activeInHierarchy(表示GameObject是否在场景中处于active状态)、activeSelf(GameObject的本地活动状态)、isStatic(仅编辑器API,指定游戏对象是否为静态)、layer(游戏对象所在的图层)、scene(游戏对象所属的场景)、tag(游戏对象的标签)、transform(游戏对象的转换,最常见的部件)
    table的Transform的属性:Position、Rotation、Scale
    table的部件有:Mesh Filter、Box Collider、Mesh Renderer
    

    在这里插入图片描述

    资源预设(Prefabs)与 对象克隆 (clone)
    预设(Prefabs)有什么好处?

    Unity的Prefab系统允许用户创建,配置和存储GameObject及其所有组件,属性值和子GameObjects作为可重用资源。预设资产充当模板,用户可以在该模板中在场景中创建新的预设实例。
    如果要重新使用以特定方式配置的GameObject(如非玩家角色(NPC),道具或场景 - 在场景中的多个位置或项目中的多个场景中),则应将其转换为预设。这比简单地复制和粘贴GameObject要好,因为Prefab系统允许用户自动保持所有副本同步。
    用户对Prefab资产所做的任何编辑都会自动反映在该预制件的实例中,使用户可以轻松地对整个项目进行广泛的更改,而无需对资产的每个副本重复进行相同的编辑。
    

    预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?

    预设和克隆的作用都是通过复制产生对象,区别是:预设的对象是统一的,“牵一发而动全身”;而克隆的对象是互不影响的,修改一个并不会影响到另一个。
    

    制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象

    void Start () {  
        GameObject anotherTable = (GameObject)Instantiate(table.gameObject);  
    } 
    void Update(){
    }
    
    

    2、 编程实践,小游戏

    游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
    技术限制: 仅允许使用 IMGUI 构建 UI
    作业目的:
    提升 debug 能力
    提升阅读 API 文档能力
    github 链接:github

    展开全文
  • Unity 编辑器常用基础 常用方法简介 物体操作 网络相关 网络协议 TCP UDP 代码怎么写 编译相关 学习资源推荐本文简介 本文旨在总结之前的博客,因为之前的博客比较零散,对于各个模块之间划分不够清晰,在此博客...

    本文简介

           本文旨在总结之前的博客,因为之前的博客比较零散,对于各个模块之间划分不够清晰,在此博客进行总结归纳,并且附上最新遇到的一些问题及解决办法,希望能够对自己和他人都能够有所帮助。另外在本文最后附加我浏览过的比较好的,相关问题解决的文章和网站,供大家方便查阅;如果您对我的文章满意,可以收藏或者关注我。

    常用方法简介

    1、Start() 开始方法;
    2、Update() 正常更新逻辑,每渲染一帧都会调用
    3、FixedUpdate() 不受帧率的变化,固定的时间间隔被调用,怎么设置间隔?Edit->Project Setting->time下面的Fixed timestep
    4、LateUpdate() 会在每一帧中被调用。在所有Update函数被调用之后才执行。有利于程序的有序执行。(例如:跟随摄像机就应该在LateUpdate执行,因为它跟随的对象也许需要在Update中执行
    5、OnGUI() 游戏界面绘制、更新
    6、OnCollisionEnter(Conllision other) 在刚体与刚体开始接触时候调用此方法,(记住是刚体之间的碰撞)
    7、OnCollisionStay(Conllision other) 在刚体与刚体碰撞的过程中,调用此方法 每帧都会调用此方法,知道碰撞结束;
    8、OnCollisionExit( Conllision other) 在刚体与刚体停止接触时,调用此方法
    9、OnTriggerEnter(Collider other) 当Collider(碰撞体)进入trigger(触发器)时调用,这个消息被发送到触发器碰撞体和刚体(或者碰撞体假设没有刚体)。注意如果碰撞体附加了一个刚体,也只发送触发器事件
    10、判断两个物体之间的距离 Vector3.Distance( position1,position2)

    物体操作

    实例化

    Transform  shoot = (Transform)Instantiate(shotPrefab,firePoint.gameObject.transform.position,
     firePoint.gameObject.transform.rotation);   
     shoot.rigidbody.velocity= transform.TransformDirection(Vector3.forward*100f);

    velocity是对物体设置某个方向的速度

    • 旋转
      Vector3.Rotation()        绕某个轴旋转 Quaternion.Angle()

    网络相关

           在这么一个多元化,网络越来越便宜和硬件性能越来越好的时代,单机游戏已经被很多早年出道的公司占据一席之地,并且单机游戏不能够有很好的社交性,至于你的应用联网了,才算一个真正的应用,那么在Unity中我们该怎么使用网络呢?

    网络协议

    TCP

    TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP)是同一层内[1] 另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。 详细简介还是问度娘或者查看相关书籍,建议书籍。

    UDP

    UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。 详细简介还是问度娘或者查看相关书籍,建议书籍。

    代码怎么写

    其实在unity中,我们用的就是Socket编程,和服务器创建连接,并维持心跳,通过协议进行通讯;代码和我们平时在C#中写的没什么差别,要记住,unity提供的是游戏渲染引擎,开发工具,并不是语言,我们用的是C#,C#的很多特性,我们都可以使用,当然切记要注意.net版本;unity中的版本是3.5 full 和3.5 sub;这个你可以在unity buildsetting中的othersetting中找到,基本上我们如果没有特殊需求,都会采用3.5sub。

    编译相关

    我们的游戏或者应用做好了,肯定要烧录到设备的,那么这就牵涉到我们打包部署这个环节,如何正确打包,针对不同的平台,我们的配置该如何呢?都有哪些差异呢?

    文件保存路径

    每个应用安装到设备,系统都会在硬盘给它分配相应的文件存储空间,但是在不同的平台,他们相对与系统的目录路径是不一致了,unity是个跨平台的开发工具,就需要针对不同的平台进行改变,为了方便,我们都会使用条件编译,如下:

            #if UNITY_ANDROID  
                the code of android  
            #endif  
            #if UNITY_IPHONE  
               the code of iphone  
                #endif  
            #if UNITY_WIN  
             the code of android  
            #endif  

    那么这些条件在哪里定义呢?首先你在VS的工程属性中可是设置,在unity中的buildsetting中也能够进行条件设定,代码中你也可以使用unity自带的平台个枚举,你可以通过代码提示枚举(RuntimePlatform)出来Application.platform==RuntimePlatform.Android判定运行游戏的设备是什么类型。

    学习资源推荐

    展开全文
  • 本文由D5Power首发于天地会,转载请标明原作者和出处。 周末听Sliz说Unity正式支持导出Flash了,作为一款成熟的游戏引擎,相信...对于Unity3D我也是刚刚研究,文中如有纰漏之处,望各位海涵。同时欢迎各位弟兄指正!
    本文由D5Power首发于天地会,转载请标明原作者和出处。

    周末听Sliz说Unity正式支持导出Flash了,作为一款成熟的游戏引擎,相信不少兄弟都对她很感兴趣。今天中午抽了点时间研究了一下,在这里做个笔记,算是本系列文章的一个开端。本文非100%原创,借鉴和参考了部分英文资料,在文中会有原版的连接。对于Unity3D我也是刚刚研究,文中如有纰漏之处,望各位海涵。同时欢迎各位弟兄指正!

    零 下载与安装

    官方网站 http://www.unity3d.com
    下载地址 http://unity3d.com/unity/download/
    安装好后,在开始界面里有视频介绍和文档介绍的连接。不再赘述。

    一 界面



    Unity3D的界面基本上如上图分布,来看一下各区域的功能。

    红色:工具栏,可以通过工具栏来设置当前的鼠标功能(缩放,移动等等),进入或退出游戏运行状态
    橙色:视图,即编辑/游戏演示窗口
    绿色:对象列表,本窗口列举了游戏中的全部游戏对象(摄像机,灯光等等)
    蓝色:游戏素材窗口,包括脚本,贴图,模型等等
    紫色:属性区

    小技巧:选中某对象(不管是在绿色的列表区,还是在橙色的视图区)后,把鼠标移到橙色的视图区,按下F则视图自动对准该对象


    二 创建游戏对象

    和我们使用FB开发一样,在开始Unity开发之前,必须要创建一个新的项目(File->New Project)。
    之后,就可以进行操作了。我们来创建一个平面(Plane),一个方盒子(Cube)和一个追光(Spotlight)

    创建平面:GameObject->Create Other->Plane
    创建方盒子:GameObject->Create Other -> Cube
    创建追光:GameObject->Create Other->Spotlight

    如果你创建完成后,并没有看到他们,可以在列表中选择某对象,然后把鼠标移动到橙色视图区,按下F。如果你看到你的对象是线条,类似下面这样:



    说明你的对象被遮挡住了,调整他们的位置到合适就可以了。如何调整位置?可以试用工具栏的第2个功能按钮(移动)



    选择该功能后,在列表区(绿色)或视图区(橙色)选择游戏对象,均可看到3方向的箭头,拖动对应方向的箭头即可完整在该方向上的移动操作。

    试着把聚光灯方在方盒子的上方,并旋转聚光灯让他对准盒子吧。类似下面这样



    最后,我们希望摄像机的视野,和我们现在视图区的一致。在列表区(绿色)中选择摄像机(MainCamera),然后选择菜单GameObject->Align With View,可以发现,摄像机的预览视图中,变成了和我们现在的视图区一样的内容,当然,尺寸小点-.-



    三 编程,追光跟随的,由键盘控制的盒子

    在Unity中,我们试用Javascript进行程序编写,语法和AS差不多。我们先实现简单的功能,让键盘可以控制盒子移动(D5的惯例。。。哈哈),然后,让追光一直跟着盒子。

    首先,我们要新建一个脚本。Asset->Create->Scrpit。这个时候,Unity自带的脚本编辑器会自动打开(MonoDevelop),我们可以看到,已经自动帮我们生成了Update函数,这个和AS的Event.ENTER_FRAME是同个概念的,即每帧都会运行。然后,我们输入以下代码:
    1. var speed = 5.0;

    2. function Update () {
    3.         var xspeed = Input.GetAxis("Horizontal")*Time.deltaTime*speed;
    4.         var yspeed = Input.GetAxis("Vertical")*Time.deltaTime*speed;
    5.         transform.Translate(xspeed,0,yspeed);
    6. }
    复制代码
    speed是移动速度
    Input.GetAxis("Horizontal")和InputGetAxis("Vertical")分辨是当前键盘的状态。如果按下A和D,则Horizontal返回1或-1,W和S则Vertical返回1或-1,否则都返回0。
    Time.deltaTime 记录了渲染最后一帧所消耗的秒数。我们根据这个来进行位移(这里我也没太明白,还在研究,我比较容易接受.x+=speed...)

    脚本写完了,接下来就需要把这个脚本绑定到某一个游戏对象上,我们想控制盒子,自然要绑到盒子上。选择盒子,然后在菜单中选择Component-->Script,选择刚才的Scrpit文件。可以看到属性栏里,绑定成功。



    现在测试一下游戏,可以发现,方盒子已经受到键盘的控制了。下面,我们要让灯光一直照向盒子,先看代码:
    1. var target:Transform;
    2. function Update () {
    3.         transform.LookAt(target);
    4. }
    复制代码
    这里我们定义了一个target,后面再解释如何用,和刚才对盒子的操作一样,我们把这个脚本绑定到聚光灯上。



    刚绑定的时候可以发现,target的值是None,因为我们还没有指定哪个对象作为target,点击None右边的箭靶一样的图标,会出现选择窗,在列表中选择Cube,target的值就被指定了。接下来,测试你的第一个“游戏”吧。

    总结

    相对于A3D,AWAY3D来讲,UNITY3D提供了完善的游戏开发环境。对于Flasher来讲,Javascript脚本也不会让我们过于陌生。如果Unity可以完美的导出到FP11的话,相信还是灰常强大的。本笔记不定期更新:)附件中有本次项目的源码

    展开全文
  • 注:本系列版本为Unity 5.3.5. 新建项目与新建场景 新建项目 每一个游戏都是一个独立的项目。 打开 Unity,输入项目名称 --&gt; 选择本地存储位置 --&gt; 选择 3D模式 --&gt; 点击“Creat ...
  • 最近对Unity3d进行学习的过程中,发现unity不仅入门教程做的丰富,而且Script API文档也是看过的所有API文档中最清晰易用的。不得不说,这极大降低了入门unity3d的门槛。 Unity3d入门学习资料   Unity3d的学习...
  • 由于毕业论文的关系,需要使用Unity3D开发,做虚拟现实的应用,使用的设备是HTC vive pro产品。初始学习,由于没有基础,因此一团乱,总结一下目前看过的教程和书籍。1、开始看的是b站上极客学院讲解的unity3d的入门...
  • Unity3D如何快速入门

    2018-11-29 12:47:08
    目录Unity3D游戏引擎介绍Unity3D学习历程Unity3D快速入门途径 Unity3D游戏引擎介绍 Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的...
  • 因此,有很多人选择自学unity3d加入到这个行业中来。 大家在进行选择的时候,一定要看是老师教得细心不细心。这里面有一个行业常识,业内为了保证教学质量,每个机构的课程都是有一帮大牛研发的,教课的老师也是按照...
  • Unity3D是一个跨平台的游戏开发引擎,它能够帮助开发者快速构建游戏场景,进行游戏开发与发布。它支持将开发好的作品发布到Windows、Mac OS、Android、iOS、Linux等多种平台。另外,Unity3D官方版本目前可以运行在...
  • 本书是国内第一本以面向对象和项目流程开发角度,全面系统介绍 Unity3D 的书籍。 本书以具体项目结构开发的角度,结合 Unity3D 层级式的综合开发环境、视觉化编辑、详 细的属性编辑器和动态的游戏预览的特点,在软件...
  • 2018年什么游戏最火? 不用问,肯定是人人都在撸的“王者荣耀”和吃鸡游戏了。...Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综...
  • 每周更新unity3d视频教程,从入门到就业,官方unity3d培训,上千门实时更新课程,供学员在线观看学习,unity3d游戏开发,可以让学员随时随地学习! 免费网上学习unity3d自学教程,国内名师机构专业授课,O基础快速学习,1小时...
  • 本书是国内第一本以面向对象和项目流程开发角度,全面系统介绍Unity3D的书籍
  • MAC中开发Unity3D

    2016-03-23 16:21:29
    一直想做3D开发,去年后半年...用Unity3D开发了游戏也不能上传AppStore,除非工作上用,不然个人开发代价有点大。 后来听说Unity3D基础版免费了,而且可以上传到AppStore,于是又想学了。 找了好几次了,怎么就是找
  • Unity3D 最经典 2 by 3 结构界面,上面呈现了 Unity3D 最为常用的几个面板,下面为各个面板的详细说明。 1.Scene【场景面板】:该面板为 Unity3D 的编辑面板;你可以将你所有的模型、灯光、以及其他材质对象拖放到...
  • Unity3D 中文快速入门教程 Unity 3D V3.0 Unity3D 中文快速入门教程
  • 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发Unity3D使用者,因为我本身自己也是Shader初学者,因此可能会存在错误或者疏漏,如果您在Shader开发上有所心得,很欢迎并恳请您指出...
  • unity3D是如今绝大多数游戏开发...有的网友说unity3d开发的游戏,多数都是用在iphone以及android等手机端游戏。比较出名的是武士系列游戏,涂鸦保龄球,城堡勇士,3D方块贴图,以及很多僵尸游戏。还有网友说:unity...
1 2 3 4 5 ... 20
收藏数 4,915
精华内容 1,966
关键字:

unity3d 开发入门