一.引言
游戏制作除了场景搭建,还有处理与玩家的交互,下面就主要整理和玩家交互相关的API,让游戏活起来
二.Input输入监测
Input提供了很多和输入相关的API,只要是输入监测,就一定会写在Update函数中,每帧进行监测
- 鼠标在屏幕位置
屏幕坐标的原点是在屏幕的左下角,往右是X轴正方向,往上是Y轴正方向
使用下面的API进行操作,返回值是Vector3,但是只有 x和y 有值,z一直是0,是因为屏幕本来就是2D的,不存在Z轴Input.mousePosition - 检测鼠标输入
鼠标按下相关检测,对于我们来说:
1.可以做 发射子弹
2.可以控制摄像机转动//鼠标按下一瞬间 进入 //0左键 1右键 2中键 //只要按下的这一瞬间 进入一次 if( Input.GetMouseButtonDown(0) ) { print("鼠标左键按下了"); } //鼠标抬起一瞬间 进入 if( Input.GetMouseButtonUp(0) ) { print("鼠标左键抬起了"); } //鼠标长按按下抬起都会进入 //就是 当按住按键不放时 会一直进入 这个判断 if( Input.GetMouseButton(1)) { print("右键按下"); } //中键滚动 //返回值的 y -1往下滚 0没有滚 1往上滚 //它的返回值 是Vector的值 我们鼠标中键滚动 会改变其中的Y值 print(Input.mouseScrollDelta); - 检测键盘输入
比如说按一个键释放一个技能或者切换武器等等的操作键盘输入的检测,建议使用枚举,字符串只支持小写,以防写错//键盘按下 if( Input.GetKeyDown(KeyCode.W) ) { print("W键按下"); } //传入字符串的重载 //这里传入的 字符串 不能是大写的 不然会报错 //只能传入小写字符串 if( Input.GetKeyDown("q") ) { print("q按下"); } //键盘抬起 if( Input.GetKeyUp(KeyCode.W) ) { print("W键抬起"); } //键盘长按 if( Input.GetKey(KeyCode.W) ) { print("W键长按"); } - 检测默认轴输入
学习鼠标、键盘输入主要是用来控制玩家,比如旋转、位移等等,而Unity提供了更便捷的方法用来控制对象的位移和旋转//键盘AD按下时 返回 -1到1之间的变换 //相当于 得到得这个值 就是我们的 左右方向 我们可以通过它来控制 对象左右移动 或者左右旋转 float h = Input.GetAxis("Horizontal"); //print(h); //键盘SW按下时 返回 -1到1之间的变换 //得到得这个值 就是我们的 上下方向 我们可以通过它来控制 对象上下移动 或者上下旋转 //print(Input.GetAxis("Vertical")); //鼠标横向移动时 -1 到 1 左 右 //print(Input.GetAxis("Mouse X")); //鼠标竖向移动时 -1 到 1 下 上 //print(Input.GetAxis("Mouse Y")); //我们默认的 GetAxis方法 是有渐变的 会总 -1~0~1之间 渐变 会出现小数 //GetAxisRaw方法 和 GetAxis使用方式相同 //只不过 它的返回值 只会是 -1 0 1 不会有中间值 - 其余检测,比如手机端的触控,暂时仅做了解
//是否有任意键或鼠标长按 if(Input.anyKey) { print("有一个键长按"); } //是否有任意键或鼠标按下 if(Input.anyKeyDown) { print("有一个键 按下"); //这一帧的键盘输入 print(Input.inputString); } //手柄输入相关 //得到连接的手柄的所有按钮名字 string[] strs = Input.GetJoystickNames(); //某一个手柄键按下 if( Input.GetButtonDown("Jump") ) { } //某一个手柄键抬起 if (Input.GetButtonUp("Jump")) { } //某一个手柄键长按 if (Input.GetButton("Jump")) { } //移动设备触摸相关 if(Input.touchCount > 0) { Touch t1 = Input.touches[0]; //位置 print(t1.position); //相对上次位置的变化 print(t1.deltaPosition); } //是否启用多点触控 Input.multiTouchEnabled = false; //陀螺仪(重力感应) //是否开启陀螺仪 必须开启 才能正常使用 Input.gyro.enabled = true; //重力加速度向量 print(Input.gyro.gravity); //旋转速度 print(Input.gyro.rotationRate); //陀螺仪 当前的旋转四元数 //比如 用这个角度信息 来控制 场景上的一个3D物体受到重力影响 //手机怎么动 它怎么动 print(Input.gyro.attitude);
三.屏幕Screen相关配置
- 静态属性
- 常用
//当前屏幕分辨率 Resolution r = Screen.currentResolution; print("当前屏幕分辨率的宽" + r.width + "高" + r.height); //屏幕窗口当前宽高 //这得到的 是当前 窗口的 宽高 不是设备分辨率的宽高 //一般写代码 要用窗口宽高 做计算时 就用他们 print(Screen.width); print(Screen.height); //屏幕休眠模式 Screen.sleepTimeout = SleepTimeout.NeverSleep; - 不常用
//运行时是否全屏模式 Screen.fullScreen = true; //窗口模式 //独占全屏FullScreenMode.ExclusiveFullScreen //全屏窗口FullScreenMode.FullScreenWindow //最大化窗口FullScreenMode.MaximizedWindow //窗口模式FullScreenMode.Windowed Screen.fullScreenMode = FullScreenMode.Windowed; //移动设备屏幕转向相关 //允许自动旋转为左横向 Home键在左 Screen.autorotateToLandscapeLeft = true; //允许自动旋转为右横向 Home键在右 Screen.autorotateToLandscapeRight = true; //允许自动旋转到纵向 Home键在下 Screen.autorotateToPortrait = true; //允许自动旋转到纵向倒着看 Home键在上 Screen.autorotateToPortraitUpsideDown = true; //指定屏幕显示方向 Screen.orientation = ScreenOrientation.Landscape;
- 常用
- 静态方法
设置分辨率,一般移动设备不使用Screen.SetResolution(1920, 1080, false);
四.Camera配置
关于Camera的配置说明,如上图,下面依次介绍比较重要的部分
- Clear Flags
如上图所示,共有四个可选项- 第一个天空盒适用于做3D游戏
- 第二个纯色填充适合2D游戏,通常会选择一张图片作为背景,新版的Unity会有Background选项,就是搭配纯色填充使用
- 第三个和多个相机叠加渲染有关,后面搭配深度Depth一起整理
- 第四个没什么用,不清除物体移动的痕迹,了解即可,具体什么效果可以参照下图
- Culling Mask
选择需要进行渲染的层级(Layer)
可以看到只有勾选了的层级才会被渲染出来,然后才能被看到 - Projection
设置摄像机的透视方式,默认是Perspective(透视模式),该模式就是用来设计3D游戏的,它能够展示出Z轴,而Orthographic(正交模式)不会展示出Z轴方向,可以理解为只有xy平面上的移动才能被看到,适合做2D设计- Perspective(透视模式)
- FOV Axis:用于判断视场角由Vertical还是Horizontal决定
- Field of View:视口大小,默认为60.改动效果如下图所示
- Physical Camera:物理摄像机,模拟现实生活中的相机调参,做了解即可,勾选上就可以进行具体调参,每个参数的含义如上图所示,一般不会勾选
- Orthographic(正交模式)
正交模式的可调参数比较少,就一个Size,用于控制摄像机可捕捉画面的大小,默认为5.一般不修改,具体效果如何,可自行尝试
- Perspective(透视模式)
- Clipping Planes
裁剪平面范围,摄像机渲染范围内有近远两个切面,近切面可以看做渲染起点,远切面为渲染终点,只有在这个范围内才能被渲染,效果如下图所示 - Depth
这个参数超级有用,它常常搭配上面提到的Depth Only模式
先解释一下什么意思,一个场景可以有多个相机,并且它们处在不一样的Depth,这个就好像两个人站在同一直线上进行拍照,前面那个人拍一张,后面那个人拍一张,然后将两张照片进行叠加,很显然,后面那张照片会覆盖前面那张,也就是说,层级越大的相机会覆盖层级小的相机的画面,那这就产生问题了,因为每个相机都会指定渲染不同的层级(Layer),如果想让它们的渲染结果同时展示,就必须选中Depth Only模式,如此一来,后面那张照片除了它渲染的内容,其他部分都是透明的,这样再进行叠加,就不会挡住层级小的的相机的渲染结果了,下面通过一个动图来展示 - Target Texture
渲染纹理,将摄像机画面渲染到一张图上,可以用来制作小地图
游戏中的小地图就是从此得来,专门用一个俯视的摄像机来管理 - Occlusion Culling:剔除遮挡,这个主要用来优化渲染性能,如果一个远处的物体被近处的物体挡住了,那么可以选择不渲染,反正也看不见,相机一般默认是勾选了这个
- Viewport Rect
视图窗口,可以将游戏窗口分成很多等份,每个等份由不同的相机来渲染,主机游戏会用到,这里就了解即可,下面上效果图
至于xy和width、height的值的调节,都是百分比的形式,上手调一调便知 - 其余部分一般不会动,具体含义见上面的思维导图即可,关于Target Display就是设置当前相机的渲染结果在哪个屏幕上显示,就是设置屏幕编号,在屏幕窗口中也可以选择当前屏幕编号,两者搭配使用,这里也不赘述了
五.Camera代码配置相关
上面是通过Inpector视图来修改相机相关的配置,与Camera有关的还有代码API,下面进行一个整理
- 重要静态成员
- 获取摄像机
//主摄像机的获取 //如果想通过这种方式 快速获取摄像机 那么场景上必须有一个 tag为MainCamera的摄像机 print(Camera.main.name); //获取摄像机的数量 print(Camera.allCamerasCount); //得到所有摄像机 Camera[] allCamera = Camera.allCameras; print(allCamera.Length); - 渲染相关委托
//摄像机剔除前处理的委托函数 Camera.onPreCull += (c) => { }; //摄像机 渲染前处理的委托 Camera.onPreRender += (c) => { }; //摄像机 渲染后 处理的委托 Camera.onPostRender += (c) => { };
- 获取摄像机
- 重要成员
- 界面上的参数,都可以在Camera中获取到
//比如 下面这句代码 就是得到主摄像机对象 上的深度 进行设置 Camera.main.depth = 10; - 世界坐标转屏幕坐标
//转换过后 x和y对应的就是屏幕坐标 z对应的 是 这个3D物体 里我们的摄像机有多远 //我们会用这个来做的功能 最多的 就是头顶血条相关的功能 Vector3 v = Camera.main.WorldToScreenPoint(this.transform.position); print(v); - 屏幕坐标转世界坐标
屏幕坐标转世界坐标时,注意Z坐标不能为0,因为,3D空间中物体的坐标是在一个面中的,而Z为0是和摄像机的位置重合,是一个点,自然始终都是一个点,不会有变化//3.屏幕坐标转世界坐标 //之所以改变Z轴 是因为 如果不改 Z默认为0 //转换过去的世界坐标系的点 永远都是一个点 可以理解为 视口 相交的焦点 //如果改变了Z 那么转换过去的 世界坐标的点 就是相对于 摄像机前方多少的单位的横截面上的世界坐标点 Vector3 v = Input.mousePosition; v.z = 5; print(Camera.main.ScreenToWorldPoint(v));
- 界面上的参数,都可以在Camera中获取到