├── .gitignore
├── DemoScene.tscn
├── LICENSE
├── README.md
├── icon.png
├── icon.png.import
├── platformer_controller
└── platformer_controller.gd
└── project.godot
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Godot-specific ignores
3 | .godot/
4 | .import/
5 | export.cfg
6 | export_presets.cfg
7 |
8 | # Mono-specific ignores
9 | .mono/
10 | data_*/
11 |
--------------------------------------------------------------------------------
/DemoScene.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=7 format=3 uid="uid://cqfhnpb7xftpo"]
2 |
3 | [ext_resource type="Script" path="res://platformer_controller/platformer_controller.gd" id="1"]
4 | [ext_resource type="Texture2D" uid="uid://di5a1pv5iuup3" path="res://icon.png" id="2"]
5 |
6 | [sub_resource type="RectangleShape2D" id="1"]
7 | size = Vector2(1024, 112)
8 |
9 | [sub_resource type="RectangleShape2D" id="2"]
10 | size = Vector2(416, 112)
11 |
12 | [sub_resource type="RectangleShape2D" id="3"]
13 | size = Vector2(64, 608)
14 |
15 | [sub_resource type="RectangleShape2D" id="4"]
16 | size = Vector2(64, 64)
17 |
18 | [node name="Main" type="Node2D"]
19 |
20 | [node name="StaticBody2D" type="StaticBody2D" parent="."]
21 | position = Vector2(520, 544)
22 |
23 | [node name="ColorRect" type="ColorRect" parent="StaticBody2D"]
24 | offset_left = -520.0
25 | offset_top = -56.0
26 | offset_right = 504.0
27 | offset_bottom = 56.0
28 | color = Color(0, 0.443137, 0.027451, 1)
29 |
30 | [node name="CollisionShape2D" type="CollisionShape2D" parent="StaticBody2D"]
31 | position = Vector2(-8, 0)
32 | shape = SubResource("1")
33 |
34 | [node name="StaticBody2D2" type="StaticBody2D" parent="."]
35 | position = Vector2(520, 360)
36 |
37 | [node name="ColorRect" type="ColorRect" parent="StaticBody2D2"]
38 | offset_left = -520.0
39 | offset_top = 16.0
40 | offset_right = -104.0
41 | offset_bottom = 128.0
42 | color = Color(0, 0.443137, 0.027451, 1)
43 |
44 | [node name="CollisionShape2D" type="CollisionShape2D" parent="StaticBody2D2"]
45 | position = Vector2(-312, 72)
46 | shape = SubResource("2")
47 |
48 | [node name="StaticBody2D3" type="StaticBody2D" parent="."]
49 | position = Vector2(520, 360)
50 |
51 | [node name="CollisionShape2D" type="CollisionShape2D" parent="StaticBody2D3"]
52 | position = Vector2(-552, -64)
53 | shape = SubResource("3")
54 |
55 | [node name="CollisionShape2D2" type="CollisionShape2D" parent="StaticBody2D3"]
56 | position = Vector2(536, -64)
57 | shape = SubResource("3")
58 |
59 | [node name="PlatformerController2D" type="CharacterBody2D" parent="."]
60 | position = Vector2(288, 320)
61 | script = ExtResource("1")
62 |
63 | [node name="icon" type="Sprite2D" parent="PlatformerController2D"]
64 | texture = ExtResource("2")
65 |
66 | [node name="CollisionShape2D" type="CollisionShape2D" parent="PlatformerController2D"]
67 | shape = SubResource("4")
68 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ev01
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PlatformerController2D
2 |
3 | A 2D platformer class for godot.
4 |
5 | ## Changelog
6 |
7 | ### Version 2.0.2
8 |
9 | - Fixed bug where falling off a cliff would give an extra jump
10 |
11 | - Fixed bug where setting coyote_time or jump_buffer to 0 would raise an error
12 |
13 | - Added ground_jump and double_jump functions
14 |
15 | - Added separate functions for starting the jump_buffer or coyote timers and checking if they are running
16 |
17 | ### Version 2.0.1
18 |
19 | - Removed the .godot and .import folders from the repository
20 |
21 | ### Version 2.0
22 |
23 | - Updated to Godot 4.0
24 |
25 | - Removed set and get functions in favour of properties
26 |
27 | - Can now have negative jump height, which will reverse gravity
28 |
29 | - Gravity is now positive when pointing down, and negative when pointing up
30 |
31 | - Added 'jumped' and 'hit_ground' signals
32 |
33 | - Split the large `_physics_process` function into multiple functions
34 |
35 | ### Version 1.0.1
36 |
37 | - Updated to Godot 3.4
38 | - Fixed division by zero error when changing min jump height
39 | - Other minor fixes
40 |
41 | ## Installation
42 |
43 | 1. Add platformer_controller.gd to your project
44 | 2. Type `extends PlatformerController2D` to the top of your script
45 | 3. Add these input mappings in your project settings (or you can change the input variables in the inspector)
46 | - "move_left"
47 | - "move_right"
48 | - "jump"
49 |
50 | ## Features
51 |
52 | - Double jump
53 | - Coyote time
54 | - Jump buffer
55 | - Hold jump to go higher
56 | - Defining jump height and duration (as opposed to setting gravity and jump velocity)
57 | - Assymetrical jumps (falling faster than rising)
58 |
59 | |
|
|
|
60 | | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
61 |
62 | ## Customization / Export variables
63 |
64 | Here are the values that you can change in the inspector:
65 |
66 | ### max_jump_height
67 |
68 | The max jump height in pixels. You reach this when you hold down jump.
69 |
70 | ### Min Jump Height
71 |
72 | The minimum jump height (tapping jump).
73 |
74 | ### Double Jump Height
75 |
76 | The height of your jump in the air (i.e. double jump, triple jump etc.).
77 |
78 | ### Jump Duration
79 |
80 | How long it takes to get to the peak of the jump (in seconds).
81 |
82 | ### Falling Gravity Multiplier
83 |
84 | Multiplies the gravity by this while falling.
85 |
86 | ### Max Jump Amount
87 |
88 | How many times you can jump before hitting the ground. Set this to 2 for a double jump.
89 |
90 | ### Max Acceleration
91 |
92 | How much you accelerate when you hold left or right (in pixels/sec^2).
93 |
94 | ### Friction
95 |
96 | The higher this number, the more friction is on your character.
97 |
98 | ### Can Hold Jump
99 |
100 | If this is off, you have to press jump down every time you land. If its on you can keep it held.
101 |
102 | ### Coyote Time
103 |
104 | You can still jump this many seconds after falling off a ledge.
105 |
106 | ### Jump Buffer
107 |
108 | Pressing jump this many seconds before hitting the ground will still make you jump.\
109 | Note: This is only needed when can_hold_jump is off.
110 |
111 | ### Input Variables
112 |
113 | `input_left`\
114 | `input_right`\
115 | `input_jump`\
116 | Set these to the names of your actions in the Input Map
117 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ev01/PlatformerController2D/178b1df40dd9ec40841893807d5ea3da819931d0/icon.png
--------------------------------------------------------------------------------
/icon.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://di5a1pv5iuup3"
6 | path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.png"
14 | dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/platformer_controller/platformer_controller.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | class_name PlatformerController2D
4 |
5 | signal jumped(is_ground_jump: bool)
6 | signal hit_ground()
7 |
8 |
9 | # Set these to the name of your action (in the Input Map)
10 | ## Name of input action to move left.
11 | @export var input_left : String = "move_left"
12 | ## Name of input action to move right.
13 | @export var input_right : String = "move_right"
14 | ## Name of input action to jump.
15 | @export var input_jump : String = "jump"
16 |
17 |
18 | const DEFAULT_MAX_JUMP_HEIGHT = 150
19 | const DEFAULT_MIN_JUMP_HEIGHT = 60
20 | const DEFAULT_DOUBLE_JUMP_HEIGHT = 100
21 | const DEFAULT_JUMP_DURATION = 0.3
22 |
23 | var _max_jump_height: float = DEFAULT_MAX_JUMP_HEIGHT
24 | ## The max jump height in pixels (holding jump).
25 | @export var max_jump_height: float = DEFAULT_MAX_JUMP_HEIGHT:
26 | get:
27 | return _max_jump_height
28 | set(value):
29 | _max_jump_height = value
30 |
31 | default_gravity = calculate_gravity(_max_jump_height, jump_duration)
32 | jump_velocity = calculate_jump_velocity(_max_jump_height, jump_duration)
33 | double_jump_velocity = calculate_jump_velocity2(double_jump_height, default_gravity)
34 | release_gravity_multiplier = calculate_release_gravity_multiplier(
35 | jump_velocity, min_jump_height, default_gravity)
36 |
37 |
38 | var _min_jump_height: float = DEFAULT_MIN_JUMP_HEIGHT
39 | ## The minimum jump height (tapping jump).
40 | @export var min_jump_height: float = DEFAULT_MIN_JUMP_HEIGHT:
41 | get:
42 | return _min_jump_height
43 | set(value):
44 | _min_jump_height = value
45 | release_gravity_multiplier = calculate_release_gravity_multiplier(
46 | jump_velocity, min_jump_height, default_gravity)
47 |
48 |
49 |
50 | var _double_jump_height: float = DEFAULT_DOUBLE_JUMP_HEIGHT
51 | ## The height of your jump in the air.
52 | @export var double_jump_height: float = DEFAULT_DOUBLE_JUMP_HEIGHT:
53 | get:
54 | return _double_jump_height
55 | set(value):
56 | _double_jump_height = value
57 | double_jump_velocity = calculate_jump_velocity2(double_jump_height, default_gravity)
58 |
59 |
60 | var _jump_duration: float = DEFAULT_JUMP_DURATION
61 | ## How long it takes to get to the peak of the jump in seconds.
62 | @export var jump_duration: float = DEFAULT_JUMP_DURATION:
63 | get:
64 | return _jump_duration
65 | set(value):
66 | _jump_duration = value
67 |
68 | default_gravity = calculate_gravity(max_jump_height, jump_duration)
69 | jump_velocity = calculate_jump_velocity(max_jump_height, jump_duration)
70 | double_jump_velocity = calculate_jump_velocity2(double_jump_height, default_gravity)
71 | release_gravity_multiplier = calculate_release_gravity_multiplier(
72 | jump_velocity, min_jump_height, default_gravity)
73 |
74 | ## Multiplies the gravity by this while falling.
75 | @export var falling_gravity_multiplier = 1.5
76 | ## Amount of jumps allowed before needing to touch the ground again. Set to 2 for double jump.
77 | @export var max_jump_amount = 1
78 | @export var max_acceleration = 10000
79 | @export var friction = 20
80 | @export var can_hold_jump : bool = false
81 | ## You can still jump this many seconds after falling off a ledge.
82 | @export var coyote_time : float = 0.1
83 | ## Pressing jump this many seconds before hitting the ground will still make you jump.
84 | ## Only neccessary when can_hold_jump is unchecked.
85 | @export var jump_buffer : float = 0.1
86 |
87 |
88 | # These will be calcualted automatically
89 | # Gravity will be positive if it's going down, and negative if it's going up
90 | var default_gravity : float
91 | var jump_velocity : float
92 | var double_jump_velocity : float
93 | # Multiplies the gravity by this when we release jump
94 | var release_gravity_multiplier : float
95 |
96 |
97 | var jumps_left : int
98 | var holding_jump := false
99 |
100 | enum JumpType {NONE, GROUND, AIR}
101 | ## The type of jump the player is performing. Is JumpType.NONE if they player is on the ground.
102 | var current_jump_type: JumpType = JumpType.NONE
103 |
104 | # Used to detect if player just hit the ground
105 | var _was_on_ground: bool
106 |
107 | var acc = Vector2()
108 |
109 | # coyote_time and jump_buffer must be above zero to work. Otherwise, godot will throw an error.
110 | @onready var is_coyote_time_enabled = coyote_time > 0
111 | @onready var is_jump_buffer_enabled = jump_buffer > 0
112 | @onready var coyote_timer = Timer.new()
113 | @onready var jump_buffer_timer = Timer.new()
114 |
115 |
116 | func _init():
117 | default_gravity = calculate_gravity(max_jump_height, jump_duration)
118 | jump_velocity = calculate_jump_velocity(max_jump_height, jump_duration)
119 | double_jump_velocity = calculate_jump_velocity2(double_jump_height, default_gravity)
120 | release_gravity_multiplier = calculate_release_gravity_multiplier(
121 | jump_velocity, min_jump_height, default_gravity)
122 |
123 |
124 | func _ready():
125 | if is_coyote_time_enabled:
126 | add_child(coyote_timer)
127 | coyote_timer.wait_time = coyote_time
128 | coyote_timer.one_shot = true
129 |
130 | if is_jump_buffer_enabled:
131 | add_child(jump_buffer_timer)
132 | jump_buffer_timer.wait_time = jump_buffer
133 | jump_buffer_timer.one_shot = true
134 |
135 |
136 | func _input(_event):
137 | acc.x = 0
138 | if Input.is_action_pressed(input_left):
139 | acc.x = -max_acceleration
140 |
141 | if Input.is_action_pressed(input_right):
142 | acc.x = max_acceleration
143 |
144 | if Input.is_action_just_pressed(input_jump):
145 | holding_jump = true
146 | start_jump_buffer_timer()
147 | if (not can_hold_jump and can_ground_jump()) or can_double_jump():
148 | jump()
149 |
150 | if Input.is_action_just_released(input_jump):
151 | holding_jump = false
152 |
153 |
154 | func _physics_process(delta):
155 | if is_coyote_timer_running() or (is_feet_on_ground() and current_jump_type == JumpType.NONE):
156 | jumps_left = max_jump_amount
157 | if is_feet_on_ground() and current_jump_type == JumpType.NONE:
158 | start_coyote_timer()
159 |
160 | # Check if we just hit the ground this frame
161 | if not _was_on_ground and is_feet_on_ground():
162 | current_jump_type = JumpType.NONE
163 | jumps_left = max_jump_amount
164 | if is_jump_buffer_timer_running() and not can_hold_jump:
165 | jump()
166 |
167 | hit_ground.emit()
168 |
169 |
170 | # Cannot do this in _input because it needs to be checked every frame
171 | if Input.is_action_pressed(input_jump):
172 | if can_ground_jump() and can_hold_jump:
173 | jump()
174 |
175 | var gravity = apply_gravity_multipliers_to(default_gravity)
176 | acc.y = gravity
177 |
178 | # Apply friction
179 | velocity.x *= 1 / (1 + (delta * friction))
180 | velocity += acc * delta
181 |
182 |
183 | _was_on_ground = is_feet_on_ground()
184 | move_and_slide()
185 |
186 |
187 | ## Use this instead of coyote_timer.start() to check if the coyote_timer is enabled first
188 | func start_coyote_timer():
189 | if is_coyote_time_enabled:
190 | coyote_timer.start()
191 |
192 | ## Use this instead of jump_buffer_timer.start() to check if the jump_buffer is enabled first
193 | func start_jump_buffer_timer():
194 | if is_jump_buffer_enabled:
195 | jump_buffer_timer.start()
196 |
197 | ## Use this instead of `not coyote_timer.is_stopped()`. This will always return false if
198 | ## the coyote_timer is disabled
199 | func is_coyote_timer_running():
200 | if (is_coyote_time_enabled and not coyote_timer.is_stopped()):
201 | return true
202 |
203 | return false
204 |
205 | ## Use this instead of `not jump_buffer_timer.is_stopped()`. This will always return false if
206 | ## the jump_buffer_timer is disabled
207 | func is_jump_buffer_timer_running():
208 | if is_jump_buffer_enabled and not jump_buffer_timer.is_stopped():
209 | return true
210 |
211 | return false
212 |
213 |
214 | func can_ground_jump() -> bool:
215 | if jumps_left <= 0:
216 | return false
217 |
218 | if (current_jump_type == JumpType.NONE and is_feet_on_ground()) or is_coyote_timer_running():
219 | return true
220 |
221 | return false
222 |
223 |
224 | func can_double_jump():
225 | if jumps_left <= 1 and jumps_left == max_jump_amount:
226 | # Special case where you've fallen off a cliff and only have 1 jump. You cannot use your
227 | # first jump in the air
228 | return false
229 |
230 | if jumps_left > 0 and not is_feet_on_ground() and coyote_timer.is_stopped():
231 | return true
232 |
233 | return false
234 |
235 |
236 | ## Same as is_on_floor(), but also returns true if gravity is reversed and you are on the ceiling
237 | func is_feet_on_ground():
238 | if is_on_floor() and default_gravity >= 0:
239 | return true
240 | if is_on_ceiling() and default_gravity <= 0:
241 | return true
242 |
243 | return false
244 |
245 |
246 | ## Perform a ground jump, or a double jump if the character is in the air.
247 | func jump():
248 | if can_double_jump():
249 | double_jump()
250 | else:
251 | ground_jump()
252 |
253 |
254 | ## Perform a double jump without checking if the player is able to.
255 | func double_jump():
256 | if jumps_left == max_jump_amount:
257 | # Your first jump must be used when on the ground.
258 | # If your first jump is used in the air, an additional jump will be taken away.
259 | jumps_left -= 1
260 |
261 | velocity.y = -double_jump_velocity
262 | current_jump_type = JumpType.AIR
263 | jumps_left -= 1
264 | jumped.emit(false)
265 |
266 |
267 | ## Perform a ground jump without checking if the player is able to.
268 | func ground_jump():
269 | velocity.y = -jump_velocity
270 | current_jump_type = JumpType.GROUND
271 | jumps_left -= 1
272 | coyote_timer.stop()
273 | jumped.emit(true)
274 |
275 |
276 | func apply_gravity_multipliers_to(gravity) -> float:
277 | if velocity.y * sign(default_gravity) > 0: # If we are falling
278 | gravity *= falling_gravity_multiplier
279 |
280 | # if we released jump and are still rising
281 | elif velocity.y * sign(default_gravity) < 0:
282 | if not holding_jump:
283 | if not current_jump_type == JumpType.AIR: # Always jump to max height when we are using a double jump
284 | gravity *= release_gravity_multiplier # multiply the gravity so we have a lower jump
285 |
286 |
287 | return gravity
288 |
289 |
290 | ## Calculates the desired gravity from jump height and jump duration. [br]
291 | ## Formula is from [url=https://www.youtube.com/watch?v=hG9SzQxaCm8]this video[/url]
292 | func calculate_gravity(p_max_jump_height, p_jump_duration):
293 | return (2 * p_max_jump_height) / pow(p_jump_duration, 2)
294 |
295 |
296 | ## Calculates the desired jump velocity from jump height and jump duration.
297 | func calculate_jump_velocity(p_max_jump_height, p_jump_duration):
298 | return (2 * p_max_jump_height) / (p_jump_duration)
299 |
300 |
301 | ## Calculates jump velocity from jump height and gravity. [br]
302 | ## Formula from
303 | ## [url]https://sciencing.com/acceleration-velocity-distance-7779124.html#:~:text=in%20every%20step.-,Starting%20from%3A,-v%5E2%3Du[/url]
304 | func calculate_jump_velocity2(p_max_jump_height, p_gravity):
305 | return sqrt(abs(2 * p_gravity * p_max_jump_height)) * sign(p_max_jump_height)
306 |
307 |
308 | ## Calculates the gravity when the key is released based off the minimum jump height and jump velocity. [br]
309 | ## Formula is from [url]https://sciencing.com/acceleration-velocity-distance-7779124.html[/url]
310 | func calculate_release_gravity_multiplier(p_jump_velocity, p_min_jump_height, p_gravity):
311 | var release_gravity = pow(p_jump_velocity, 2) / (2 * p_min_jump_height)
312 | return release_gravity / p_gravity
313 |
314 |
315 | ## Returns a value for friction that will hit the max speed after 90% of time_to_max seconds. [br]
316 | ## Formula from [url]https://www.reddit.com/r/gamedev/comments/bdbery/comment/ekxw9g4/?utm_source=share&utm_medium=web2x&context=3[/url]
317 | func calculate_friction(time_to_max):
318 | return 1 - (2.30259 / time_to_max)
319 |
320 |
321 | ## Formula from [url]https://www.reddit.com/r/gamedev/comments/bdbery/comment/ekxw9g4/?utm_source=share&utm_medium=web2x&context=3[/url]
322 | func calculate_speed(p_max_speed, p_friction):
323 | return (p_max_speed / p_friction) - p_max_speed
324 |
325 |
--------------------------------------------------------------------------------
/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="PlatformerController2D"
14 | run/main_scene="res://DemoScene.tscn"
15 | config/features=PackedStringArray("4.0")
16 | config/icon="res://icon.png"
17 |
18 | [display]
19 |
20 | window/size/viewport_width=1024
21 | window/size/viewport_height=600
22 | window/stretch/mode="canvas_items"
23 |
24 | [input]
25 |
26 | move_left={
27 | "deadzone": 0.5,
28 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
29 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null)
30 | ]
31 | }
32 | move_right={
33 | "deadzone": 0.5,
34 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
35 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null)
36 | ]
37 | }
38 | jump={
39 | "deadzone": 0.5,
40 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
41 | , null, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)
42 | ]
43 | }
44 |
45 | [physics]
46 |
47 | common/enable_pause_aware_picking=true
48 |
49 | [rendering]
50 |
51 | environment/default_environment="res://default_env.tres"
52 |
--------------------------------------------------------------------------------