Unity3D简单入门

关于我学习Unity时遇到的知识

  1. AR入门
  2. 如何实现一个简单的拼图游戏
  3. 开发过程中遇到的一些问题

AR入门

1、Vuforia环境搭建

博主的AR游戏是使用Vuforia做的,Vuforia组件在你安装Unity时应该是可选的,如果忘记选了,那就去Vuforia的网站上下载就可以了。
Unity3D简单入门_第1张图片
选第二个安装就可以了。

2、新建一个Unity项目

Unity3D简单入门_第2张图片
Template记得选3D就可以了。

3、做一些基本配置
  • 按图中的步骤。因为我要开发的是手机上的AR游戏所以要更换平台到Android。把画横线的那个选项勾上。
    Unity3D简单入门_第3张图片
    Unity3D简单入门_第4张图片
  • 然后建一个ARcamera
    Unity3D简单入门_第5张图片
  • 进行一些配置
    Unity3D简单入门_第6张图片
  • 点击Add License,会跳转到Vuforia的官网,需要你申请一个钥匙,这个是必不可少的,每个项目都有自己的钥匙,你可以把它当成唯一标识。
    Unity3D简单入门_第7张图片
    Unity3D简单入门_第8张图片
    Unity3D简单入门_第9张图片
  • 里面就有钥匙了,复制之后粘贴到框里面就可以了。
4、建识别物数据库
  • 接下来我们要在Vuforia官网建立一个识别物数据库,这个数据库的作用就是我们AR游戏的核心了。
    Unity3D简单入门_第10张图片
    Unity3D简单入门_第11张图片
  • 添加你要AR识别的照片即可,这里我们用纸牌梅花K来做识别物。
    Unity3D简单入门_第12张图片
    4.4
  • Rating的意思就是被识别的图片的等级,最好都是五星级别,那意味着你的图片更容易被识别。
    Unity3D简单入门_第13张图片
  • 选中这个数据库,然后下载下来,双击打开它,导入到Unity的项目当中去。可以看到AR camera的databases属性发生变化,证明已经导入成功。
    Unity3D简单入门_第14张图片
5、第一次识别
  • 建一个Image
    Unity3D简单入门_第15张图片
  • 这个地方可以更换识别物。Unity3D简单入门_第16张图片
  • 在Image上面建一个立方体。
    Unity3D简单入门_第17张图片
  • 调整一下方块的大小,方向和位置
    Unity3D简单入门_第18张图片
  • 因为是要开发手机AR游戏,所以调整一下预览。根据自己的手机大小选择。
    Unity3D简单入门_第19张图片
  • 然后点击运行,看一下效果。成功!
    Unity3D简单入门_第20张图片
6、第一个按钮脚本

Unity3D简单入门_第21张图片

  • 先建一个文件夹专门存放脚本,然后create一个C#脚本,命名为Btn_Cube。Unity3D简单入门_第22张图片
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Btn_Cube : MonoBehaviour
{
    public GameObject btn;//定义物体变量 btn
    public GameObject cube;//定义物体变量 cube
    // Start is called before the first frame update
    void Start()
    {
        Button btn_cube = btn.GetComponent<Button>();//获取Button组件
        btn_cube.onClick.AddListener(btnClick);//点击事件
    }

    void btnClick(){
        cube.SetActive(false); //隐藏物体cube
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
  • 这个脚本作用就是,当我们点击这个按钮之后,使得方块Cube消失。
    Unity3D简单入门_第23张图片
  • 将脚本拖拽到Cube的属性里面,然后就会出现Btn和Cube两个物体变量,再把Cube方块拖拽到Cube物体变量,把Button拖拽到Btn变量上即可。
  • 运行测试一下即可发现方块Cube上会多出来一个按钮,点击即可触发方块消失事件。
  • 这只是其中一种方法来实现点击事件,更多的方法可以自行上网查询。
7、Unity中常用的API和变量类型

博主只是提一下自己在开发的时候遇到的感觉有用的知识,具体用法需要读者自行百度搜索。下面我以挂载在方块Cube下的脚本Btn_Cube为例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Btn_Cube : MonoBehaviour
{
    public GameObject btn;
    public GameObject cube;
    // Start is called before the first frame update
    void Start()
    {
        // API:GameObject.GetComponent<脚本>()。常用于获取UI组件信息并进行操作,Componet就是右侧栏里面所有的脚本
        Button btn_cube = btn.GetComponent<Button>();
        // API:Button.onClick.AddListener(点击事件)。按钮点击事件
        btn_cube.onClick.AddListener(btnClick);
        // Transform和GameObject是Unity中比较重要的两个变量类型,两者可以相互转换
        Transform t = cube.transform;
        GameObject obj = t.gameObject;
        // API:Transform.Find("")即寻找该物体下的子物体,这时可以不用拖拽物体到GameObject变量上,还有其他常用的其他方法,自行百度
        Transform t_child = t.Find("");
        // API:GameObject.SetActive()控制物体显示隐藏的方法
        obj.SetActive(false);
        // API:GameObject.activeInHierarchy判断物体是否隐藏的方法
        if(obj.activeInHierarchy){

        }
        // API:触摸点击事件,射线法,具体自行百度
        if(Input.GetMouseButtonDown(0)){
            RaycastHit hit;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit))
            {
                // touchCount:手指数量。
                // Input.GetTouch(0).phase:触碰状态。
                // TouchPhase.Began:刚触碰时
                if(Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began){
                    // 射线碰撞到的碰撞体所在的物体
                    GameObject hitobj = hit.collider.gameObject;
                }
            }
        }
        
    }

    void btnClick(){
        cube.SetActive(false);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

如何实现一个简单的拼图游戏

用Unity实现一个简单的拼图游戏,博主也是学习了别人的博客,在这里分享一下:https://gameinstitute.qq.com/community/detail/124936。

1、先导入一张图片并修改

Unity3D简单入门_第24张图片

2、建一个UI的Raw Image来当背景
  • 注意修改背景的大小跟图片适配
    Unity3D简单入门_第25张图片
  • 添加Grid Layout Group脚本,注意每一个格子的大小也要适配
    Unity3D简单入门_第26张图片
    Unity3D简单入门_第27张图片
3、建格子
  • 先建一个空物体,命名为Cell,再在它的下面建一个UI的Image,调整Image的大小,与Grid Layout Group里面的Cell一样大,并新建一个Tag名为Cell,修改它的Tag为Cell。
    Unity3D简单入门_第28张图片
    Unity3D简单入门_第29张图片
  • 新建一个文件夹存放Prefab,拖拽Cell到该文件夹中即可
    Unity3D简单入门_第30张图片
4、挂载脚本

新建三个脚本,分别为GameManager、ImageCreater、DragOnPic,ImageCreater挂在Raw Image上,DragOnPic挂载Cell中的Image上
Unity3D简单入门_第31张图片

using UnityEngine;
public class GameManager
{
	
	static public void RandomArray(Sprite[] sprites)
	{
		for (int i = 0; i < sprites.Length; i++)
		{
			//随机抽取数字中的一个位置,并将这张图片与第i张图片交换.
			int index = Random.Range(i, sprites.Length);
			Sprite temp = sprites[i];
			sprites[i] = sprites[index];
			sprites[index] = temp;
		}
	}
	/// 
	/// Sets the parent.
	/// 
	static public void SetParent(Transform mine, Transform target, Transform oldParent)
	{
		//如果检测到图片,则交换父物体并重置位置.
		switch (target.tag)
		{
			case "Cell":
				mine.SetParent(target.parent);
				target.SetParent(oldParent);
				mine.localPosition = Vector3.zero;
				target.localPosition = Vector3.zero;
				break;
			default:
				mine.SetParent(oldParent);
				mine.localPosition = Vector3.zero;
				break;
		}
	}
	/// 
	/// Checks is win.
	/// 
	static public bool CheckWin()
	{
		for (int i = 0; i < ImageCreater._instance.transform.childCount; i++)
		{
			if (ImageCreater._instance.transform.GetChild(i).name != ImageCreater._instance.transform.GetChild(i).transform.GetChild(0).name)
			{
				return false;
			}
		}
		return true;
	}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ImageCreater : MonoBehaviour
{
	public static ImageCreater _instance;
	//存储裁剪好图片的数组.
	public Sprite[] sprites;
	//格子的预设体.
	public GameObject cellPrefab;
    // Start is called before the first frame update
    void Start()
    {
		_instance = this;
		CreateImages();        
    }
    private void CreateImages()
	{
		//将图片数组随机排列.
		GameManager.RandomArray(sprites);
		//生产图片.
		for (int i = 0; i < sprites.Length; i++)
		{
			//通过预设体生成图片.
			GameObject cell = (GameObject)Instantiate(cellPrefab);
			//设置cell的名字方便检测是否完成拼图.
			cell.name = i.ToString();
			//获取cell的子物体.
			Transform image = cell.transform.GetChild(0);
			//设置显示的图片.
			image.GetComponent<Image>().sprite = sprites[i];
			//设置子物体的名称,方便检测是否完成拼图.
			int tempIndex = sprites[i].name.LastIndexOf('_');
			image.name = sprites[i].name.Substring(tempIndex + 1);
			//将Cell设置为Panel的子物体.
			cell.transform.SetParent(this.transform);
			//初始化大小.
			cell.transform.localScale = Vector3.one;
		}
	}

    // Update is called once per frame
    void Update()
    {
        
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class DragOnPic : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    //记录下自己的父物体.
	Transform myParent;
	//Panel,使拖拽是显示在最上方.
	Transform tempParent;
	CanvasGroup cg;
	RectTransform rt;
	//记录鼠标位置.
	Vector3 newPosition;
    void Awake()
	{
		//添加CanvasGroup组件用于在拖拽是忽略自己,从而检测到被交换的图片.
		cg = this.gameObject.AddComponent<CanvasGroup>();
		rt = this.GetComponent<RectTransform>();
		tempParent = GameObject.Find("Canvas").transform;
    }

    public void OnBeginDrag(PointerEventData eventData)
	{
		//拖拽开始时记下自己的父物体.
		myParent = transform.parent;
		//拖拽开始时禁用检测.
		cg.blocksRaycasts = false;
		this.transform.SetParent(tempParent);
	}

    void IDragHandler.OnDrag(PointerEventData eventData)
	{
		//推拽是图片跟随鼠标移动.
		RectTransformUtility.ScreenPointToWorldPointInRectangle(rt, Input.mousePosition, eventData.enterEventCamera, out newPosition);
		transform.position = newPosition;
	}
    public void OnEndDrag(PointerEventData eventData)
	{
		//获取鼠标下面的物体.
		GameObject target = eventData.pointerEnter;
		//如果能检测到物体.
		if (target)
		{
			GameManager.SetParent(this.transform, target.transform, myParent);
		}
		else
		{
			this.transform.SetParent(myParent);
			this.transform.localPosition = Vector3.zero;
		}
		//拖拽结束时启用检测.
		cg.blocksRaycasts = true;
		//检测是否完成拼图.
		if (GameManager.CheckWin())
		{
			Debug.Log("Win!!!");
		}
	}
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

5、建一个Prefab
  • 新建一个Prefabs文件存放Prefab,将Cell拖拽到该文件夹中,注意要把脚本挂载上之后再拖拽
    Unity3D简单入门_第32张图片
  • 然后将上面的Cell隐藏,将Prefabs中的Cell拖拽到脚本ImageCreater中去。
    Unity3D简单入门_第33张图片
    Unity3D简单入门_第34张图片
  • 运行!
    Unity3D简单入门_第35张图片

开发过程中遇到的一些问题

1、遇到的一个错误

Copying assembly from ‘Temp/Unity.TextMeshPro.dll’ to 'Library/ScriptAssembl
翻译过来就是某东西无法复制,百度了一下最终解决了,博主是因为电脑管家的拦截才报这个错误的,把电脑管家关了之后重启一下项目就可以了。

2、Unity 使用VS code作代码编辑器

用自己习惯的工具来写代码更加方便一点,而且装好插件的话会有代码提示,大大提高了写代码的效率,十分推荐大家使用。
Unity3D简单入门_第36张图片
博主自己是使用VScode,还需要装两个插件,分别是C#和Debugger for Unity。
Unity3D简单入门_第37张图片
Unity3D简单入门_第38张图片
理论上讲,这两个插件就可以实现代码补全功能,但实际上博主还是无法实现vscode对Unity的代码补全功能,最后捣鼓了一下,成功解决了问题。
当时VScode控制台会有错误提示(没有把图截下来),其实按照控制台的提示去把需要的东西下载下来就可以了。
博主遇到的情况是这样的:
Unity3D简单入门_第39张图片
随便点开项目文件夹画红线的三个文件之一,可以看到v4.7.1但是控制台提示我并没有找到这个版本,那么就把对应版本的下载下来就可以了。
Unity3D简单入门_第40张图片
4.7.1版本的下载地址是:https://dotnet.microsoft.com/download/dotnet-framework/net471。安装完之后重启VScode就可以了。

3、Unity动态修改Image图片
  • 第一种方式是:Image.overrideSprite =
    void Start()
    {
        GameObject obj;
        Transform t = obj.transform.Find("");
		Image image = t.GetComponent<Image>();
		//Resources.Load表示路径位于Resources,即后面填写的路径path要在文件夹Resources里面的
		//输出获取到的图片资源的名字
		Debug.Log("1:" + image.sprite.name);
		image.overrideSprite = Resources.Load("path",typeof(Sprite))as Sprite;
		Debug.Log("2" + image.sprite.name);
		Sprite s = Resources.Load<Sprite>("");
		image.sprite = s;
    }

overrideSprite是临时的修改图片,意思是不会真正将图片更换,而是覆盖另一张图片在其上。对比两次输出即可发现图片资源没有被更换

  • 另一种方法是:Image.sprite =
    void Start()
    {
        GameObject obj;
        Transform t = obj.transform.Find("");
		Image image = t.GetComponent<Image>();
		//输出获取到的图片资源的名字
		Debug.Log("1:" + image.sprite.name);
		Sprite s = Resources.Load<Sprite>("path");
		image.sprite = s;
		Debug.Log("2" + image.sprite.name);
    }

这一种方式则是会真正替换掉原来的图片,假如你需要对图片替换前后进行判断的话,就需要选择这种方式来替换图片。

  • 注意图片格式要修改成Sprite。

附加

  • 博主学Unity是因为在学校报了个AR游戏的项目,然后在开发的过程中感觉蛮有趣的,也算是把Unity从零基础入门了吧,因此写篇博客来记录一下。然后Unity的3D素材很不好找,我是在爱给网上面找的素材,免费的素材每天只能下载一两个。

你可能感兴趣的:(学习,unity3d,c#,android)