mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2026-01-08 17:00:08 +01:00
Add HFSM + pushdown automaton demo
This commit is contained in:
20
2d/finite_state_machine/Demo.tscn
Normal file
20
2d/finite_state_machine/Demo.tscn
Normal file
@@ -0,0 +1,20 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://player/Player.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://debug/StatesStackDiplayer.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://debug/ControlsPanel.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://debug/Explanations.tscn" type="PackedScene" id=4]
|
||||
|
||||
[node name="Demo" type="Node" index="0"]
|
||||
|
||||
[node name="Player" parent="." index="0" instance=ExtResource( 1 )]
|
||||
|
||||
[node name="StatesStackDiplayer" parent="." index="1" instance=ExtResource( 2 )]
|
||||
|
||||
[node name="ControlsPanel" parent="." index="2" instance=ExtResource( 3 )]
|
||||
|
||||
[node name="Explanations" parent="." index="3" instance=ExtResource( 4 )]
|
||||
|
||||
[connection signal="state_changed" from="Player" to="StatesStackDiplayer" method="_on_Player_state_changed"]
|
||||
|
||||
|
||||
3
2d/finite_state_machine/autoload/global_constants.gd
Normal file
3
2d/finite_state_machine/autoload/global_constants.gd
Normal file
@@ -0,0 +1,3 @@
|
||||
extends Node
|
||||
|
||||
enum STATUSES { STATUS_NONE, STATUS_INVINCIBLE, STATUS_POISONED, STATUS_STUNNED }
|
||||
77
2d/finite_state_machine/debug/ControlsPanel.tscn
Normal file
77
2d/finite_state_machine/debug/ControlsPanel.tscn
Normal file
@@ -0,0 +1,77 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://debug/top_level_ui.gd" type="Script" id=1]
|
||||
[ext_resource path="res://fonts/source_code_pro_explanations.tres" type="DynamicFont" id=2]
|
||||
|
||||
[node name="ControlsPanel" type="Panel" index="0"]
|
||||
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = -220.0
|
||||
margin_bottom = 170.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Keys" type="Label" parent="." index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = -10.0
|
||||
margin_bottom = -10.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 4
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
text = "Shoot:
|
||||
Attack:
|
||||
Stagger:
|
||||
Jump:
|
||||
Sprint:"
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "BBCode", "custom_fonts" ]
|
||||
|
||||
[node name="Keys2" type="Label" parent="." index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = -10.0
|
||||
margin_bottom = -10.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 4
|
||||
custom_fonts/font = ExtResource( 2 )
|
||||
text = "R
|
||||
F
|
||||
X
|
||||
Space
|
||||
Shift"
|
||||
align = 2
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "BBCode", "custom_fonts" ]
|
||||
|
||||
|
||||
59
2d/finite_state_machine/debug/Explanations.tscn
Normal file
59
2d/finite_state_machine/debug/Explanations.tscn
Normal file
@@ -0,0 +1,59 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://fonts/source_code_pro_explanations_bold.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://fonts/source_code_pro_explanations.tres" type="DynamicFont" id=2]
|
||||
[ext_resource path="res://debug/top_level_ui.gd" type="Script" id=3]
|
||||
|
||||
|
||||
[node name="Explanations" type="RichTextLabel"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = -370.0
|
||||
margin_right = -10.0
|
||||
margin_bottom = -730.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 4
|
||||
custom_fonts/bold_font = ExtResource( 1 )
|
||||
custom_fonts/normal_font = ExtResource( 2 )
|
||||
bbcode_enabled = true
|
||||
bbcode_text = "This example shows how to apply the State programming pattern in GDscript, including Hierarchical States, and a pushdown automaton.
|
||||
|
||||
States are common in games. You can use the pattern to:
|
||||
|
||||
1. Separate each behavior and transitions between behaviors, thus make scripts shorter and easier to manage
|
||||
2. Respect the Single Responsibility Principle. Each State object represents [b]one[/b] action
|
||||
3. Improve your code's structure. Look at the scene tree and FileSystem tab: without looking at the code, you'll know what the Player can or cannot do.
|
||||
|
||||
You can read more about States in the excellent [url=http://gameprogrammingpatterns.com/state.html]Game Programming Patterns ebook[/url]."
|
||||
visible_characters = -1
|
||||
percent_visible = 1.0
|
||||
meta_underlined = true
|
||||
tab_size = 4
|
||||
text = "This example shows how to apply the State programming pattern in GDscript, including Hierarchical States, and a pushdown automaton.
|
||||
|
||||
States are common in games. You can use the pattern to:
|
||||
|
||||
1. Separate each behavior and transitions between behaviors, thus make scripts shorter and easier to manage
|
||||
2. Respect the Single Responsibility Principle. Each State object represents one action
|
||||
3. Improve your code's structure. Look at the scene tree and FileSystem tab: without looking at the code, you'll know what the Player can or cannot do.
|
||||
|
||||
You can read more about States in the excellent Game Programming Patterns ebook."
|
||||
scroll_active = true
|
||||
scroll_following = false
|
||||
selection_enabled = false
|
||||
override_selected_font_color = false
|
||||
script = ExtResource( 3 )
|
||||
_sections_unfolded = [ "BBCode", "custom_fonts" ]
|
||||
__meta__ = {
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
|
||||
107
2d/finite_state_machine/debug/StatesStackDiplayer.tscn
Normal file
107
2d/finite_state_machine/debug/StatesStackDiplayer.tscn
Normal file
@@ -0,0 +1,107 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://debug/states-stack-displayer.gd" type="Script" id=1]
|
||||
[ext_resource path="res://fonts/SourceCodePro-Bold.ttf" type="DynamicFontData" id=2]
|
||||
|
||||
[sub_resource type="DynamicFont" id=1]
|
||||
|
||||
size = 20
|
||||
use_mipmaps = false
|
||||
use_filter = true
|
||||
font_data = ExtResource( 2 )
|
||||
_sections_unfolded = [ "Font", "Settings" ]
|
||||
|
||||
[node name="StatesStackDiplayer" type="Panel"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 210.0
|
||||
margin_bottom = 170.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
}
|
||||
|
||||
[node name="Title" type="Label" parent="." index="0"]
|
||||
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.0
|
||||
margin_left = -105.0
|
||||
margin_right = 105.0
|
||||
margin_bottom = 40.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 4
|
||||
custom_fonts/font = SubResource( 1 )
|
||||
text = "Pushown"
|
||||
align = 1
|
||||
valign = 1
|
||||
uppercase = true
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "custom_fonts" ]
|
||||
|
||||
[node name="States" type="Label" parent="." index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 20.0
|
||||
margin_top = 50.0
|
||||
margin_right = 190.0
|
||||
margin_bottom = 170.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 4
|
||||
custom_fonts/font = SubResource( 1 )
|
||||
text = "Jump
|
||||
Test"
|
||||
align = 1
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "custom_fonts" ]
|
||||
|
||||
[node name="Numbers" type="Label" parent="." index="2"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 20.0
|
||||
margin_top = 50.0
|
||||
margin_right = 190.0
|
||||
margin_bottom = 170.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 4
|
||||
custom_fonts/font = SubResource( 1 )
|
||||
text = "1.
|
||||
2."
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "custom_fonts" ]
|
||||
|
||||
|
||||
18
2d/finite_state_machine/debug/states-stack-displayer.gd
Normal file
18
2d/finite_state_machine/debug/states-stack-displayer.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
tool
|
||||
extends Panel
|
||||
|
||||
func _ready():
|
||||
set_as_toplevel(true)
|
||||
|
||||
func _on_Player_state_changed(states_stack):
|
||||
var states_names = ''
|
||||
var numbers = ''
|
||||
var index = 0
|
||||
for state in states_stack:
|
||||
states_names += state.get_name() + '\n'
|
||||
numbers += str(index) + '\n'
|
||||
index += 1
|
||||
|
||||
$States.text = states_names
|
||||
$Numbers.text = numbers
|
||||
|
||||
5
2d/finite_state_machine/debug/top_level_ui.gd
Normal file
5
2d/finite_state_machine/debug/top_level_ui.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
func _ready():
|
||||
set_as_toplevel(true)
|
||||
101
2d/finite_state_machine/default_env.tres
Normal file
101
2d/finite_state_machine/default_env.tres
Normal file
@@ -0,0 +1,101 @@
|
||||
[gd_resource type="Environment" load_steps=2 format=2]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
radiance_size = 4
|
||||
sky_top_color = Color( 0.0470588, 0.454902, 0.976471, 1 )
|
||||
sky_horizon_color = Color( 0.556863, 0.823529, 0.909804, 1 )
|
||||
sky_curve = 0.25
|
||||
sky_energy = 1.0
|
||||
ground_bottom_color = Color( 0.101961, 0.145098, 0.188235, 1 )
|
||||
ground_horizon_color = Color( 0.482353, 0.788235, 0.952941, 1 )
|
||||
ground_curve = 0.01
|
||||
ground_energy = 1.0
|
||||
sun_color = Color( 1, 1, 1, 1 )
|
||||
sun_latitude = 35.0
|
||||
sun_longitude = 0.0
|
||||
sun_angle_min = 1.0
|
||||
sun_angle_max = 100.0
|
||||
sun_curve = 0.05
|
||||
sun_energy = 16.0
|
||||
texture_size = 2
|
||||
|
||||
[resource]
|
||||
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
||||
background_sky_custom_fov = 0.0
|
||||
background_color = Color( 0, 0, 0, 1 )
|
||||
background_energy = 1.0
|
||||
background_canvas_max_layer = 0
|
||||
ambient_light_color = Color( 0, 0, 0, 1 )
|
||||
ambient_light_energy = 1.0
|
||||
ambient_light_sky_contribution = 1.0
|
||||
fog_enabled = false
|
||||
fog_color = Color( 0.5, 0.6, 0.7, 1 )
|
||||
fog_sun_color = Color( 1, 0.9, 0.7, 1 )
|
||||
fog_sun_amount = 0.0
|
||||
fog_depth_enabled = true
|
||||
fog_depth_begin = 10.0
|
||||
fog_depth_curve = 1.0
|
||||
fog_transmit_enabled = false
|
||||
fog_transmit_curve = 1.0
|
||||
fog_height_enabled = false
|
||||
fog_height_min = 0.0
|
||||
fog_height_max = 100.0
|
||||
fog_height_curve = 1.0
|
||||
tonemap_mode = 0
|
||||
tonemap_exposure = 1.0
|
||||
tonemap_white = 1.0
|
||||
auto_exposure_enabled = false
|
||||
auto_exposure_scale = 0.4
|
||||
auto_exposure_min_luma = 0.05
|
||||
auto_exposure_max_luma = 8.0
|
||||
auto_exposure_speed = 0.5
|
||||
ss_reflections_enabled = false
|
||||
ss_reflections_max_steps = 64
|
||||
ss_reflections_fade_in = 0.15
|
||||
ss_reflections_fade_out = 2.0
|
||||
ss_reflections_depth_tolerance = 0.2
|
||||
ss_reflections_roughness = true
|
||||
ssao_enabled = false
|
||||
ssao_radius = 1.0
|
||||
ssao_intensity = 1.0
|
||||
ssao_radius2 = 0.0
|
||||
ssao_intensity2 = 1.0
|
||||
ssao_bias = 0.01
|
||||
ssao_light_affect = 0.0
|
||||
ssao_color = Color( 0, 0, 0, 1 )
|
||||
ssao_quality = 0
|
||||
ssao_blur = 3
|
||||
ssao_edge_sharpness = 4.0
|
||||
dof_blur_far_enabled = false
|
||||
dof_blur_far_distance = 10.0
|
||||
dof_blur_far_transition = 5.0
|
||||
dof_blur_far_amount = 0.1
|
||||
dof_blur_far_quality = 1
|
||||
dof_blur_near_enabled = false
|
||||
dof_blur_near_distance = 2.0
|
||||
dof_blur_near_transition = 1.0
|
||||
dof_blur_near_amount = 0.1
|
||||
dof_blur_near_quality = 1
|
||||
glow_enabled = false
|
||||
glow_levels/1 = false
|
||||
glow_levels/2 = false
|
||||
glow_levels/3 = true
|
||||
glow_levels/4 = false
|
||||
glow_levels/5 = true
|
||||
glow_levels/6 = false
|
||||
glow_levels/7 = false
|
||||
glow_intensity = 0.8
|
||||
glow_strength = 1.0
|
||||
glow_bloom = 0.0
|
||||
glow_blend_mode = 2
|
||||
glow_hdr_threshold = 1.0
|
||||
glow_hdr_scale = 2.0
|
||||
glow_bicubic_upscale = false
|
||||
adjustment_enabled = false
|
||||
adjustment_brightness = 1.0
|
||||
adjustment_contrast = 1.0
|
||||
adjustment_saturation = 1.0
|
||||
|
||||
BIN
2d/finite_state_machine/fonts/SourceCodePro-Black.ttf
Normal file
BIN
2d/finite_state_machine/fonts/SourceCodePro-Black.ttf
Normal file
Binary file not shown.
BIN
2d/finite_state_machine/fonts/SourceCodePro-Bold.ttf
Normal file
BIN
2d/finite_state_machine/fonts/SourceCodePro-Bold.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://fonts/SourceCodePro-Bold.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
|
||||
size = 20
|
||||
use_mipmaps = false
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Font", "Settings" ]
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://fonts/SourceCodePro-Black.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
|
||||
size = 24
|
||||
use_mipmaps = false
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Font", "Settings" ]
|
||||
|
||||
BIN
2d/finite_state_machine/icon.png
Normal file
BIN
2d/finite_state_machine/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
32
2d/finite_state_machine/icon.png.import
Normal file
32
2d/finite_state_machine/icon.png.import
Normal file
@@ -0,0 +1,32 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
source_md5="66cdb591455c91e0e285218a159ee4a1"
|
||||
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||
dest_md5="302305b1ae85287055e65e5202170a74"
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
198
2d/finite_state_machine/player/Player.tscn
Normal file
198
2d/finite_state_machine/player/Player.tscn
Normal file
@@ -0,0 +1,198 @@
|
||||
[gd_scene load_steps=20 format=2]
|
||||
|
||||
[ext_resource path="res://player/state-machine.gd" type="Script" id=1]
|
||||
[ext_resource path="res://player/shadow.png" type="Texture" id=2]
|
||||
[ext_resource path="res://player/body.png" type="Texture" id=3]
|
||||
[ext_resource path="res://player/weapon/weapon_pivot.gd" type="Script" id=4]
|
||||
[ext_resource path="res://player/weapon/Sword.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://player/health/Health.tscn" type="PackedScene" id=6]
|
||||
[ext_resource path="res://player/states/motion/on_ground/idle.gd" type="Script" id=7]
|
||||
[ext_resource path="res://player/states/motion/on_ground/move.gd" type="Script" id=8]
|
||||
[ext_resource path="res://player/states/motion/in_air/jump.gd" type="Script" id=9]
|
||||
[ext_resource path="res://player/states/combat/stagger.gd" type="Script" id=10]
|
||||
[ext_resource path="res://player/states/combat/attack.gd" type="Script" id=11]
|
||||
[ext_resource path="res://player/states/die.gd" type="Script" id=12]
|
||||
[ext_resource path="res://player/bullet/bullet_spawner.gd" type="Script" id=13]
|
||||
[ext_resource path="res://fonts/SourceCodePro-Bold.ttf" type="DynamicFontData" id=14]
|
||||
[ext_resource path="res://player/states/debug/state-name-displayer.gd" type="Script" id=15]
|
||||
|
||||
|
||||
[sub_resource type="Animation" id=1]
|
||||
|
||||
length = 1.0
|
||||
loop = false
|
||||
step = 0.1
|
||||
|
||||
[sub_resource type="Animation" id=2]
|
||||
|
||||
length = 0.6
|
||||
loop = false
|
||||
step = 0.1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath("BodyPivot/Body:modulate")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.4 ),
|
||||
"transitions": PoolRealArray( 1, 1, 1, 1, 1, 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ Color( 1, 1, 1, 1 ), Color( 1, 0, 0, 1 ), Color( 1, 1, 1, 1 ), Color( 1, 0, 0, 1 ), Color( 1, 1, 1, 1 ), Color( 1, 0, 0, 1 ), Color( 1, 1, 1, 1 ) ]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id=3]
|
||||
|
||||
length = 1.0
|
||||
loop = false
|
||||
step = 0.1
|
||||
|
||||
[sub_resource type="DynamicFont" id=4]
|
||||
|
||||
size = 20
|
||||
use_mipmaps = false
|
||||
use_filter = true
|
||||
font_data = ExtResource( 14 )
|
||||
_sections_unfolded = [ "Font", "Settings" ]
|
||||
|
||||
[node name="Player" type="KinematicBody2D"]
|
||||
|
||||
position = Vector2( 628.826, 391.266 )
|
||||
input_pickable = false
|
||||
collision_layer = 1
|
||||
collision_mask = 1
|
||||
collision/safe_margin = 0.08
|
||||
script = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Visibility" ]
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ ]
|
||||
}
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." index="0"]
|
||||
|
||||
root_node = NodePath("..")
|
||||
autoplay = ""
|
||||
playback_process_mode = 1
|
||||
playback_default_blend_time = 0.0
|
||||
playback_speed = 1.0
|
||||
anims/idle = SubResource( 1 )
|
||||
anims/stagger = SubResource( 2 )
|
||||
anims/walk = SubResource( 3 )
|
||||
blend_times = [ ]
|
||||
|
||||
[node name="Shadow" type="Sprite" parent="." index="1"]
|
||||
|
||||
self_modulate = Color( 1, 1, 1, 0.361098 )
|
||||
position = Vector2( 0, -4 )
|
||||
texture = ExtResource( 2 )
|
||||
_sections_unfolded = [ "Visibility" ]
|
||||
|
||||
[node name="BodyPivot" type="Position2D" parent="." index="2"]
|
||||
|
||||
[node name="Body" type="Sprite" parent="BodyPivot" index="0"]
|
||||
|
||||
position = Vector2( 0, -58.8242 )
|
||||
texture = ExtResource( 3 )
|
||||
|
||||
[node name="WeaponPivot" type="Position2D" parent="." index="3"]
|
||||
|
||||
position = Vector2( 1.17401, -61.266 )
|
||||
script = ExtResource( 4 )
|
||||
|
||||
[node name="Offset" type="Position2D" parent="WeaponPivot" index="0"]
|
||||
|
||||
position = Vector2( 110, 0 )
|
||||
|
||||
[node name="Sword" parent="WeaponPivot/Offset" index="0" instance=ExtResource( 5 )]
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="." index="4"]
|
||||
|
||||
build_mode = 0
|
||||
polygon = PoolVector2Array( -20, 0, -20, -20, 20, -20, 20, 0 )
|
||||
|
||||
[node name="Health" parent="." index="5" instance=ExtResource( 6 )]
|
||||
|
||||
[node name="States" type="Node" parent="." index="6"]
|
||||
|
||||
[node name="Idle" type="Node" parent="States" index="0"]
|
||||
|
||||
script = ExtResource( 7 )
|
||||
|
||||
[node name="Move" type="Node" parent="States" index="1"]
|
||||
|
||||
script = ExtResource( 8 )
|
||||
MAX_WALK_SPEED = 450
|
||||
MAX_RUN_SPEED = 700
|
||||
|
||||
[node name="Jump" type="Node" parent="States" index="2"]
|
||||
|
||||
script = ExtResource( 9 )
|
||||
BASE_MAX_HORIZONTAL_SPEED = 400.0
|
||||
AIR_ACCELERATION = 1000.0
|
||||
AIR_DECCELERATION = 2000.0
|
||||
AIR_STEERING_POWER = 50.0
|
||||
JUMP_HEIGHT = 120.0
|
||||
JUMP_DURATION = 0.8
|
||||
GRAVITY = 1600.0
|
||||
|
||||
[node name="Stagger" type="Node" parent="States" index="3"]
|
||||
|
||||
script = ExtResource( 10 )
|
||||
|
||||
[node name="Attack" type="Node" parent="States" index="4"]
|
||||
|
||||
script = ExtResource( 11 )
|
||||
|
||||
[node name="Die" type="Node" parent="States" index="5"]
|
||||
|
||||
script = ExtResource( 12 )
|
||||
|
||||
[node name="BulletSpawn" type="Node2D" parent="." index="7"]
|
||||
|
||||
editor/display_folded = true
|
||||
position = Vector2( 1.17401, -61.266 )
|
||||
script = ExtResource( 13 )
|
||||
_sections_unfolded = [ "Transform" ]
|
||||
|
||||
[node name="CooldownTimer" type="Timer" parent="BulletSpawn" index="0"]
|
||||
|
||||
process_mode = 1
|
||||
wait_time = 0.2
|
||||
one_shot = true
|
||||
autostart = false
|
||||
|
||||
[node name="StateNameDisplayer" type="Label" parent="." index="8"]
|
||||
|
||||
editor/display_folded = true
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = -109.0
|
||||
margin_top = -172.0
|
||||
margin_right = 110.0
|
||||
margin_bottom = -138.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 4
|
||||
custom_fonts/font = SubResource( 4 )
|
||||
text = "Test"
|
||||
align = 1
|
||||
valign = 1
|
||||
uppercase = true
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
script = ExtResource( 15 )
|
||||
_sections_unfolded = [ "Rect", "custom_fonts" ]
|
||||
|
||||
[connection signal="state_changed" from="." to="StateNameDisplayer" method="_on_Player_state_changed"]
|
||||
|
||||
[connection signal="animation_finished" from="AnimationPlayer" to="." method="_on_animation_finished"]
|
||||
|
||||
[connection signal="attack_finished" from="WeaponPivot/Offset/Sword" to="States/Attack" method="_on_Sword_attack_finished"]
|
||||
|
||||
|
||||
BIN
2d/finite_state_machine/player/body.png
Normal file
BIN
2d/finite_state_machine/player/body.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
32
2d/finite_state_machine/player/body.png.import
Normal file
32
2d/finite_state_machine/player/body.png.import
Normal file
@@ -0,0 +1,32 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/body.png-313f6363670a5852a7b7126ab476d8b1.stex"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://player/body.png"
|
||||
source_md5="e76fc4b6b913ad7e09352eada55fc124"
|
||||
|
||||
dest_files=[ "res://.import/body.png-313f6363670a5852a7b7126ab476d8b1.stex" ]
|
||||
dest_md5="b65921b7af7d7cea3cb9567625d04d34"
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
25
2d/finite_state_machine/player/bullet/Bullet.tscn
Normal file
25
2d/finite_state_machine/player/bullet/Bullet.tscn
Normal file
@@ -0,0 +1,25 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://player/bullet/bullet.gd" type="Script" id=1]
|
||||
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
|
||||
custom_solver_bias = 0.0
|
||||
radius = 12.0
|
||||
|
||||
[node name="Bullet" type="KinematicBody2D"]
|
||||
|
||||
input_pickable = false
|
||||
collision_layer = 2
|
||||
collision_mask = 2
|
||||
collision/safe_margin = 0.08
|
||||
script = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Collision", "collision" ]
|
||||
SPEED = 1000.0
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." index="0"]
|
||||
|
||||
shape = SubResource( 1 )
|
||||
|
||||
|
||||
28
2d/finite_state_machine/player/bullet/bullet.gd
Normal file
28
2d/finite_state_machine/player/bullet/bullet.gd
Normal file
@@ -0,0 +1,28 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
|
||||
var direction = Vector2()
|
||||
export(float) var SPEED = 1000.0
|
||||
|
||||
|
||||
func _ready():
|
||||
set_as_toplevel(true)
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if is_outside_view_bounds():
|
||||
queue_free()
|
||||
|
||||
var motion = direction * SPEED * delta
|
||||
var collision_info = move_and_collide(motion)
|
||||
if collision_info:
|
||||
queue_free()
|
||||
|
||||
|
||||
func is_outside_view_bounds():
|
||||
return position.x > OS.get_screen_size().x or position.x < 0.0 \
|
||||
or position.y > OS.get_screen_size().y or position.y < 0.0
|
||||
|
||||
|
||||
func _draw():
|
||||
draw_circle(Vector2(), $CollisionShape2D.shape.radius, Color('#ffffff'))
|
||||
16
2d/finite_state_machine/player/bullet/bullet_spawner.gd
Normal file
16
2d/finite_state_machine/player/bullet/bullet_spawner.gd
Normal file
@@ -0,0 +1,16 @@
|
||||
extends Node2D
|
||||
|
||||
var bullet = preload("Bullet.tscn")
|
||||
|
||||
func fire(direction):
|
||||
if not $CooldownTimer.is_stopped():
|
||||
return
|
||||
|
||||
$CooldownTimer.start()
|
||||
var new_bullet = bullet.instance()
|
||||
new_bullet.direction = direction
|
||||
add_child(new_bullet)
|
||||
|
||||
|
||||
func update(host, delta):
|
||||
return 'previous'
|
||||
17
2d/finite_state_machine/player/health/Health.tscn
Normal file
17
2d/finite_state_machine/player/health/Health.tscn
Normal file
@@ -0,0 +1,17 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://player/health/health.gd" type="Script" id=1]
|
||||
|
||||
[node name="Health" type="Node"]
|
||||
|
||||
script = ExtResource( 1 )
|
||||
max_health = 9
|
||||
|
||||
[node name="PoisonTimer" type="Timer" parent="." index="0"]
|
||||
|
||||
process_mode = 1
|
||||
wait_time = 0.6
|
||||
one_shot = false
|
||||
autostart = false
|
||||
|
||||
|
||||
62
2d/finite_state_machine/player/health/health.gd
Normal file
62
2d/finite_state_machine/player/health/health.gd
Normal file
@@ -0,0 +1,62 @@
|
||||
extends Node
|
||||
|
||||
signal health_changed
|
||||
signal health_depleted
|
||||
signal status_changed
|
||||
|
||||
var health = 0
|
||||
export(int) var max_health = 9
|
||||
|
||||
var status = null
|
||||
const POISON_DAMAGE = 1
|
||||
var poison_cycles = 0
|
||||
|
||||
|
||||
func _ready():
|
||||
health = max_health
|
||||
$PoisonTimer.connect('timeout', self, '_on_PoisonTimer_timeout')
|
||||
|
||||
|
||||
func _change_status(new_status):
|
||||
match status:
|
||||
GlobalConstants.STATUS_POISONED:
|
||||
$PoisonTimer.stop()
|
||||
|
||||
match new_status:
|
||||
GlobalConstants.STATUS_POISONED:
|
||||
poison_cycles = 0
|
||||
$PoisonTimer.start()
|
||||
status = new_status
|
||||
emit_signal('status_changed', new_status)
|
||||
|
||||
|
||||
func take_damage(amount, effect=null):
|
||||
if status == GlobalConstants.STATUS_INVINCIBLE:
|
||||
return
|
||||
health -= amount
|
||||
health = max(0, health)
|
||||
emit_signal("health_changed", health)
|
||||
|
||||
if not effect:
|
||||
return
|
||||
match effect[0]:
|
||||
GlobalConstants.STATUS_POISONED:
|
||||
_change_status(GlobalConstants.STATUS_POISONED)
|
||||
poison_cycles = effect[1]
|
||||
# print("%s got hit and took %s damage. Health: %s/%s" % [get_name(), amount, health, max_health])
|
||||
|
||||
|
||||
func heal(amount):
|
||||
health += amount
|
||||
health = max(health, max_health)
|
||||
emit_signal("health_changed", health)
|
||||
# print("%s got healed by %s points. Health: %s/%s" % [get_name(), amount, health, max_health])
|
||||
|
||||
|
||||
func _on_PoisonTimer_timeout():
|
||||
take_damage(POISON_DAMAGE)
|
||||
poison_cycles -= 1
|
||||
if poison_cycles == 0:
|
||||
_change_status(GlobalConstants.STATUS_NONE)
|
||||
return
|
||||
$PoisonTimer.start()
|
||||
BIN
2d/finite_state_machine/player/shadow.png
Normal file
BIN
2d/finite_state_machine/player/shadow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 967 B |
32
2d/finite_state_machine/player/shadow.png.import
Normal file
32
2d/finite_state_machine/player/shadow.png.import
Normal file
@@ -0,0 +1,32 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/shadow.png-493c4635eca1ce8bdece629560617dc7.stex"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://player/shadow.png"
|
||||
source_md5="ba1c3f4ef3a93dcd980bc4d020c4a22c"
|
||||
|
||||
dest_files=[ "res://.import/shadow.png-493c4635eca1ce8bdece629560617dc7.stex" ]
|
||||
dest_md5="7dd3fb33b53c00ce76edd77833bce15d"
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
60
2d/finite_state_machine/player/state-machine-bad-use.gd
Normal file
60
2d/finite_state_machine/player/state-machine-bad-use.gd
Normal file
@@ -0,0 +1,60 @@
|
||||
extends KinematicBody2D
|
||||
|
||||
signal state_changed
|
||||
|
||||
var look_direction = Vector2()
|
||||
|
||||
var current_state = null
|
||||
var states_stack = []
|
||||
|
||||
onready var states_map = {
|
||||
'idle': $States/Idle,
|
||||
'move': $States/Move,
|
||||
'jump': $States/Jump,
|
||||
'shoot': $States/Shoot,
|
||||
}
|
||||
|
||||
func _ready():
|
||||
states_stack.push_front($States/Idle)
|
||||
current_state = states_stack[0]
|
||||
_change_state('idle')
|
||||
|
||||
|
||||
# Delegate the call to the state
|
||||
func _physics_process(delta):
|
||||
var new_state = current_state.update(self, delta)
|
||||
if new_state:
|
||||
_change_state(new_state)
|
||||
|
||||
|
||||
func _input(event):
|
||||
var new_state = current_state.handle_input(self, event)
|
||||
if new_state:
|
||||
_change_state(new_state)
|
||||
|
||||
|
||||
# Exit the current state, change it and enter the new one
|
||||
func _change_state(state_name):
|
||||
# The pushdown mechanism isn't very useful in this example.
|
||||
# If the player stops moving mid-air Jump will still return to move
|
||||
# print('Exiting %s and enterig %s' % [current_state.get_name(), new_state.get_name()])
|
||||
current_state.exit(self)
|
||||
|
||||
# removing state previously pushed on the stack
|
||||
if state_name == 'previous':
|
||||
states_stack.pop_front()
|
||||
elif state_name in ['jump', 'shoot']:
|
||||
states_stack.push_front(states_map[state_name])
|
||||
if state_name == 'jump':
|
||||
$States/Jump.initialize(current_state.speed, current_state.velocity)
|
||||
else:
|
||||
# pushing new state on to the stack
|
||||
var new_state = states_map[state_name]
|
||||
states_stack[0] = new_state
|
||||
|
||||
# We only reinitialize the state when we don't use the pushdown automaton
|
||||
if state_name != 'previous':
|
||||
current_state.enter(self)
|
||||
|
||||
current_state = states_stack[0]
|
||||
emit_signal('state_changed', current_state.get_name())
|
||||
133
2d/finite_state_machine/player/state-machine.gd
Normal file
133
2d/finite_state_machine/player/state-machine.gd
Normal file
@@ -0,0 +1,133 @@
|
||||
"""
|
||||
The point of the State pattern is to separate concerns, to help follow
|
||||
the single responsibility principle. Each state describes an action or
|
||||
behavior.
|
||||
|
||||
The state machine is the only entity that"s aware of the states.
|
||||
That"s why this script receives strings from the states: it maps
|
||||
these strings to actual state objects: the states (Move, Jump, etc.)
|
||||
are not aware of their siblings. This way you can change any of
|
||||
the states anytime without breaking the game.
|
||||
"""
|
||||
extends KinematicBody2D
|
||||
|
||||
signal state_changed
|
||||
signal direction_changed(new_direction)
|
||||
|
||||
var look_direction = Vector2(1, 0) setget set_look_direction
|
||||
|
||||
|
||||
"""
|
||||
This example keeps a history of some states so e.g. after taking a hit,
|
||||
the character can return to the previous state. The states_stack is
|
||||
an Array, and we use Array.push_front() and Array.pop_front() to add and
|
||||
remove states from the history.
|
||||
"""
|
||||
var states_stack = []
|
||||
var current_state = null
|
||||
|
||||
onready var states_map = {
|
||||
"idle": $States/Idle,
|
||||
"move": $States/Move,
|
||||
"jump": $States/Jump,
|
||||
"stagger": $States/Stagger,
|
||||
"attack": $States/Attack,
|
||||
}
|
||||
|
||||
func _ready():
|
||||
for state_node in $States.get_children():
|
||||
state_node.connect("finished", self, "_change_state")
|
||||
|
||||
states_stack.push_front($States/Idle)
|
||||
current_state = states_stack[0]
|
||||
_change_state("idle")
|
||||
|
||||
|
||||
# The state machine delegates process and input callbacks to the current state
|
||||
# The state object, e.g. Move, then handles input, calculates velocity
|
||||
# and moves what I called its "host", the Player node (KinematicBody2D) in this case.
|
||||
func _physics_process(delta):
|
||||
current_state.update(self, delta)
|
||||
|
||||
|
||||
func _input(event):
|
||||
"""
|
||||
If you make a shooter game, you may want the player to be able to
|
||||
fire bullets anytime.
|
||||
If that"s the case you don"t want to use the states. They"ll add micro
|
||||
freezes in the gameplay and/or make your code more complex
|
||||
Firing is the weapon"s responsibility (BulletSpawn here) so the weapon should handle it
|
||||
"""
|
||||
if event.is_action_pressed("fire"):
|
||||
$BulletSpawn.fire(look_direction)
|
||||
return
|
||||
elif event.is_action_pressed("attack"):
|
||||
if current_state == $States/Attack:
|
||||
return
|
||||
_change_state("attack")
|
||||
return
|
||||
current_state.handle_input(self, event)
|
||||
|
||||
|
||||
func _on_animation_finished(anim_name):
|
||||
"""
|
||||
We want to delegate every method or callback that could trigger
|
||||
a state change to the state objects. The base script state.gd,
|
||||
that all states extend, makes sure that all states have the same
|
||||
interface, that is to say access to the same base methods, including
|
||||
_on_animation_finished. See state.gd
|
||||
"""
|
||||
current_state._on_animation_finished(anim_name)
|
||||
|
||||
|
||||
func _change_state(state_name):
|
||||
"""
|
||||
We use this method to:
|
||||
1. Clean up the current state with its the exit method
|
||||
2. Manage the flow and the history of states
|
||||
3. Initialize the new state with its enter method
|
||||
Note that to go back to the previous state in the states history,
|
||||
the state objects return the "previous" keyword and not a specific
|
||||
state name.
|
||||
"""
|
||||
current_state.exit(self)
|
||||
|
||||
if state_name == "previous":
|
||||
states_stack.pop_front()
|
||||
elif state_name in ["stagger", "jump", "attack"]:
|
||||
states_stack.push_front(states_map[state_name])
|
||||
elif state_name == "dead":
|
||||
queue_free()
|
||||
return
|
||||
else:
|
||||
var new_state = states_map[state_name]
|
||||
states_stack[0] = new_state
|
||||
|
||||
if state_name == "attack":
|
||||
$WeaponPivot/Offset/Sword.attack()
|
||||
if state_name == "jump":
|
||||
$States/Jump.initialize(current_state.speed, current_state.velocity)
|
||||
|
||||
current_state = states_stack[0]
|
||||
if state_name != "previous":
|
||||
# We don"t want to reinitialize the state if we"re going back to the previous state
|
||||
current_state.enter(self)
|
||||
emit_signal("state_changed", states_stack)
|
||||
|
||||
|
||||
func take_damage(attacker, amount, effect=null):
|
||||
if self.is_a_parent_of(attacker):
|
||||
return
|
||||
$States/Stagger.knockback_direction = (attacker.global_position - global_position).normalized()
|
||||
$Health.take_damage(amount, effect)
|
||||
|
||||
|
||||
func set_dead(value):
|
||||
set_process_input(not value)
|
||||
set_physics_process(not value)
|
||||
$CollisionPolygon2D.disabled = value
|
||||
|
||||
|
||||
func set_look_direction(value):
|
||||
look_direction = value
|
||||
emit_signal("direction_changed", value)
|
||||
14
2d/finite_state_machine/player/states/combat/attack.gd
Normal file
14
2d/finite_state_machine/player/states/combat/attack.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
The stagger state end with the stagger animation from the AnimationPlayer
|
||||
The animation only affects the Body Sprite"s modulate property so
|
||||
it could stack with other animations if we had two AnimationPlayer nodes
|
||||
"""
|
||||
extends "../state.gd"
|
||||
|
||||
|
||||
func enter(host):
|
||||
host.get_node("AnimationPlayer").play("idle")
|
||||
|
||||
|
||||
func _on_Sword_attack_finished():
|
||||
emit_signal("finished", "previous")
|
||||
16
2d/finite_state_machine/player/states/combat/stagger.gd
Normal file
16
2d/finite_state_machine/player/states/combat/stagger.gd
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
The stagger state end with the stagger animation from the AnimationPlayer
|
||||
The animation only affects the Body Sprite"s modulate property so
|
||||
it could stack with other animations if we had two AnimationPlayer nodes
|
||||
"""
|
||||
extends "../state.gd"
|
||||
|
||||
var knockback_direction = Vector2()
|
||||
|
||||
func enter(host):
|
||||
host.get_node("AnimationPlayer").play("stagger")
|
||||
|
||||
|
||||
func _on_animation_finished(anim_name):
|
||||
assert anim_name == "stagger"
|
||||
emit_signal("finished", "previous")
|
||||
@@ -0,0 +1,12 @@
|
||||
extends Label
|
||||
|
||||
var start_position = Vector2()
|
||||
|
||||
func _ready():
|
||||
start_position = rect_position
|
||||
|
||||
func _physics_process(delta):
|
||||
rect_position = $"../BodyPivot".position + start_position
|
||||
|
||||
func _on_Player_state_changed(states_stack):
|
||||
text = states_stack[0].get_name()
|
||||
10
2d/finite_state_machine/player/states/die.gd
Normal file
10
2d/finite_state_machine/player/states/die.gd
Normal file
@@ -0,0 +1,10 @@
|
||||
extends "state.gd"
|
||||
|
||||
|
||||
# Initialize the state. E.g. change the animation
|
||||
func enter(host):
|
||||
host.set_dead(true)
|
||||
host.get_node("AnimationPlayer").play("die")
|
||||
|
||||
func _on_animation_finished(anim_name):
|
||||
emit_signal("finished", "dead")
|
||||
70
2d/finite_state_machine/player/states/motion/in_air/jump.gd
Normal file
70
2d/finite_state_machine/player/states/motion/in_air/jump.gd
Normal file
@@ -0,0 +1,70 @@
|
||||
extends "../motion.gd"
|
||||
|
||||
export(float) var BASE_MAX_HORIZONTAL_SPEED = 400.0
|
||||
|
||||
export(float) var AIR_ACCELERATION = 1000.0
|
||||
export(float) var AIR_DECCELERATION = 2000.0
|
||||
export(float) var AIR_STEERING_POWER = 50.0
|
||||
|
||||
export(float) var JUMP_HEIGHT = 120.0
|
||||
export(float) var JUMP_DURATION = 0.8
|
||||
|
||||
export(float) var GRAVITY = 1600.0
|
||||
|
||||
|
||||
var enter_velocity = Vector2()
|
||||
|
||||
var max_horizontal_speed = 0.0
|
||||
var horizontal_speed = 0.0
|
||||
var horizontal_velocity = Vector2()
|
||||
|
||||
var vertical_speed = 0.0
|
||||
var height = 0.0
|
||||
|
||||
|
||||
func initialize(speed, velocity):
|
||||
horizontal_speed = speed
|
||||
max_horizontal_speed = speed if speed > 0.0 else BASE_MAX_HORIZONTAL_SPEED
|
||||
enter_velocity = velocity
|
||||
|
||||
|
||||
func enter(host):
|
||||
var input_direction = get_input_direction()
|
||||
update_look_direction(host, input_direction)
|
||||
|
||||
horizontal_velocity = enter_velocity if input_direction else Vector2()
|
||||
vertical_speed = 600.0
|
||||
|
||||
host.get_node("AnimationPlayer").play("idle")
|
||||
|
||||
|
||||
func update(host, delta):
|
||||
var input_direction = get_input_direction()
|
||||
update_look_direction(host, input_direction)
|
||||
|
||||
move_horizontally(host, delta, input_direction)
|
||||
animate_jump_height(host, delta)
|
||||
if height <= 0.0:
|
||||
emit_signal("finished", "previous")
|
||||
|
||||
|
||||
func move_horizontally(host, delta, direction):
|
||||
if direction:
|
||||
horizontal_speed += AIR_ACCELERATION * delta
|
||||
else:
|
||||
horizontal_speed -= AIR_DECCELERATION * delta
|
||||
horizontal_speed = clamp(horizontal_speed, 0, max_horizontal_speed)
|
||||
|
||||
var target_velocity = horizontal_speed * direction.normalized()
|
||||
var steering_velocity = (target_velocity - horizontal_velocity).normalized() * AIR_STEERING_POWER
|
||||
horizontal_velocity += steering_velocity
|
||||
|
||||
host.move_and_slide(horizontal_velocity)
|
||||
|
||||
|
||||
func animate_jump_height(host, delta):
|
||||
vertical_speed -= GRAVITY * delta
|
||||
height += vertical_speed * delta
|
||||
height = max(0.0, height)
|
||||
|
||||
host.get_node("BodyPivot").position.y = -height
|
||||
22
2d/finite_state_machine/player/states/motion/motion.gd
Normal file
22
2d/finite_state_machine/player/states/motion/motion.gd
Normal file
@@ -0,0 +1,22 @@
|
||||
# Collection of important methods to handle direction and animation
|
||||
extends "../state.gd"
|
||||
|
||||
|
||||
func handle_input(host, event):
|
||||
if event.is_action_pressed("simulate_damage"):
|
||||
emit_signal("finished", "stagger")
|
||||
|
||||
|
||||
func get_input_direction():
|
||||
var input_direction = Vector2()
|
||||
input_direction.x = int(Input.is_action_pressed("move_right")) - int(Input.is_action_pressed("move_left"))
|
||||
input_direction.y = int(Input.is_action_pressed("move_down")) - int(Input.is_action_pressed("move_up"))
|
||||
return input_direction
|
||||
|
||||
|
||||
func update_look_direction(host, direction):
|
||||
if direction and host.look_direction != direction:
|
||||
host.look_direction = direction
|
||||
if not direction.x in [-1, 1]:
|
||||
return
|
||||
host.get_node("BodyPivot").set_scale(Vector2(direction.x, 1))
|
||||
@@ -0,0 +1,14 @@
|
||||
extends "on_ground.gd"
|
||||
|
||||
func enter(host):
|
||||
host.get_node("AnimationPlayer").play("idle")
|
||||
|
||||
|
||||
func handle_input(host, event):
|
||||
return .handle_input(host, event)
|
||||
|
||||
|
||||
func update(host, delta):
|
||||
var input_direction = get_input_direction()
|
||||
if input_direction:
|
||||
emit_signal("finished", "move")
|
||||
@@ -0,0 +1,38 @@
|
||||
extends "on_ground.gd"
|
||||
|
||||
export(float) var MAX_WALK_SPEED = 450
|
||||
export(float) var MAX_RUN_SPEED = 700
|
||||
|
||||
func enter(host):
|
||||
speed = 0.0
|
||||
velocity = Vector2()
|
||||
|
||||
var input_direction = get_input_direction()
|
||||
update_look_direction(host, input_direction)
|
||||
host.get_node("AnimationPlayer").play("walk")
|
||||
|
||||
|
||||
func handle_input(host, event):
|
||||
return .handle_input(host, event)
|
||||
|
||||
|
||||
func update(host, delta):
|
||||
var input_direction = get_input_direction()
|
||||
if not input_direction:
|
||||
emit_signal("finished", "idle")
|
||||
update_look_direction(host, input_direction)
|
||||
|
||||
speed = MAX_RUN_SPEED if Input.is_action_pressed("run") else MAX_WALK_SPEED
|
||||
var collision_info = move(host, speed, input_direction)
|
||||
if not collision_info:
|
||||
return
|
||||
if speed == MAX_RUN_SPEED and collision_info.collider.is_in_group("environment"):
|
||||
return null
|
||||
|
||||
|
||||
func move(host, speed, direction):
|
||||
velocity = direction.normalized() * speed
|
||||
host.move_and_slide(velocity, Vector2(), 5, 2)
|
||||
if host.get_slide_count() == 0:
|
||||
return
|
||||
return host.get_slide_collision(0)
|
||||
@@ -0,0 +1,9 @@
|
||||
extends "../motion.gd"
|
||||
|
||||
var speed = 0.0
|
||||
var velocity = Vector2()
|
||||
|
||||
func handle_input(host, event):
|
||||
if event.is_action_pressed("jump"):
|
||||
emit_signal("finished", "jump")
|
||||
return .handle_input(host, event)
|
||||
29
2d/finite_state_machine/player/states/state.gd
Normal file
29
2d/finite_state_machine/player/states/state.gd
Normal file
@@ -0,0 +1,29 @@
|
||||
"""
|
||||
Base interface for all states: it doesn't do anything in itself
|
||||
but forces us to pass the right arguments to the methods below
|
||||
and makes sure every State object had all of these methods.
|
||||
"""
|
||||
extends Node
|
||||
|
||||
signal finished(next_state_name)
|
||||
|
||||
# Initialize the state. E.g. change the animation
|
||||
func enter(host):
|
||||
return
|
||||
|
||||
|
||||
# Clean up the state. Reinitialize values like a timer
|
||||
func exit(host):
|
||||
return
|
||||
|
||||
|
||||
func handle_input(host, event):
|
||||
return
|
||||
|
||||
|
||||
func update(host, delta):
|
||||
return
|
||||
|
||||
|
||||
func _on_animation_finished(anim_name):
|
||||
return
|
||||
278
2d/finite_state_machine/player/weapon/Sword.tscn
Normal file
278
2d/finite_state_machine/player/weapon/Sword.tscn
Normal file
@@ -0,0 +1,278 @@
|
||||
[gd_scene load_steps=8 format=2]
|
||||
|
||||
[ext_resource path="res://player/weapon/sword.gd" type="Script" id=1]
|
||||
[ext_resource path="res://player/weapon/sword.png" type="Texture" id=2]
|
||||
|
||||
[sub_resource type="Animation" id=1]
|
||||
|
||||
resource_name = "SETUP"
|
||||
length = 1.0
|
||||
loop = false
|
||||
step = 0.1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath(".:rotation_degrees")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 0,
|
||||
"values": [ 0.0 ]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/path = NodePath(".:scale")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 0,
|
||||
"values": [ Vector2( 1, 1 ) ]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/path = NodePath(".:visible")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 1,
|
||||
"values": [ true ]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/path = NodePath(".:monitoring")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 1,
|
||||
"values": [ true ]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/path = NodePath(".:monitorable")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 1,
|
||||
"values": [ false ]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id=2]
|
||||
|
||||
resource_name = "attack_circular"
|
||||
length = 0.3
|
||||
loop = false
|
||||
step = 0.05
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath(".:rotation_degrees")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0, 0.15, 0.2 ),
|
||||
"transitions": PoolRealArray( 0.439427, 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ -100.0, 100.0, 90.0 ]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/path = NodePath(".:scale")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/keys = {
|
||||
"times": PoolRealArray( 0, 0.05, 0.15, 0.2 ),
|
||||
"transitions": PoolRealArray( 1, 2.50795, 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ Vector2( 1, 1 ), Vector2( 1, 1.3 ), Vector2( 1, 1 ), Vector2( 1, 1 ) ]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/path = NodePath(".:visible")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 1,
|
||||
"values": [ true ]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id=3]
|
||||
|
||||
length = 0.45
|
||||
loop = false
|
||||
step = 0.05
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath(".:rotation_degrees")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0, 0.15, 0.2 ),
|
||||
"transitions": PoolRealArray( 0.439427, 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ -80.0, 85.0, 75.0 ]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/path = NodePath(".:scale")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/keys = {
|
||||
"times": PoolRealArray( 0, 0.05, 0.15, 0.2 ),
|
||||
"transitions": PoolRealArray( 1, 2.50795, 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ Vector2( 1, 1 ), Vector2( 1, 1.3 ), Vector2( 1, 1 ), Vector2( 1, 1 ) ]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/path = NodePath(".:visible")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 1,
|
||||
"values": [ true ]
|
||||
}
|
||||
tracks/3/type = "method"
|
||||
tracks/3/path = NodePath(".")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/keys = {
|
||||
"times": PoolRealArray( 0.1, 0.25 ),
|
||||
"transitions": PoolRealArray( 1, 1 ),
|
||||
"values": [ {
|
||||
"args": [ ],
|
||||
"method": "set_attack_input_listening"
|
||||
}, {
|
||||
"args": [ ],
|
||||
"method": "set_ready_for_next_attack"
|
||||
} ]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id=4]
|
||||
|
||||
resource_name = "attack_medium"
|
||||
length = 0.5
|
||||
loop = false
|
||||
step = 0.05
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath(".:rotation_degrees")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0.05, 0.25, 0.35 ),
|
||||
"transitions": PoolRealArray( 0.439427, 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ 95.0, -95.0, -90.0 ]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/path = NodePath(".:scale")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/keys = {
|
||||
"times": PoolRealArray( 0, 0.1, 0.2, 0.25 ),
|
||||
"transitions": PoolRealArray( 1, 2.50795, 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ Vector2( 1, 1 ), Vector2( 1, 1.3 ), Vector2( 1, 1 ), Vector2( 1, 1 ) ]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/path = NodePath(".:visible")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 1,
|
||||
"values": [ true ]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id=5]
|
||||
|
||||
length = 0.01
|
||||
loop = false
|
||||
step = 0.1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath(".:visible")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0 ),
|
||||
"transitions": PoolRealArray( 1 ),
|
||||
"update": 1,
|
||||
"values": [ false ]
|
||||
}
|
||||
|
||||
[node name="Sword" type="Area2D"]
|
||||
|
||||
input_pickable = false
|
||||
gravity_vec = Vector2( 0, 1 )
|
||||
gravity = 98.0
|
||||
linear_damp = 0.1
|
||||
angular_damp = 1.0
|
||||
monitorable = false
|
||||
collision_layer = 16
|
||||
collision_mask = 3
|
||||
audio_bus_override = false
|
||||
audio_bus_name = "Master"
|
||||
script = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Transform" ]
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." index="0"]
|
||||
|
||||
root_node = NodePath("..")
|
||||
autoplay = ""
|
||||
playback_process_mode = 1
|
||||
playback_default_blend_time = 0.0
|
||||
playback_speed = 1.0
|
||||
anims/SETUP = SubResource( 1 )
|
||||
anims/attack_circular = SubResource( 2 )
|
||||
anims/attack_fast = SubResource( 3 )
|
||||
anims/attack_medium = SubResource( 4 )
|
||||
anims/idle = SubResource( 5 )
|
||||
blend_times = [ ]
|
||||
_sections_unfolded = [ "Playback Options" ]
|
||||
|
||||
[node name="sword" type="Sprite" parent="." index="1"]
|
||||
|
||||
position = Vector2( 4, 0 )
|
||||
texture = ExtResource( 2 )
|
||||
offset = Vector2( 67, 0 )
|
||||
_sections_unfolded = [ "Offset", "Transform" ]
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="." index="2"]
|
||||
|
||||
build_mode = 0
|
||||
polygon = PoolVector2Array( 28.0001, -15.9999, 136, -15.9995, 160, 0, 136, 16.0005, 27.9999, 16.0001 )
|
||||
|
||||
|
||||
107
2d/finite_state_machine/player/weapon/sword.gd
Normal file
107
2d/finite_state_machine/player/weapon/sword.gd
Normal file
@@ -0,0 +1,107 @@
|
||||
extends Area2D
|
||||
|
||||
signal attack_finished
|
||||
|
||||
enum STATES { IDLE, ATTACK }
|
||||
var state = null
|
||||
|
||||
enum ATTACK_INPUT_STATES { IDLE, LISTENING, REGISTERED }
|
||||
var attack_input_state = IDLE
|
||||
var ready_for_next_attack = false
|
||||
const MAX_COMBO_COUNT = 3
|
||||
var combo_count = 0
|
||||
|
||||
var attack_current = {}
|
||||
var combo = [{
|
||||
'damage': 1,
|
||||
'animation': 'attack_fast',
|
||||
'effect': null
|
||||
},
|
||||
{
|
||||
'damage': 1,
|
||||
'animation': 'attack_fast',
|
||||
'effect': null
|
||||
},
|
||||
{
|
||||
'damage': 3,
|
||||
'animation': 'attack_medium',
|
||||
'effect': null
|
||||
}]
|
||||
|
||||
var hit_objects = []
|
||||
|
||||
|
||||
func _ready():
|
||||
$AnimationPlayer.connect('animation_finished', self, "_on_animation_finished")
|
||||
self.connect("body_entered", self, "_on_body_entered")
|
||||
_change_state(IDLE)
|
||||
|
||||
|
||||
func _change_state(new_state):
|
||||
match state:
|
||||
ATTACK:
|
||||
hit_objects = []
|
||||
attack_input_state = IDLE
|
||||
ready_for_next_attack = false
|
||||
|
||||
match new_state:
|
||||
IDLE:
|
||||
combo_count = 0
|
||||
$AnimationPlayer.stop()
|
||||
visible = false
|
||||
monitoring = false
|
||||
ATTACK:
|
||||
attack_current = combo[combo_count -1]
|
||||
$AnimationPlayer.play(attack_current['animation'])
|
||||
visible = true
|
||||
monitoring = true
|
||||
state = new_state
|
||||
|
||||
|
||||
func _input(event):
|
||||
if not state == ATTACK:
|
||||
return
|
||||
if attack_input_state != LISTENING:
|
||||
return
|
||||
if event.is_action_pressed('attack'):
|
||||
attack_input_state = REGISTERED
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if attack_input_state == REGISTERED and ready_for_next_attack:
|
||||
attack()
|
||||
|
||||
|
||||
func attack():
|
||||
combo_count += 1
|
||||
_change_state(ATTACK)
|
||||
|
||||
|
||||
# use with AnimationPlayer func track
|
||||
func set_attack_input_listening():
|
||||
attack_input_state = LISTENING
|
||||
|
||||
|
||||
# use with AnimationPlayer func track
|
||||
func set_ready_for_next_attack():
|
||||
ready_for_next_attack = true
|
||||
|
||||
|
||||
func _on_body_entered(body):
|
||||
if not body.has_node('Health'):
|
||||
return
|
||||
if body.get_rid().get_id() in hit_objects:
|
||||
return
|
||||
hit_objects.append(body.get_rid().get_id())
|
||||
body.take_damage(self, attack_current['damage'], attack_current['effect'])
|
||||
|
||||
|
||||
func _on_animation_finished(name):
|
||||
if not attack_current:
|
||||
return
|
||||
|
||||
if attack_input_state == REGISTERED and combo_count < MAX_COMBO_COUNT:
|
||||
attack()
|
||||
else:
|
||||
_change_state(IDLE)
|
||||
emit_signal("attack_finished")
|
||||
BIN
2d/finite_state_machine/player/weapon/sword.png
Normal file
BIN
2d/finite_state_machine/player/weapon/sword.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
32
2d/finite_state_machine/player/weapon/sword.png.import
Normal file
32
2d/finite_state_machine/player/weapon/sword.png.import
Normal file
@@ -0,0 +1,32 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/sword.png-fc7f0084cdf333c826eda2b33f2ec3cc.stex"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://player/weapon/sword.png"
|
||||
source_md5="17fb5e0e6c6fc2c23b36fdbb53f93b1d"
|
||||
|
||||
dest_files=[ "res://.import/sword.png-fc7f0084cdf333c826eda2b33f2ec3cc.stex" ]
|
||||
dest_md5="68d99f8d04dc7b6a17bb7ce168593030"
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
16
2d/finite_state_machine/player/weapon/weapon_pivot.gd
Normal file
16
2d/finite_state_machine/player/weapon/weapon_pivot.gd
Normal file
@@ -0,0 +1,16 @@
|
||||
extends Position2D
|
||||
|
||||
var z_index_start = 0
|
||||
|
||||
func _ready():
|
||||
$"..".connect("direction_changed", self, '_on_Parent_direction_changed')
|
||||
z_index_start = z_index
|
||||
|
||||
|
||||
func _on_Parent_direction_changed(direction):
|
||||
rotation = direction.angle()
|
||||
match direction:
|
||||
Vector2(0, -1):
|
||||
z_index = z_index_start - 1
|
||||
_:
|
||||
z_index = z_index_start
|
||||
68
2d/finite_state_machine/project.godot
Normal file
68
2d/finite_state_machine/project.godot
Normal file
@@ -0,0 +1,68 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=3
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Hierarchical Finite State Machine example"
|
||||
run/main_scene="res://Demo.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
GlobalConstants="*res://autoload/global_constants.gd"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/width=1280
|
||||
window/size/height=720
|
||||
window/size/test_width=1280
|
||||
window/size/test_height=720
|
||||
window/stretch/mode="2d"
|
||||
window/stretch/aspect="keep"
|
||||
|
||||
[gdnative]
|
||||
|
||||
singletons=[ ]
|
||||
|
||||
[input]
|
||||
|
||||
move_left=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
move_up=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
move_right=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null)
|
||||
]
|
||||
move_down=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null)
|
||||
]
|
||||
fire=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":82,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":2,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
run=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777237,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":7,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
jump=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
simulate_damage=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":88,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
attack=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":70,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
|
||||
[rendering]
|
||||
|
||||
environment/default_environment="res://default_env.tres"
|
||||
Reference in New Issue
Block a user