Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Interactions;
//This script handles moving the character on the X axis, both on the ground and in the air.
[RequireComponent(typeof(CharacterGround))]
[RequireComponent(typeof(Rigidbody2D))]
public class CharacterMovement : MonoBehaviour
{
[Header("Components")]
private Rigidbody2D body;
CharacterGround ground;
[Header( "GMTK Platformer Settings" )]
public Character_Settings_SO characterSettingsSO = null;
//[Header("Movement Stats")]
//[SerializeField, Range(0f, 20f)][Tooltip("Maximum movement speed")] public float maxSpeed = 10f;
//[SerializeField, Range(0f, 100f)][Tooltip("How fast to reach max speed")] public float maxAcceleration = 52f;
//[SerializeField, Range(0f, 100f)][Tooltip("How fast to stop after letting go")] public float maxDeceleration = 52f;
//[SerializeField, Range(0f, 100f)][Tooltip("How fast to stop when changing direction")] public float maxTurnSpeed = 80f;
//[SerializeField, Range(0f, 100f)][Tooltip("How fast to reach max speed when in mid-air")] public float maxAirAcceleration;
//[SerializeField, Range(0f, 100f)][Tooltip("How fast to stop in mid-air when no direction is used")] public float maxAirDeceleration;
//[SerializeField, Range(0f, 100f)][Tooltip("How fast to stop when changing direction when in mid-air")] public float maxAirTurnSpeed = 80f;
//[SerializeField][Tooltip("Friction to apply against movement on stick")] private float friction;
//[Header("Options")]
//[Tooltip("When false, the charcter will skip acceleration and deceleration and instantly move and stop")] public bool useAcceleration;
[Header("Calculations")]
public float directionX;
private Vector2 desiredVelocity;
public Vector2 velocity;
private float maxSpeedChange;
private float acceleration;
private float deceleration;
private float turnSpeed;
[Header("Current State")]
public bool onGround;
public bool pressingKey;
private void Awake() {
if ( characterSettingsSO == null ) {
Debug.LogError( "You must assign a GMTK_Settings_SO Scriptable Object to the CharacterMovement script for it to function." );
enabled = false;
}
//Find the character's Rigidbody and ground detection script
body = GetComponent<Rigidbody2D>();
ground = GetComponent<CharacterGround>();
}
public void OnMovement(InputAction.CallbackContext context)
{
//This is called when you input a direction on a valid input type, such as arrow keys or analogue stick
//The value will read -1 when pressing left, 0 when idle, and 1 when pressing right.
directionX = context.ReadValue<float>();
}
private void Update()
{
//Used to flip the character's sprite when she changes direction
//Also tells us that we are currently pressing a direction button
if (directionX != 0)
{
transform.localScale = new Vector3(directionX > 0 ? 1 : -1, 1, 1);
pressingKey = true;
}
else
{
pressingKey = false;
}
//Calculate's the character's desired velocity - which is the direction you are facing, multiplied by the character's maximum speed
//Friction is not used in this game
desiredVelocity = new Vector2(directionX, 0f) * Mathf.Max( characterSettingsSO.maxSpeed - characterSettingsSO.friction, 0f);
}
private void FixedUpdate()
{
//Fixed update runs in sync with Unity's physics engine
//Get Kit's current ground status from her ground script
onGround = ground.GetOnGround();
//Get the Rigidbody's current velocity
velocity = body.velocity;
//Calculate movement, depending on whether "Instant Movement" has been checked
if ( characterSettingsSO.useAcceleration )
{
RunWithAcceleration();
}
else
{
if (onGround)
{
RunWithoutAcceleration();
}
else
{
RunWithAcceleration();
}
}
}
private void RunWithAcceleration()
{
//Set our acceleration, deceleration, and turn speed stats, based on whether we're on the ground on in the air
acceleration = onGround ? characterSettingsSO.maxAcceleration : characterSettingsSO.maxAirAcceleration;
deceleration = onGround ? characterSettingsSO.maxDeceleration : characterSettingsSO.maxAirDeceleration;
turnSpeed = onGround ? characterSettingsSO.maxTurnSpeed : characterSettingsSO.maxAirTurnSpeed;
if (pressingKey)
{
//If the sign (i.e. positive or negative) of our input direction doesn't match our movement, it means we're turning around and so should use the turn speed stat.
if (Mathf.Sign(directionX) != Mathf.Sign(velocity.x))
{
maxSpeedChange = turnSpeed * Time.deltaTime;
}
else
{
//If they match, it means we're simply running along and so should use the acceleration stat
maxSpeedChange = acceleration * Time.deltaTime;
}
}
else
{
//And if we're not pressing a direction at all, use the deceleration stat
maxSpeedChange = deceleration * Time.deltaTime;
}
//Move our velocity towards the desired velocity, at the rate of the number calculated above
velocity.x = Mathf.MoveTowards(velocity.x, desiredVelocity.x, maxSpeedChange);
//Update the Rigidbody with this new velocity
body.velocity = velocity;
}
private void RunWithoutAcceleration()
{
//If we're not using acceleration and deceleration, just send our desired velocity (direction * max speed) to the Rigidbody
velocity.x = desiredVelocity.x;
body.velocity = velocity;
}
}