第一人称射击游戏实战——用户输入参数的封装及赋值
创建一个空物体,命名为FP_player,设置position为X=16.44,Y=0,Z=-45.65。需要通过角色控制器来操作,因此添加Character Controller组件。并设置Center X=0,Y=1,Z=0。Radius=0.4,Height=0;
知识储备
1.[RequireComponent(typeof(a))]
其中a代表的是可以是Unity组件,也可以是脚本(组件的本质也是脚本)
功能:当添加了一个需使用到某个组件的脚本到一游戏对象上时,这一组件会自动的添加在游戏对象中。
作用:防止添加组件错误
注意事项:只有当脚本加到对象上时会检查必备的组件是否添加,若已经添加好的脚本,更改代码不会为对象自动添加组件
2.[HideInInspector]
使得指定的变量即使是public的访问权限,也不会在inspector面板上显示出来。
知识点一:
前面两个章节已经对于按钮事件给出了函数GetButton,GetButtonDown,GetAxis,GetAxisRaw等。
并且利用Hashtable和list对按键名字和键码进行了封装。但是,我们还需要将输入的按键操作给游戏人物身上,才能有对应的动作。因此需要一些变量,针对游戏人物的控制。因此,我们本步骤写,主要分为两块:1.变量的命名。2.变量的赋值。
变量的命名代码如下,脚本名为fps_PlayerParameter:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class fps_PlayerParameter:MonoBehaviour
{
[HideInInspector]
public Vector2 inputSmoothLook;//用于镜头的控制
[HideInInspector]
public Vector2 inputMoveVector;//用于人物的移动控制
[HideInInspector]
public bool inputCrouch;
[HideInInspector]
public bool inputJump;
[HideInInspector]
public bool inputSprint;
[HideInInspector]
public bool inputFire;
[HideInInspector]
public bool inputReload;
}
知识储备
1.鼠标光标Cursor
lockState(CursorLockMode):决定硬件光标是否在视图中央锁定,或者限制在窗口或者完全不限制。
visible(bool):决定硬件光标是否可视。
SetCursor:将Cursor设置纹理。
Cursor中的lockState是属于CursorLockMode类,该类有三个子类——None,Locked,Confined。
注意事项:1.当锁定时,光标在视图中央无法移动,该状态下,无论visible值,都不可见。2.当限制时,除了限制在视图中央,其他正常。当然为了用户体验,最好例如加一个按钮让用户决定是否locked or confined。
2.获取游戏对象的方法
(1).通过标签寻找
GameObject[] FindGameObjectsWithTag(string tag)
作用:返回有标签为tag的游戏对象的数列,若没有找到一个,则返回空数列,当然使用前注意先申明Tag,若Tag本身就不存在,会抛出异常。
(2).通过游戏对象名字寻找
GameObject.Find(string name)
注意:若name包括“/”,会像路径名一样遍历层次结构,不建议每帧使用,性能低下。通常在MonoBehaviour.Start中会将GameObject分配给一个变量,然后在MonoBehaviour.Update中使用该变量。
(3).通过制定类型寻找
object[] FindObjectOfType(Type type)
T[] FindObjectOfType()
这两种方法都可以。例如
T tr =GameObject.FindObjectOfType(typeof(T)) as T;
T tr = GameObject.FindObjectOfType();
注意:应为该方法返回值是object[],是游戏对象的基类,因此此功能非常慢,不推荐使用,而且还需要注意利用as向下转型。
3.获取组件的方法
主要用一种方法的两种形式,类似于获取游戏对象的方法(3)。
Component GetComponent( Type type)
作用:返回了type类型的组件,前提是游戏对象附加了该Component,若没有附加,则返回Null。
另外一种就是T GetComponent()
例如
HingeJoint hinge = gameobject.GetComponent(typeof(HingeJoint)) as HingJoint;
HingeJoint hinge= gameobject.GetComponent < HingeJoint>();
4.获取子物体的组件的方法
Component[] GetComponentsInChildren(Type t, bool includeInactive)
或者
T[] GetComponentsInChildren(bool includeInactive)
功能:查找父物体与其所有子物体中的同一指定类型组件。可以再利用foreach或者for循环对其修改(推荐用for修改,foreach查看显示。
因为返回的是Component[] 可以返回子物体的同一组件,但是GetComponentInChildren也是合法的,只不过是返回子物体中的第一个有指定组件的组件,即Component。
注意:这里includeInactive决定了哪个子物体被查找,是bool类型,如果是true,就是全部子物体都要查找。当然,不论是true还是false,父物体都是会查找一遍的。
例如:
Transform[] tr = gameobject.GetComponentsInChildren(typeof(Transform)) as Transform;
Transform[] tr= gameobject.GetComponent < Transform>();
同样的,查找时,因为查找的是Component,是Transform的父类,因此也要注意as向下转型。
总结:我们通常采用的还是用泛型来获取,因此还是少用as。
5.属性访问器的同类访问以及类外访问
属性访问器通常对类内的变量进行保护,通过Set或者Get或者Set
和Get进行读写操作。在对该类实例化的时候,是通过类或者对象来访问属性访问器的。例如,Person类中有私有变量age,属性Age。在.net中,主函数Main对Person类实例化xiaoming后需对age进行赋值,则要么通过Person.Age或者xiaoming.Age,取决于Person类是静态还是非静态。但是如果是脚本中,类内访问,不需要Person或者xiaoming。直接对Age进行赋值。Age=10;即可。
知识点二
创建脚本,命名为fps_FPInput,主要用来对上述的变量进行赋值初始化。
代码思路:需要用属性访问,将第一人称视角不显示鼠标光标,因此对于LockMode和visible进行控制。另外,本脚本的主要作用是将检测按键是否按下,然后将状态告诉给人物控制中的对应的人物变量。因此需要利用到 第一人称射击游戏实战——按键输入封装链接中的脚本fps_Input.之前,该脚本添加在了命名为GameController的空物体上,这里还需要在命名为FP_Player的空物体上挂载上两个脚本,便于赋值给PlayerParameter中的各种变量,控制相机的转动,人物的移动以及各种动作的完成。这两个脚本就是1.PlayerParameter(变量的命名)2.fps_FPInput(变量的赋值)
public class fps_FPInput:MonoBehaviour
{
public bool LockCursor
{
get
{
return Cursor.LockState=Cursor.CursorLockMode.Locked? true:false;
}
set
{
Cursor.visible=value;
Cursor.LockState=value? Cursor.CursorLockMode.Locked:Cursor.CursorLockMode.None;
}
}
private fps_Player Parameter;
private fps_Input input;
void Start()
{
LockCursor=true;//属性访问器的同类访问。
parameter = this.GetComponent<fps_Player>();
input=Gameobject.FindGameObjectWithTag(Tags.gameController).GetComponent<fps_Input>();
//获取两个组件(是fps_Player脚本和fps_Input脚本),因此parameter和input两个是脚本类型的变量。
}
private void InitialInput()
{
parameter.inputMoveVector=new Vector2(input.GetAxis("Horizontal"),input.GetAxis("Vertical"));
parameter.inputSmoothLook=new Vector2(input.GetAxisRaw("Mouse X"),input.GetAxisRaw("Mouse Y"));
//注意:GetAxis和GetiAxisRaw是我们前面封装好的检测轴的方法,而不是Input.GetAxis和Input.GetAxisRaw。
parameter.inputCrouch=input.GetButton("Crouch");
parameter.inputJump=input.GetButton("jump");
parameter.inputFire=input.GetButton("Fire");
parameter.inputSprint=input.GetButton("Sprint");
parameter.inputReload=input.GetButtonDown("Reload");
//GetButton是封装好的检测GetKey。因按下按键,动作连续执行。但是GetButtonDown是封装好的检测GetKeyDown,按下一次按键,就可以装弹,不需要一直装弹。
}
void Update()
{
InitialInput();
}
}