Merge pull request #445 from aaronfranke/kc2d
Organize and simplify the Kinematic Character 2D demo
@@ -1,4 +1,4 @@
|
||||
# Kinematic Character
|
||||
# Kinematic Character 2D
|
||||
|
||||
Example of how to make a kinematic character controller in 2D using
|
||||
[`KinematicBody2D`](https://docs.godotengine.org/en/latest/classes/class_kinematicbody2d.html).
|
||||
|
||||
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
@@ -2,15 +2,15 @@
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/circle.png-10953cad44a8947fbdd4128a631e9e52.stex"
|
||||
path="res://.import/circle.png-65a28e998f412b3cddff971e28b7d768.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://circle.png"
|
||||
dest_files=[ "res://.import/circle.png-10953cad44a8947fbdd4128a631e9e52.stex" ]
|
||||
source_file="res://level/circle.png"
|
||||
dest_files=[ "res://.import/circle.png-65a28e998f412b3cddff971e28b7d768.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 480 B After Width: | Height: | Size: 480 B |
@@ -2,15 +2,15 @@
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/long_obstacle.png-1b33440a15b4db156b2a9ec7e9a2a80e.stex"
|
||||
path="res://.import/long_obstacle.png-d70ee394f796e1de9a423783aa84ec5d.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://long_obstacle.png"
|
||||
dest_files=[ "res://.import/long_obstacle.png-1b33440a15b4db156b2a9ec7e9a2a80e.stex" ]
|
||||
source_file="res://level/long_obstacle.png"
|
||||
dest_files=[ "res://.import/long_obstacle.png-d70ee394f796e1de9a423783aa84ec5d.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 468 B After Width: | Height: | Size: 468 B |
@@ -2,15 +2,15 @@
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/obstacle.png-dfb3e99d3af573251007cdf5e1c252b9.stex"
|
||||
path="res://.import/obstacle.png-06287f6b2d26dd03335fd87ab78c2cc2.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://obstacle.png"
|
||||
dest_files=[ "res://.import/obstacle.png-dfb3e99d3af573251007cdf5e1c252b9.stex" ]
|
||||
source_file="res://level/obstacle.png"
|
||||
dest_files=[ "res://.import/obstacle.png-06287f6b2d26dd03335fd87ab78c2cc2.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
5
2d/kinematic_character/level/princess.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends Node
|
||||
|
||||
func _on_body_entered(body):
|
||||
if body.name == "Player":
|
||||
$"../WinText".show()
|
||||
|
Before Width: | Height: | Size: 495 B After Width: | Height: | Size: 495 B |
@@ -2,15 +2,15 @@
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/princess.png-9b4caf2cfe324ae3734249d5b559d39d.stex"
|
||||
path="res://.import/princess.png-359cb1d8a4fd115119b22ac7899e2787.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://princess.png"
|
||||
dest_files=[ "res://.import/princess.png-9b4caf2cfe324ae3734249d5b559d39d.stex" ]
|
||||
source_file="res://level/princess.png"
|
||||
dest_files=[ "res://.import/princess.png-359cb1d8a4fd115119b22ac7899e2787.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
# Angle in degrees towards either side that the player can consider "floor".
|
||||
const FLOOR_ANGLE_TOLERANCE = 40
|
||||
const WALK_FORCE = 600
|
||||
const WALK_MIN_SPEED = 10
|
||||
const WALK_MAX_SPEED = 200
|
||||
const STOP_FORCE = 1300
|
||||
const JUMP_SPEED = 200
|
||||
const JUMP_MAX_AIRBORNE_TIME = 0.2
|
||||
|
||||
const SLIDE_STOP_VELOCITY = 1.0 # Pixels/second
|
||||
const SLIDE_STOP_MIN_TRAVEL = 1.0 # Pixels
|
||||
|
||||
var velocity = Vector2()
|
||||
var on_air_time = 100
|
||||
var jumping = false
|
||||
var prev_jump_pressed = false
|
||||
|
||||
onready var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
|
||||
|
||||
func _physics_process(delta):
|
||||
var force = Vector2(0, gravity)
|
||||
var walk = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
|
||||
var jump = Input.is_action_pressed("jump")
|
||||
|
||||
if (velocity.x <= WALK_MIN_SPEED and velocity.x > -WALK_MAX_SPEED) or (velocity.x >= -WALK_MIN_SPEED and velocity.x < WALK_MAX_SPEED):
|
||||
force.x += WALK_FORCE * walk
|
||||
|
||||
if abs(walk) < 0.5:
|
||||
var vsign = sign(velocity.x)
|
||||
var vlen = abs(velocity.x)
|
||||
vlen -= STOP_FORCE * delta
|
||||
if vlen < 0:
|
||||
vlen = 0
|
||||
velocity.x = vlen * vsign
|
||||
|
||||
# Integrate forces to velocity.
|
||||
velocity += force * delta
|
||||
# Integrate velocity into motion and move.
|
||||
velocity = move_and_slide(velocity, Vector2.UP)
|
||||
|
||||
if is_on_floor():
|
||||
on_air_time = 0
|
||||
|
||||
if jumping and velocity.y > 0:
|
||||
# If falling, no longer jumping.
|
||||
jumping = false
|
||||
|
||||
if on_air_time < JUMP_MAX_AIRBORNE_TIME and jump and not prev_jump_pressed and not jumping:
|
||||
# Jump must also be allowed to happen if the character left the floor a little bit ago.
|
||||
# Makes controls more snappy.
|
||||
velocity.y = -JUMP_SPEED
|
||||
jumping = true
|
||||
|
||||
on_air_time += delta
|
||||
prev_jump_pressed = jump
|
||||
32
2d/kinematic_character/player/player.gd
Normal file
@@ -0,0 +1,32 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
const WALK_FORCE = 600
|
||||
const WALK_MAX_SPEED = 200
|
||||
const STOP_FORCE = 1300
|
||||
const JUMP_SPEED = 200
|
||||
|
||||
var velocity = Vector2()
|
||||
|
||||
onready var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
|
||||
|
||||
func _physics_process(delta):
|
||||
# Horizontal movement code. First, get the player's input.
|
||||
var walk = WALK_FORCE * (Input.get_action_strength("move_right") - Input.get_action_strength("move_left"))
|
||||
# Slow down the player if they're not trying to move.
|
||||
if abs(walk) < WALK_FORCE * 0.2:
|
||||
# The velocity, slowed down a bit, and then reassigned.
|
||||
velocity.x = move_toward(velocity.x, 0, STOP_FORCE * delta)
|
||||
else:
|
||||
velocity.x += walk * delta
|
||||
# Clamp to the maximum horizontal movement speed.
|
||||
velocity.x = clamp(velocity.x, -WALK_MAX_SPEED, WALK_MAX_SPEED)
|
||||
|
||||
# Vertical movement code. Apply gravity.
|
||||
velocity.y += gravity * delta
|
||||
|
||||
# Move based on the velocity and snap to the ground.
|
||||
velocity = move_and_slide_with_snap(velocity, Vector2.DOWN, Vector2.UP)
|
||||
|
||||
# Check for jumping. is_on_floor() must be called after movement code.
|
||||
if is_on_floor() and Input.is_action_just_pressed("jump"):
|
||||
velocity.y = -JUMP_SPEED
|
||||
|
Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 502 B |
@@ -2,15 +2,15 @@
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/player.png-2dd0af52de4b213777cd8c9df94c0978.stex"
|
||||
path="res://.import/player.png-1ad27fc2a62fa126eae918723933dd6f.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://player.png"
|
||||
dest_files=[ "res://.import/player.png-2dd0af52de4b213777cd8c9df94c0978.stex" ]
|
||||
source_file="res://player/player.png"
|
||||
dest_files=[ "res://.import/player.png-1ad27fc2a62fa126eae918723933dd6f.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://player.gd" type="Script" id=1]
|
||||
[ext_resource path="res://player.png" type="Texture" id=2]
|
||||
[ext_resource path="res://player/player.gd" type="Script" id=1]
|
||||
[ext_resource path="res://player/player.png" type="Texture" id=2]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=1]
|
||||
extents = Vector2( 7, 7 )
|
||||
@@ -15,7 +15,7 @@ _global_script_class_icons={
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Kinematic Character"
|
||||
config/name="Kinematic Character 2D"
|
||||
run/main_scene="res://world.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
extends Node2D
|
||||
|
||||
func _on_princess_body_enter(body):
|
||||
# The name of this editor-generated callback is unfortunate.
|
||||
if body.get_name() == "Player":
|
||||
$WinText.show()
|
||||
@@ -1,11 +1,11 @@
|
||||
[gd_scene load_steps=19 format=2]
|
||||
|
||||
[ext_resource path="res://world.gd" type="Script" id=1]
|
||||
[ext_resource path="res://obstacle.png" type="Texture" id=2]
|
||||
[ext_resource path="res://player.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://princess.png" type="Texture" id=4]
|
||||
[ext_resource path="res://circle.png" type="Texture" id=5]
|
||||
[ext_resource path="res://long_obstacle.png" type="Texture" id=6]
|
||||
[ext_resource path="res://level/obstacle.png" type="Texture" id=2]
|
||||
[ext_resource path="res://player/player.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://level/princess.png" type="Texture" id=4]
|
||||
[ext_resource path="res://level/circle.png" type="Texture" id=5]
|
||||
[ext_resource path="res://level/long_obstacle.png" type="Texture" id=6]
|
||||
[ext_resource path="res://level/princess.gd" type="Script" id=7]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=1]
|
||||
extents = Vector2( 8, 8 )
|
||||
@@ -19,6 +19,11 @@ extents = Vector2( 8, 8 )
|
||||
0/tile_mode = 0
|
||||
0/occluder_offset = Vector2( 0, 0 )
|
||||
0/navigation_offset = Vector2( 0, 0 )
|
||||
0/shape_offset = Vector2( 8, 8 )
|
||||
0/shape_transform = Transform2D( 1, 0, 0, 1, 8, 8 )
|
||||
0/shape = SubResource( 1 )
|
||||
0/shape_one_way = false
|
||||
0/shape_one_way_margin = 1.0
|
||||
0/shapes = [ {
|
||||
"autotile_coord": Vector2( 0, 0 ),
|
||||
"one_way": false,
|
||||
@@ -112,7 +117,6 @@ extents = Vector2( 8, 8 )
|
||||
extents = Vector2( 32, 8 )
|
||||
|
||||
[node name="World" type="Node2D"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="TileMap" type="TileMap" parent="."]
|
||||
tile_set = SubResource( 2 )
|
||||
@@ -154,6 +158,7 @@ anims/updown = SubResource( 6 )
|
||||
|
||||
[node name="Princess" type="Area2D" parent="."]
|
||||
position = Vector2( 97, 72 )
|
||||
script = ExtResource( 7 )
|
||||
|
||||
[node name="Collision" type="CollisionShape2D" parent="Princess"]
|
||||
shape = SubResource( 7 )
|
||||
@@ -261,4 +266,4 @@ shape = SubResource( 12 )
|
||||
[node name="Camera2D" type="Camera2D" parent="."]
|
||||
offset = Vector2( 265, 247 )
|
||||
current = true
|
||||
[connection signal="body_entered" from="Princess" to="." method="_on_princess_body_enter"]
|
||||
[connection signal="body_entered" from="Princess" to="Princess" method="_on_body_entered"]
|
||||
|
||||
@@ -14,7 +14,7 @@ onready var gun = $Sprite/Gun
|
||||
|
||||
|
||||
func _ready():
|
||||
# Static types are necessary to avoid
|
||||
# Static types are necessary here to avoid warnings.
|
||||
var camera: Camera2D = $Camera
|
||||
if action_suffix == "_p1":
|
||||
camera.custom_viewport = $"../.."
|
||||
|
||||