进行Unity3D游戏引擎开发遇到的坑(part 1)

2,972 阅读8分钟

代码无法自动补全

要在unity里设置

打开unity3D --> Edit --> Preferences

然后选择External Tools 在External Script Editor下拉列表中找到Visual Studio 2019(这里我是装的VS2019,所以是这个,看个人的版本不同)

如果你在这个下拉列表里没有找到Visual Studio 20XX这个选择项,你就选择Browse 然后找到你VS的安装目录,把VS里的exe启动文件选中,也就是那个名叫devenv的文件

选中之后你再通过unity3D里双击c#文件打开VS 就有智能提示了

GUI 系列的组件无法正常显示

目前Unity高版本已不再支持GUI Texture、GUI Text系列组件

建议不要再用GUI系列的组件了,2017版本已失效

建议用UGUI,在层级视图,右键创建UI栏目下的所需内容,其具备GUI的所有功能

步骤为

  1. 创建UI
  2. 写脚本,注意要引入using UnityEngine.UI
  3. 挂载脚本
  4. 注意:图片要为sprite格式的

transform的position和localPosition属性的区别

position是世界坐标中的位置,可以理解为绝对坐标

localPosition是相对于父对象的位置,是相对坐标,我们在transform栏看到的是相对坐标

如果对象是一级对象,position和localPosition是相同的

transform的position.y不能单独修改,要用向量修改

众所周知,transform.position.x/y/z不可以单独修改,需要通过Vector3对整个position进行修改

一种说法(不靠谱)

position.x 只有get函数没有set函数,所以不可以对它单独修改

另一种说法(靠谱)

定位到Transform类中,position是一个Vector3类型的属性,而Vector3是一个结构体,所以position是一个结构体,结构体是一个值类型,值类型在方法传递的时只传递值的副本

transform.position.x = 1时调用属性的Get方法得到position,但是这个position只是一个副本,对这个副本做的任何修改都对原position无影响,显然这样做是没有意义的,所以编译器禁止你做这样的操作

精准移动物体

一直按住V,开启顶点吸附模型,先选择物体的顶点,然后用鼠标拖拽物体到理想的物体表明,两者会精确贴合的

给平面/地形贴图,设置密度

点击材质

检视面板设置Tiling,这就是平面上要显示多少张图片

报错,场景中有两个Audio Listener

There are 2 audio listeners in the scene. Please ensure there is always exactly one audio listener in the scene.

说明场景中有两个摄像机,且摄像机上都挂载了Audio Listener组件,相当于有两只耳朵,系统无法确定将音频声音传递给谁,所以需要将一个摄像机的Audio Listener取消勾选

提高摄像机贴图的清晰度

点击Render Texture,修改Size属性,越大越清晰,但也更耗资源

让游戏物体或组件无效化

让游戏物体无效化:.setActive(false) 有效化即为true

让组件无效化:.enabled = false

更改鼠标样式

public Texture2D cursorTexture;

Cursor.SetCursor(cursorTexture, Vector2.zero, CursorMode.Auto);
材质、渲染区域、渲染形式

注意:

  • 材质就是图片,不过要把图片的渲染模型改为Cursor
  • 渲染区域就是指针所在图片的位置,比如说你的texture是100*100的,你希望用中点来操作,那么这个vector2的值是50,50;而不是0.5,0.5。它是实际值,而不是比例
  • 渲染形式一般都设为平台自适应显示

实在找不到如何在检视面板查看图片像素大小,只能通过代码输出

Debug.Log(cursorTexture.width);
Debug.Log(cursorTexture.height);

添加天空盒

在主摄像机设置Clear Flags为天空盒,并为主摄像机添加组件Skybox,点击右侧齿轮选择天空盒

通过设置刚体的velocity和angularVelocity,移动和旋转很慢

可能是碰撞器与地面重合了,将碰撞体稍微移除地面即可

Input.GetAxis()与Input.GetAxisRaw()的区别

Input.GetAxisRaw() 当在游戏运行的时候,按下你设置好的键盘就会返回 1和-1这两个值

Input.GetAxis() 当按下你设置的建则会返回一个类似加速度的值 0.1-->0.3 -->0.1然后将会依次减少..类似刹车和开车.适用于赛车加速

让物体朝向鼠标方向

Vector3 mouseXInput = Input.mousePosition;
mouseXInput = Camera.main.ScreenToWorldPoint(mouseXInput);
transform.LookAt(new Vector3(mouseXInput.x, transform.position.y, mouseXInput.z));

旋转的几种方式

1.简单

transform.rotation = transform.rotation * Quaternion.Euler(0, rotateInput * rotationSpeed * Time.deltaTime, 0);

2.精确

void Update () {
    // 鼠标和按键同时控制
	float mousex = Input.GetAxisRaw("Rotation") == 0 ? Input.GetAxisRaw("Mouse X") : Input.GetAxisRaw("Rotation");
	angle += mousex * rotationSpeed;
	angle = angle < -360 ? angle += 360 : angle;
	angle = angle > 360 ? angle -= 360 : angle;
	angle = Mathf.Clamp(angle, -360, 360);
}

void LateUpdate()
{
        // 水平旋转量
	Quaternion xQuat = Quaternion.AngleAxis(angle, Vector3.up); // 可以改为本地坐标系
	// 垂直旋转量
	Quaternion yQuat = Quaternion.AngleAxis(0, Vector3.left);
	transform.rotation = xQuat * yQuat;
}
  1. 旋转朝向某个物体的方向
void Rotate()
	{
		float angle = Vector3.Angle(transform.forward, player.position - transform.position);
		if (angle <= 1) return;
		Vector3 cross = Vector3.Cross(transform.forward, player.position - transform.position);
		if (cross.y > 0)
		{
			transform.Rotate(new Vector3(0, 100f*Time.deltaTime, 0));
		}
		else
		{
			transform.Rotate(new Vector3(0, -100f * Time.deltaTime, 0));
		}
	}

查找游戏物体

todo

各坐标空间的变换

todo

Unity类型转换 as

GameObject go1 = Instantiate(perfab, Position, Quaternion.identity) as GameObject; 
GameObject go2 = (GameObject)Instantiate(perfab, Position, Quaternion.identity); 

为什么需要转换:

通常我们不加转换语句就会报错是因为Instantiate实例化出的对象是Object类型,需要强制转换成GameObject

两者区别

1.用括号强制类型转换:转换不成功会抛出异常,对引用类型和值类型都适用。

2.as运算符:转换不成功得到一个null值,不会抛出异常;仅适用于引用类型,不能用于值类型。

总结一句:强制类型转换比较暴力,as比较温和.我一般用as(减少因转换失败而报错)

粒子爆炸效果很奇怪

如果是自己做的,那很正常

如果是导入的资源,可能是爆炸所需材质没有一起导入

删除物体与预制体之间的联系

选中游戏物体,点击主菜单下的GameObject>Break Prefab Instance,可以看到物体名称由蓝色变为白色,但此时其并未完全与预制体断开联系,检视面板上还有select、revert、applay三个按钮,再次将游戏物体制作为预制体,再把预制体给删了,可以看到物体名称变为红色,此时再选中物体,点击主菜单下的GameObject>Break Prefab Instance就OK了

修改刚体重力

1. 修改所有物体重力: Edit>Project settings>physics

2. 修改单个物体重力

加组件Constant Force,设置y方向的力,负值为向下

写脚本

p_Rigidbody.AddForce (0, 1, 0);

UI大小自适应屏幕

todo

运行状态下,进入场景没有光照

点击 菜单栏>Windows>Lighting>Settings,取消自动渲染,再点击右侧按钮,会发现在场景文件夹下新生成了保存场景光照信息的文件夹

代码修改颜色的透明度

切记,color是一个整体,不能单独修改其中的某一个值

this.GetComponent<Text>().color = new Color(this.GetComponent<Text>().color.r, this.GetComponent<Text>().color.g, this.GetComponent<Text>().color.b, newa);

UGUI的按钮点击无效果

幕布上顺序问题,将按钮拖到幕布的最后即可,或者控制其他UI的大小,不要相互遮挡

还有可能是没有Event System,你的幕布不是新建的是复制过来的

旋转模型后发现Z轴方向没变

将世界坐标系切换为局部坐标系,写代码是也要注意 局部与世界坐标系的方向

防止刚体旋转

根据情况锁定,如果对物体的控制没有用到刚体(如用自动寻路组件),全部锁上也可以

暂停功能

  1. 慎用
Time.timeScale = 0;
  1. 给脚本设个标志位,Update函数最开始就判断,否则返回,不过这种方法比较麻烦

UI元素大小屏幕自适应

很简单,选择画布,在检视面板将UI Scale Mode设置为Scale With Screen Size,再设置Match为0.5,(为0表示只有宽度自适应,1为只有高度自适应,0.5表示综合)

给VS添加mysql的引用

菜单栏>>项目>>添加引用>>浏览电脑上的“MySql.Data.dll”>>勾选前面的方括号(我就是没勾,坑了许久)

枚举类型在面板上显示

public enum AlgorithmSelect
    {
        AstartAlgorithm,
        GreedyAlgorithm
    }

public AlgorithmSelect algorithmSelect;

更进阶的东东

在点击UGUI元素时不触发射线检测

using UnityEngine.EventSystems;

// 碰到UI元素就不发射射线
if (EventSystem.current.IsPointerOverGameObject() || EventSystem.current.currentSelectedGameObject != null)
	return;

参考资料:Unity点击UI时不触发场景物体的响应

组件寻路若速度过大会跑偏

暂时无法通过对面板上数值的修改来修正

曲线救国:设置完毕目标位置后停止寻路

物体被激活后没有调用Start方法

加一个生命周期函数

void OnEnable()
{
    Awake();
    Start();
}

判断两物体间有没有障碍物阻挡

// 判断两物体间是否有障碍物
private void Judge()
{
	if(!Physics.Linecast(new Vector3(transform.position.x,0.5f,transform.position.z), new Vector3(player.position.x,0.5f,player.position.z)))
	{
		Debug.Log("没有阻挡");
	}
}

更进一步,判断是否有具体层级的障碍物

对于一个函数有多重循环问题

如果有多重循环,最内层循环直接return,貌似不会直接跳出函数,会死循环,还是要层层循环break一下