- Creating ELearning Games with Unity
- David Horachek
- 1417字
- 2021-07-16 12:22:50
Developing the player controls code
The third system we need to implement is the controls or how the character will respond to the user input. As a first pass, we need to be able to move our player in the world, so we will implement walk forward, walk backwards, walk left, and walk right. Luckily for us, Unity gives us an input system with axes so that we can write our control code once, and it will work with any devices that have an axis (such as keyboard or joypad). Of course, the devil is in the detail and keyboard controls behave differently from joypads, so we will write our code for keyboard input as it is the most responsive and most ubiquitous device. Once this script is finished, its behavior in combination with the GameCam
script will control how the player motion feels in the game.
Implementing PlayerControls.cs
For every frame our player updates, perform the following steps that describe our PlayeControls algorithm:
- Store the forward and right vectors of the current camera.
- Store the raw axis input from the controller (keyboard or joystick). These values will range from
-1.0
to1.0
, corresponding to full left or right, or full forward or backwards. Note that if you use a joystick, the rate of change of these values will generally be much slower than if a keyboard is used, so the code that processes it must be adjusted accordingly. - Apply the raw input to transform the current camera basis vectors and compute a camera relative target direction vector.
- Interpolate the current movement vector towards the target vector and damp the rate of change of the movement vector, storing the result away.
- Compute the displacement of the camera with movement * movespeed and apply this to the camera.
- Rotate the camera to the current move direction vector.
Now let's implement this algorithm in C# code:
- Right click on the
Chapter1 assets
folder and select Create New C# Script. Name itPlayerControls.cs
. Add this script toGameObject
of Player1 by dragging-and-dropping it onto the object. - Add a
CharacterController
component to the player'sGameObject
component as well. If Unity asks you whether you want to replace the box collider, agree to the change. - Create
public Vector3 moveDirection
that will be used to store the current actual direction vector of the player. We initialize it to the zero vector by default as follows:public Vector3 moveDirection = Vector3.zero;
- Create three public float variables:
rotateSpeed
,moveSpeed
, andspeedSmoothing
. The first two are coefficients of motion for rotation and translation, and the third is a factor that influences the smoothing ofmoveSpeed
. Note thatmoveSpeed
is private because this will only be computed as the result of the smoothing calculation betweenmoveDirection
andtargetDirection
as shown in the following code:public Float rotateSpeed; private float moveSpeed = 0.0f; public float speedSmoothing = 10.0f;
- Inside the update loop of this script, we will call a custom method called
UpdateMovement()
. This method will contain the code that actually reads input from the user and moves the player in the game as shown in the following code:void Update() { UpdateMovement() }
- Above the update loop, let's implement the
UpdateMovement()
method as follows:void UpdateMovement () { // to be filled in }
- Inside this method, step 1 is accomplished by storing the horizontal projection of the forward and right vectors of the current camera as follows:
Vector3 cameraForward = Camera.mainCamera.transform.TransformDirection (Vector3.forward);
- We project onto the horizontal plane because we want the character's motion to be parallel to the horizontal plane rather than vary with the camera's angle. We also use
Normalize
to ensure that the vector is well formed, as shown in the following code:cameraForward.y = 0.0f; cameraForward.Normalize();
Also, note the trick whereby we find the right vector by flipping the x and z components and negating the last component. This is faster than extracting and transforming the right vector, but returns the same result shown in the following code:
Vector3 cameraRight = new Vector3 (cameraForward.z, 0.0f, -cameraForward.x);
- We store the raw axis values from Unity's
Input
class. Recall that this is the class that handles input for us, from which we can poll button and axes values. Forh
(which has a range from-1
to1
), the value between this range corresponds to an amount of horizontal displacement on the analog stick, joystick, or a keypress, as shown in the following code:float v = Input.GetAxisRaw("Vertical");
For v (which ranges from
-1
to1
), the value between this range corresponds to an amount of vertical displacement of the analog stick, joystick, or a different keypress.float h = Input.GetAxisRaw("Horizontal");
To see the keybindings, please check the input class settings under Edit | ProjectSettings | Input. There, under the Axes field in the object inspector, we can see all of the defined axes in the input manager class, their bindings, their names, and their parameters.
- We compute the target direction vector for the character as proportional to the user input (v, h). By transforming (v, h) into camera space, the result is a world space vector that holds a camera relative motion vector that we store in
targetDirection
as shown in the following code:Vector3 targetDirection = h * cameraRight + v * cameraForward;
- If this target vector is non-zero (when the user is moving, and hence
v
,h
are non-zero), we updatemoveDirection
by rotating it smoothly (and by a small magnitude), towardsmoveTarget
. By doing this in every frame, the actual direction eventually approximates the target direction, even astargetDirection
itself changes.We keep
moveDirection
normalized because our move speed calculation assumes a unit direction vector as shown in the following code:moveDirection = Vector3.RotateTowards (moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000); moveDirection = moveDirection.normalized;
- We smoothly LERP the speed of our character up and down, trailing the actual magnitude of the
targetDirection
vector. This is to create an appealing effect that reduces jitter in the player and is crucial when we are using keyboard controls, where the variance inv
andh
raw data is at its highest, as shown in the following code:float curSmooth = speedSmoothing * Time.deltaTime; float targetSpeed = Mathf.Min (targetDirection.magnitude, 1.0f); moveSpeed = Mathf.Lerp (moveSpeed, targetSpeed, curSmooth);
- We compute the displacement vector for the player in this frame with movementDirection * movespeed (remember that
movespeed
is smoothly interpolated andmoveDirection
is smoothly rotated towardtargetDirecton
).We scale displacement by
Time.delta
time (the amount of real time that has elapsed since the last frame). We do this so that our calculation is time dependent rather than frame rate dependent as shown in the following code:Vector3 displacement = moveDirection * moveSpeed * Time.deltaTime;
- Then, we move the character by invoking the
move
method on theCharacterController
component of the player, passing thedisplacement
vector as a parameter as follows:this.GetComponent<CharacterController>() .Move(displacement);
- Finally, we assign the rotation of
MoveDirection
to the rotation of the transform as follows:transform.rotation = Quaternion.LookRotation (moveDirection);
Congratulations! You have now written your first player controls class that can read user input from multiple axes and use that to drive a rotating and translating character capsule. To test this class, let's set the following default values in the Inspector pane as seen in the previous screenshot:
- Track Obj: Set this to the Player1 object by dragging-and-dropping the object reference from the Hierarchy tab to the
trackObj
reference in the object inspector. - Height: Set this to
0.25
. In general, the lower the camera, the more dramatic the effect, but the less playable the game will be (because the user can see less of the world on screen). - Desired Distance: Set this to
4
. At this setting, we can see the character framed nicely on screen when it is both moving and standing still. - Rot Damp: Set this to
0.01
. The smaller this value, the looser and more interesting the rotation effect. The larger this value, the more tense the spring in the interpolation. - Height Damp: Set this to
0.5
. The smaller this value, the looser and more interesting the height blending effect.
Try experimenting with the following values and see what happens:
- Rotate Speed : Set the default to
100
. The higher the value, the faster the player will rotate when the horizontal axis is set to full left or right. - Speed Smoothing: Set the default to
10
. The higher this value, the smoother the character's acceleration and deceleration.
Try experimenting with these values to understand their effect on the player's motion behavior.
- Dreamweaver 8中文版商業(yè)案例精粹
- 來吧!帶你玩轉(zhuǎn)Excel VBA
- Windows XP中文版應(yīng)用基礎(chǔ)
- 計算機網(wǎng)絡(luò)應(yīng)用基礎(chǔ)
- 運動控制器與交流伺服系統(tǒng)的調(diào)試和應(yīng)用
- 愛犯錯的智能體
- Salesforce for Beginners
- 教育機器人的風(fēng)口:全球發(fā)展現(xiàn)狀及趨勢
- Applied Data Visualization with R and ggplot2
- 云計算和大數(shù)據(jù)的應(yīng)用
- Apache源代碼全景分析(第1卷):體系結(jié)構(gòu)與核心模塊
- Mastering MongoDB 3.x
- 機器人制作入門(第4版)
- RealFlow流體制作經(jīng)典實例解析
- 運動控制系統(tǒng)