Compare commits

...

14 Commits

Author SHA1 Message Date
fffd8c947b implementing jump input buffering on grounded
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 18s
Create tag and build when new code gets to main / Export (push) Successful in 9m47s
2026-01-07 09:58:18 +01:00
a1d57d6a1a some tuto fixing
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 19s
Create tag and build when new code gets to main / Export (push) Successful in 9m49s
2026-01-06 16:35:17 +01:00
941205af2b small gravity and jump balancing, removed wall jumping coyote times
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 19s
Create tag and build when new code gets to main / Export (push) Successful in 9m34s
2026-01-06 16:08:39 +01:00
6c2ad89687 fixing the manlting into geo
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 19s
Create tag and build when new code gets to main / Export (push) Successful in 9m42s
2026-01-06 12:36:38 +01:00
59494f9e98 updating CI to build for linux as well
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 19s
Create tag and build when new code gets to main / Export (push) Successful in 9m34s
2025-12-25 09:37:51 +01:00
510246c341 fix a scene load issue
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 21s
Create tag and build when new code gets to main / Export (push) Successful in 8m22s
2025-12-22 14:25:17 +01:00
b184bcdea5 added a small dash when leaving a wall run organically
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 18s
Create tag and build when new code gets to main / Export (push) Successful in 8m36s
2025-12-21 17:23:38 +01:00
cf52af4237 mantling after aimed dash with new mantle system 2025-12-21 16:44:35 +01:00
e0fc301414 fixed user stuff
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 17s
Create tag and build when new code gets to main / Export (push) Successful in 8m10s
2025-12-19 19:11:53 +01:00
b792e8721c mantle system fix amazing
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 22s
Create tag and build when new code gets to main / Export (push) Successful in 8m19s
2025-12-19 18:59:34 +01:00
2e2df4ff50 new broken mantle system and fixed lots of gamefeel regarding wall hugs and jumps and coyote time
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 20s
Create tag and build when new code gets to main / Export (push) Successful in 8m51s
2025-12-17 16:39:10 +01:00
a84e0ecfb3 Merge branch 'main' of https://git.game-dev.space/minimata/MovementTests
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 20s
Create tag and build when new code gets to main / Export (push) Successful in 8m25s
2025-12-15 11:20:39 +01:00
f828c1d786 added a coyote time for wall jumps 2025-12-15 11:20:17 +01:00
a98785abec Update .gitea/workflows/main.yaml
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 18s
Create tag and build when new code gets to main / Export (push) Successful in 8m49s
2025-12-10 21:26:25 +00:00
18 changed files with 1410 additions and 809 deletions

View File

@@ -54,27 +54,12 @@ jobs:
- name: Import resources and build solution
run: |
godot --headless --editor --build-solutions --quit --import --path $PWD
- name: Build Windows
run: |
mkdir -v -p build/windows
godot --headless --verbose --build-solutions --export-release "Windows Desktop" build/windows/${{ env.GAME_NAME }}.exe
zip -r Windows.zip build/windows
- name: Build Windows ARM
run: |
mkdir -v -p build/windowsArm
godot --headless --verbose --build-solutions --export-release "Windows ARM" build/windowsArm/${{ env.GAME_NAME }}.exe
zip -r WindowsArm.zip build/windowsArm
# - name: Linux Build
# run: |
# mkdir -v -p build/linux
# godot --headless --verbose --export-release "Linux/X11" build/linux/${{ env.GAME_NAME }}.x86_64
# zip -r Linux.zip build/linux
# - name: Mac Build
# run: |
# mkdir -v -p build/mac
# godot --headless --verbose --export-release "macOS" build/mac/${{ env.GAME_NAME }}.zip
# zip -r Mac.zip build/mac
- name: Upload to Itch
uses: KikimoraGames/itch-publish@v0.0.3
with:
@@ -84,6 +69,12 @@ jobs:
buildNumber: ${{ needs.BumpTag.outputs.tag_name }}
gameData: Windows.zip
buildChannel: windows
- name: Build Windows ARM
run: |
mkdir -v -p build/windowsArm
godot --headless --verbose --build-solutions --export-release "Windows ARM" build/windowsArm/${{ env.GAME_NAME }}.exe
zip -r WindowsArm.zip build/windowsArm
- name: Upload to Itch
uses: KikimoraGames/itch-publish@v0.0.3
with:
@@ -93,21 +84,33 @@ jobs:
buildNumber: ${{ needs.BumpTag.outputs.tag_name }}
gameData: WindowsArm.zip
buildChannel: windows-arm
# - name: Upload to Itch
# uses: KikimoraGames/itch-publish@v0.0.3
# with:
# butlerApiKey: ${{ secrets.BUTLER_TOKEN }}
# itchUsername: ${{ env.ITCHIO_USERNAME }}
# itchGameId: ${{ env.ITCHIO_GAMEID }}
# buildNumber: ${{ needs.BumpTag.outputs.tag_name }}
# gameData: Linux.zip
# buildChannel: linux
# - name: Upload to Itch
# uses: KikimoraGames/itch-publish@v0.0.3
# with:
# butlerApiKey: ${{ secrets.BUTLER_TOKEN }}
# itchUsername: ${{ env.ITCHIO_USERNAME }}
# itchGameId: ${{ env.ITCHIO_GAMEID }}
# buildNumber: ${{ needs.BumpTag.outputs.tag_name }}
# gameData: Mac.zip
# buildChannel: mac
- name: Linux Build
run: |
mkdir -v -p build/linux
godot --headless --verbose --export-release "Linux/X11" build/linux/${{ env.GAME_NAME }}.x86_64
zip -r Linux.zip build/linux
- name: Upload to Itch
uses: KikimoraGames/itch-publish@v0.0.3
with:
butlerApiKey: ${{ secrets.BUTLER_TOKEN }}
itchUsername: ${{ env.ITCHIO_USERNAME }}
itchGameId: ${{ env.ITCHIO_GAMEID }}
buildNumber: ${{ needs.BumpTag.outputs.tag_name }}
gameData: Linux.zip
buildChannel: linux
- name: Mac Build
run: |
mkdir -v -p build/mac
godot --headless --verbose --export-release "macOS" build/mac/${{ env.GAME_NAME }}.zip
zip -r Mac.zip build/mac
- name: Upload to Itch
uses: KikimoraGames/itch-publish@v0.0.3
with:
butlerApiKey: ${{ secrets.BUTLER_TOKEN }}
itchUsername: ${{ env.ITCHIO_USERNAME }}
itchGameId: ${{ env.ITCHIO_GAMEID }}
buildNumber: ${{ needs.BumpTag.outputs.tag_name }}
gameData: Mac.zip
buildChannel: mac

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -50,7 +50,7 @@ collision_layer = 3
collision_mask = 5
[node name="CSGBox3D" type="CSGBox3D" parent="Greybox"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.09619, -0.472656, -46.3293)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.096, -0.5, -46.329)
use_collision = true
size = Vector3(100, 1, 190.741)
material = ExtResource("3_vvhq3")
@@ -400,3 +400,205 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 4.5, -11.5)
use_collision = true
size = Vector3(1, 0.5, 5)
material = ExtResource("3_vvhq3")
[node name="Mantles" type="CSGCombiner3D" parent="Greybox"]
[node name="Label3D22" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, -5.5, 0.1, 11)
text = "0.5m"
[node name="Label3D35" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, -8.5, 0.1, 11)
text = "0.25m"
[node name="Label3D23" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, -2, 0.1, 11)
text = "1m"
[node name="Label3D27" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, -11, 0.1, 12.5)
text = "1m"
[node name="Label3D28" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, 13, 0.1, 12.5)
text = "1m"
[node name="Label3D29" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, 13, 0.1, 21)
text = "2m"
[node name="Label3D30" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, 13, 0.1, 28.5)
text = "3m"
[node name="Label3D31" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, -11, 0.1, 21)
text = "2m"
[node name="Label3D32" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, -11, 0.1, 28.5)
text = "3m"
[node name="Label3D24" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, 2, 0.1, 11)
text = "1.5m"
[node name="Label3D25" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, 6, 0.1, 11)
text = "2m"
[node name="Label3D26" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, 10, 0.1, 11)
text = "4m"
[node name="CSGBox3D33" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 12.5)
use_collision = true
size = Vector3(4, 1, 1)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D34" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 0.5, 12.25)
use_collision = true
size = Vector3(3, 1, 0.5)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D35" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0.5, 12.75)
use_collision = true
size = Vector3(4, 1, 1.5)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D36" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0.5, 13)
use_collision = true
size = Vector3(4, 1, 2)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D37" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 0.5, 14)
use_collision = true
size = Vector3(4, 1, 4)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D38" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 1, 20.5)
use_collision = true
size = Vector3(4, 2, 1)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D39" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 1, 20.25)
use_collision = true
size = Vector3(3, 2, 0.5)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D40" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 1, 20.75)
use_collision = true
size = Vector3(4, 2, 1.5)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D41" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 1, 21)
use_collision = true
size = Vector3(4, 2, 2)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D42" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 1, 22)
use_collision = true
size = Vector3(4, 2, 4)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D43" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 1.5, 28.5)
use_collision = true
size = Vector3(4, 3, 1)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D44" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 1.5, 28.25)
use_collision = true
size = Vector3(3, 3, 0.5)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D45" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 1.5, 28.75)
use_collision = true
size = Vector3(4, 3, 1.5)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D46" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 1.5, 29)
use_collision = true
size = Vector3(4, 3, 2)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D47" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 1.5, 30)
use_collision = true
size = Vector3(4, 3, 4)
material = ExtResource("3_vvhq3")
[node name="Label3D33" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, 13, 0.1, 36.5)
text = "4m"
[node name="Label3D34" type="Label3D" parent="Greybox/Mantles"]
transform = Transform3D(-5, 4.3711395e-07, 1.9106861e-14, 0, -2.18557e-07, 5, 4.3711395e-07, 5, 2.18557e-07, -11, 0.1, 36.5)
text = "4m"
[node name="CSGBox3D48" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 2, 36.5)
use_collision = true
size = Vector3(4, 4, 1)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D49" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 2, 36.25)
use_collision = true
size = Vector3(3, 4, 0.5)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D53" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.5, 0.5, 12.125)
use_collision = true
size = Vector3(3, 1, 0.25)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D54" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.5, 1, 20.125)
use_collision = true
size = Vector3(3, 2, 0.25)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D55" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.5, 1.5, 28.125)
use_collision = true
size = Vector3(3, 3, 0.25)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D56" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.5, 2, 36.125)
use_collision = true
size = Vector3(3, 4, 0.25)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D50" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 36.75)
use_collision = true
size = Vector3(4, 4, 1.5)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D51" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 2, 37)
use_collision = true
size = Vector3(4, 4, 2)
material = ExtResource("3_vvhq3")
[node name="CSGBox3D52" type="CSGBox3D" parent="Greybox/Mantles"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 2, 38)
use_collision = true
size = Vector3(4, 4, 4)
material = ExtResource("3_vvhq3")

View File

@@ -1,8 +1,7 @@
[gd_scene load_steps=41 format=3 uid="uid://dmkw8cmalm5k"]
[gd_scene load_steps=40 format=3 uid="uid://dmkw8cmalm5k"]
[ext_resource type="PackedScene" uid="uid://bei4nhkf8lwdo" path="res://player_controller/PlayerController.tscn" id="1_2vsi6"]
[ext_resource type="Script" uid="uid://blenis2y55fmg" path="res://tools/city_helpers.gd" id="1_qwuk2"]
[ext_resource type="Resource" uid="uid://bl5crtu1gkrtr" path="res://systems/inputs/base_mode/base_mode.tres" id="2_p287n"]
[ext_resource type="Texture2D" uid="uid://ca4kkq3w8cd4n" path="res://assets/sky/sky_15_2k.png" id="2_ruo5i"]
[ext_resource type="PackedScene" uid="uid://dkr80d2pi0d41" path="res://addons/guide/debugger/guide_debugger.tscn" id="2_uet8a"]
[ext_resource type="Script" uid="uid://cyh0d64pfygbl" path="res://addons/maaacks_game_template/base/scripts/pause_menu_controller.gd" id="7_ukfuy"]
@@ -92,7 +91,6 @@ adjustment_enabled = true
[node name="Main" type="Node3D"]
script = ExtResource("1_qwuk2")
base_mode = ExtResource("2_p287n")
[node name="BackgroundMusicPlayer" parent="." instance=ExtResource("9_i2xii")]
stream = ExtResource("10_eca4n")

View File

@@ -1,6 +1,7 @@
[gd_scene load_steps=47 format=3 uid="uid://bei4nhkf8lwdo"]
[gd_scene load_steps=48 format=3 uid="uid://bei4nhkf8lwdo"]
[ext_resource type="Script" uid="uid://bbbrf5ckydfna" path="res://player_controller/Scripts/PlayerController.cs" id="1_poq2x"]
[ext_resource type="PackedScene" uid="uid://cf3rrgr1imvv4" path="res://scenes/path/path.tscn" id="2_6lejt"]
[ext_resource type="Resource" uid="uid://bl5crtu1gkrtr" path="res://systems/inputs/base_mode/base_mode.tres" id="3_cresl"]
[ext_resource type="Resource" uid="uid://cpdaw41ah5gic" path="res://systems/inputs/base_mode/rotate_y.tres" id="4_rxwoh"]
[ext_resource type="Resource" uid="uid://ccrb5xsnphc8" path="res://systems/inputs/base_mode/rotate_floorplane.tres" id="5_4u7i3"]
@@ -62,20 +63,22 @@ blend_mode = 1
[node name="Player" type="CharacterBody3D"]
script = ExtResource("1_poq2x")
WalkSpeed = 7.5
AccelerationAir = 2.0
DecelerationAir = 0.1
Weight = 5.0
AccelerationAir = 0.8
DecelerationAir = 0.02
Weight = 4.0
MantleTime = 0.3
SimpleJumpStartVelocity = 8.0
MantlePath = ExtResource("2_6lejt")
CoyoteTime = 0.3
InputBufferFrames = 5
SimpleJumpStartVelocity = 6.0
SimpleJumpHangTimeInFrames = 1
SimpleJumpGravityLesseningFactor = 2.5
DoubleJumpStartVelocity = 15.0
SimpleJumpGravityLesseningFactor = 2.0
DoubleJumpHangTimeInFrames = 3
DoubleJumpGravityLesseningFactor = 1.5
MegaJumpStartVelocity = 30.0
MegaJumpHangTimeInFrames = 12
MegaJumpGravityLesseningFactor = 1.2
WallJumpStartVelocity = 12.0
WallJumpStartVelocity = 8.0
MaxNumberOfEmpoweredActions = 3
SimpleDashStrength = 15.0
PoweredDashStrength = 30.0
@@ -85,7 +88,7 @@ WallHugGravityLesseningFactor = 15.0
WallHugDownwardMaxSpeed = 8.0
WallHugHorizontalDeceleration = 0.5
WallRunAltitudeLossSpeed = 12.0
WallRunSpeedThreshold = 5.0
WallRunSpeedThreshold = 10.0
[node name="WallRunSnapper" type="RayCast3D" parent="."]
unique_name_in_owner = true
@@ -132,6 +135,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
CameraInclineAcceleration = 20.0
GroundedCameraIncline = 3.0
[node name="MantleSystem" parent="HeadSystem" instance=ExtResource("8_qu4wy")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.6, 0)
MantleEndLocationDistanceFromWall = 0.3
MantleHeightCastStart = 2.5
[node name="StairsSystem" type="Node3D" parent="."]
script = ExtResource("7_bmt5a")
@@ -142,10 +150,6 @@ target_position = Vector3(0, -0.55, 0)
[node name="StairsBelowRayCast3D" type="RayCast3D" parent="."]
target_position = Vector3(0, -0.75, 0)
[node name="MantleSystem" parent="." instance=ExtResource("8_qu4wy")]
MantleEndLocationDistanceFromWall = 0.3
MantleHeightCastStart = 2.0
[node name="Bobbing" type="Node3D" parent="."]
script = ExtResource("10_7wk1w")
@@ -153,6 +157,7 @@ script = ExtResource("10_7wk1w")
script = ExtResource("12_m2mxi")
[node name="HeadCollisionDetectors" type="Node3D" parent="."]
visible = false
[node name="HeadCollisionDetector0" type="RayCast3D" parent="HeadCollisionDetectors"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4, -0.210707)
@@ -173,6 +178,7 @@ target_position = Vector3(0, 1, 0)
[node name="TweenQueueSystem" parent="." instance=ExtResource("22_rpwev")]
[node name="WallHugSystem" type="Node3D" parent="."]
visible = false
script = ExtResource("27_n7qhm")
[node name="back" type="RayCast3D" parent="WallHugSystem"]
@@ -230,6 +236,11 @@ transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 0
mesh = SubResource("CylinderMesh_nodcl")
[node name="DashCooldown" type="Timer" parent="."]
wait_time = 0.8
one_shot = true
[node name="AirborneDashCooldown" type="Timer" parent="."]
wait_time = 0.5
one_shot = true
[node name="PowerCooldown" type="Timer" parent="."]
@@ -242,7 +253,6 @@ one_shot = true
ignore_time_scale = true
[node name="StateChartDebugger" parent="." instance=ExtResource("24_q5h8a")]
visible = false
offset_left = 1524.0
offset_top = 1.0
offset_right = -8.0
@@ -500,45 +510,45 @@ delay_in_seconds = "0.0"
script = ExtResource("26_infe6")
initial_state = NodePath("SimpleJump")
[node name="OnMantle" type="Node" parent="StateChart/Root/Movement/Jump"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Mantling")
event = &"mantle"
delay_in_seconds = "0.0"
[node name="SimpleJump" type="Node" parent="StateChart/Root/Movement/Jump"]
script = ExtResource("27_34snm")
[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Jump/SimpleJump"]
script = ExtResource("28_n7qhm")
to = NodePath("../../MegaJump")
event = &"megajump"
delay_in_seconds = "0.0"
[node name="OnJumpEnded" type="Node" parent="StateChart/Root/Movement/Jump/SimpleJump"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Airborne/DoubleJumpEnabled")
event = &"jump_ended"
delay_in_seconds = "0.0"
[node name="DoubleJump" type="Node" parent="StateChart/Root/Movement/Jump"]
script = ExtResource("27_34snm")
[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Jump/DoubleJump"]
[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Jump/SimpleJump"]
script = ExtResource("28_n7qhm")
to = NodePath("../../MegaJump")
event = &"megajump"
delay_in_seconds = "0.0"
[node name="DoubleJump" type="Node" parent="StateChart/Root/Movement/Jump"]
script = ExtResource("27_34snm")
[node name="OnJumpEnded" type="Node" parent="StateChart/Root/Movement/Jump/DoubleJump"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Airborne/Falling")
event = &"jump_ended"
delay_in_seconds = "0.0"
[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Jump/DoubleJump"]
script = ExtResource("28_n7qhm")
to = NodePath("../../MegaJump")
event = &"megajump"
delay_in_seconds = "0.0"
[node name="MegaJump" type="Node" parent="StateChart/Root/Movement/Jump"]
script = ExtResource("27_34snm")
[node name="OnJumpEnded" type="Node" parent="StateChart/Root/Movement/Jump/MegaJump"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Airborne/Falling")
event = &"jump_ended"
delay_in_seconds = "0.0"
[node name="Dashing" type="Node" parent="StateChart/Root/Movement"]
script = ExtResource("26_infe6")
initial_state = NodePath("Dash")
@@ -602,12 +612,6 @@ initial_state = NodePath("CoyoteEnabled")
script = ExtResource("41_ruloh")
default_state = NodePath("../CoyoteEnabled")
[node name="OnWallHug" type="Node" parent="StateChart/Root/Movement/Airborne"]
script = ExtResource("28_n7qhm")
to = NodePath("../../OnWall/Hugging")
event = &"wall_hug"
delay_in_seconds = "0.0"
[node name="OnWallRun" type="Node" parent="StateChart/Root/Movement/Airborne"]
script = ExtResource("28_n7qhm")
to = NodePath("../../OnWall/Running")
@@ -650,6 +654,12 @@ delay_in_seconds = "0.0"
[node name="DoubleJumpEnabled" type="Node" parent="StateChart/Root/Movement/Airborne"]
script = ExtResource("27_34snm")
[node name="OnWallHug" type="Node" parent="StateChart/Root/Movement/Airborne/DoubleJumpEnabled"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../OnWall/HuggingCoyoteEnabled")
event = &"wall_hug"
delay_in_seconds = "0.0"
[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Airborne/DoubleJumpEnabled"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Jump/MegaJump")
@@ -665,6 +675,12 @@ delay_in_seconds = "0.0"
[node name="Falling" type="Node" parent="StateChart/Root/Movement/Airborne"]
script = ExtResource("27_34snm")
[node name="OnWallHug" type="Node" parent="StateChart/Root/Movement/Airborne/Falling"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../OnWall/Hugging")
event = &"wall_hug"
delay_in_seconds = "0.0"
[node name="ToDoubleJump" type="Node" parent="StateChart/Root/Movement/Airborne/Falling"]
script = ExtResource("28_n7qhm")
to = NodePath("../../DoubleJumpEnabled")
@@ -687,12 +703,6 @@ to = NodePath("../../Grounded")
event = &"grounded"
delay_in_seconds = "0.0"
[node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Jump/SimpleJump")
event = &"jump"
delay_in_seconds = "0.0"
[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Jump/MegaJump")
@@ -705,15 +715,81 @@ to = NodePath("../../Airborne/Reset")
event = &"start_falling"
delay_in_seconds = "0.0"
[node name="OnMantle" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Mantling")
event = &"mantle"
delay_in_seconds = "0.0"
[node name="HuggingCoyoteEnabled" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm")
[node name="OnExpiration" type="Node" parent="StateChart/Root/Movement/OnWall/HuggingCoyoteEnabled"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Hugging")
event = &"coyote_expired"
delay_in_seconds = "0.0"
[node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/HuggingCoyoteEnabled"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Jump/DoubleJump")
event = &"jump"
delay_in_seconds = "0.0"
[node name="Hugging" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm")
[node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/Hugging"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Jump/DoubleJump")
event = &"jump"
delay_in_seconds = "0.0"
[node name="Hanging" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm")
[node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/Hanging"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Jump/DoubleJump")
event = &"jump"
delay_in_seconds = "0.0"
[node name="RunningCoyoteEnabled" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm")
[node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/RunningCoyoteEnabled"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Jump/DoubleJump")
event = &"jump"
delay_in_seconds = "0.0"
[node name="OnExpiration" type="Node" parent="StateChart/Root/Movement/OnWall/RunningCoyoteEnabled"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Running")
event = &"coyote_expired"
delay_in_seconds = "0.0"
[node name="OnLeaveWall" type="Node" parent="StateChart/Root/Movement/OnWall/RunningCoyoteEnabled"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Airborne/CoyoteEnabled")
event = &"start_falling"
delay_in_seconds = "0.0"
[node name="Running" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm")
[node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/Running"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Jump/SimpleJump")
event = &"jump"
delay_in_seconds = "0.0"
[node name="OnLeaveWall" type="Node" parent="StateChart/Root/Movement/OnWall/Running"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Airborne/CoyoteEnabled")
event = &"start_falling"
delay_in_seconds = "0.0"
[connection signal="input_aim_canceled" from="InputController" to="." method="OnInputAimCanceled"]
[connection signal="input_aim_down" from="InputController" to="." method="OnInputAimDown"]
[connection signal="input_aim_pressed" from="InputController" to="." method="OnInputAimPressed"]

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Godot;
using GodotStateCharts;
using Movementtests.addons.godot_state_charts.csharp;
@@ -15,7 +14,7 @@ public partial class PlayerController : CharacterBody3D
MoveCamera,
None,
}
private bool _isUsingGamepad = false;
private bool _isUsingGamepad;
// User API to important child nodes.
public HeadSystem HeadSystem;
@@ -25,7 +24,6 @@ public partial class PlayerController : CharacterBody3D
public MantleSystem MantleSystem;
public DashSystem DashSystem;
public CapsuleCollider CapsuleCollider;
public TweenQueueSystem TweenQueueSystem;
public Node3D WeaponRoot;
public WeaponSystem WeaponSystem;
public WallHugSystem WallHugSystem;
@@ -39,9 +37,11 @@ public partial class PlayerController : CharacterBody3D
private bool _movementEnabled = true;
private Vector3 _dashDirection = Vector3.Zero;
private bool _shouldMantle;
private Vector3 _mantleLocation = Vector3.Zero;
private Vector3 _dashDirection = Vector3.Zero;
private Vector3 _preMantleVelocity = Vector3.Zero;
private float _lastFrameWasOnFloor = -Mathf.Inf;
@@ -58,6 +58,7 @@ public partial class PlayerController : CharacterBody3D
// Timers
private Timer _timeScaleAimInAirTimer;
private Timer _simpleDashCooldownTimer;
private Timer _airborneDashCooldownTimer;
private Timer _powerCooldownTimer;
[Export] public Marker3D TutorialWeaponTarget;
@@ -81,11 +82,15 @@ public partial class PlayerController : CharacterBody3D
[ExportGroup("Mantle")]
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
public float MantleTime { get; set; } = 0.1f;
[Export]
public PackedScene MantlePath { get; set; }
// Jump
[ExportGroup("Jump")]
[Export(PropertyHint.Range, "0,1,0.01")]
public float CoyoteTime { get; set; } = 0.2f;
[Export(PropertyHint.Range, "0,10,1,or_greater")]
public int InputBufferFrames { get; set; } = 3;
// Simple jump
[ExportSubgroup("Simple jump")]
@@ -186,6 +191,11 @@ public partial class PlayerController : CharacterBody3D
private bool _canDash = true;
private bool _shouldMantleOnDashEnded;
private Vector3 _wallHugStartLocation = Vector3.Zero;
private Vector3 _wallHugStartNormal = Vector3.Zero;
private Vector3 _wallHugStartProjectedVelocity = Vector3.Zero;
private Vector3 _currentWallContactPoint = Vector3.Zero;
private StateChart _playerState;
private StateChartState _aiming;
@@ -197,22 +207,35 @@ public partial class PlayerController : CharacterBody3D
private StateChartState _grounded;
private StateChartState _airborne;
private StateChartState _coyoteEnabled;
// private StateChartState _doubleJumpEnabled;
private StateChartState _simpleJump;
private StateChartState _doubleJump;
private StateChartState _megaJump;
private StateChartState _mantling;
private StateChartState _simpleDash;
private StateChartState _poweredDash;
private StateChartState _aimedDash;
private StateChartState _onWall;
private StateChartState _onWallHugging;
private StateChartState _onWallHuggingCoyoteEnabled;
private StateChartState _onWallHanging;
private StateChartState _onWallRunning;
private Transition _onJumpFromWall;
private StateChartState _onWallRunningCoyoteEnabled;
private Transition _onJumpFromWallCoyote;
private Transition _onJumpFromWallRunCoyote;
private Transition _onJumpFromWall1;
private Transition _onJumpFromWall2;
private Transition _onJumpFromWall3;
private Transition _onMegajumpFromWall;
private Transition _onLeaveWallFromRunCoyote;
private Transition _onLeaveWallFromRun;
private int _currentJumpBufferFrames = 0;
private float _playerHeight;
private float _playerRadius;
private bool _isJumpInputPressed;
private float _lookSensitivityMultiplier = 1.0f;
private float _mouseSensitivityMultiplier = 1.0f;
@@ -228,7 +251,6 @@ public partial class PlayerController : CharacterBody3D
///////////////////////////
// General use stuff
TweenQueueSystem = GetNode<TweenQueueSystem>("TweenQueueSystem");
PlayerUi = GetNode<PlayerUi>("UI");
// DashIndicator = GetNode<TextureRect>("%DashIndicator");
PowerCooldownIndicator = GetNode<ColorRect>("%DashCooldownIndicator");
@@ -250,9 +272,9 @@ public partial class PlayerController : CharacterBody3D
Node3D cameraSmooth = GetNode<Node3D>("HeadSystem/CameraSmooth");
// Movement stuff
WeaponRoot = GetNode<Node3D>("WeaponRoot");
WeaponRoot = GetNode<Node3D>("WeaponRoot");
WeaponSystem = GetNode<WeaponSystem>("WeaponRoot/WeaponSystem");
MantleSystem = GetNode<MantleSystem>("MantleSystem");
MantleSystem = GetNode<MantleSystem>("HeadSystem/MantleSystem");
CapsuleCollider = GetNode<CapsuleCollider>("CapsuleCollider");
DashSystem = GetNode<DashSystem>("DashSystem");
StairsSystem = GetNode<StairsSystem>("StairsSystem");
@@ -282,31 +304,39 @@ public partial class PlayerController : CharacterBody3D
_empowerOn = StateChartState.Of(GetNode("StateChart/Root/Empower/On"));
_powerExpired = StateChartState.Of(GetNode("StateChart/Root/PowerReserve/Expired"));
_powerRecharging = StateChartState.Of(GetNode("StateChart/Root/PowerReserve/AtLeastOneCharge"));
_powerFull = StateChartState.Of(GetNode("StateChart/Root/PowerReserve/Full"));
_powerFull = StateChartState.Of(GetNode("StateChart/Root/PowerReserve/Full"));
_grounded = StateChartState.Of(GetNode("StateChart/Root/Movement/Grounded"));
_airborne = StateChartState.Of(GetNode("StateChart/Root/Movement/Airborne"));
_coyoteEnabled = StateChartState.Of(GetNode("StateChart/Root/Movement/Airborne/CoyoteEnabled"));
// _doubleJumpEnabled = StateChartState.Of(GetNode("StateChart/Root/Movement/Airborne/DoubleJumpEnabled"));
_simpleJump = StateChartState.Of(GetNode("StateChart/Root/Movement/Jump/SimpleJump"));
_doubleJump = StateChartState.Of(GetNode("StateChart/Root/Movement/Jump/DoubleJump"));
_megaJump = StateChartState.Of(GetNode("StateChart/Root/Movement/Jump/MegaJump"));
_onJumpFromWall = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/OnJump"));
_mantling = StateChartState.Of(GetNode("StateChart/Root/Movement/Mantling"));
_onJumpFromWallCoyote = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/HuggingCoyoteEnabled/OnJump"));
_onJumpFromWallRunCoyote = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/RunningCoyoteEnabled/OnJump"));
_onJumpFromWall1 = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/Hugging/OnJump"));
_onJumpFromWall2 = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/Hanging/OnJump"));
_onJumpFromWall3 = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/Running/OnJump"));
_onMegajumpFromWall = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/OnMegajump"));
_onWall = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall"));
_onWallHuggingCoyoteEnabled = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/HuggingCoyoteEnabled"));
_onWallHugging = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/Hugging"));
_onWallHanging = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/Hanging"));
_onWallRunning = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/Running"));
_onWallRunningCoyoteEnabled = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/RunningCoyoteEnabled"));
_onLeaveWallFromRun = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/Running/OnLeaveWall"));
_onLeaveWallFromRunCoyote = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/RunningCoyoteEnabled/OnLeaveWall"));
// State timers
_powerCooldownTimer = GetNode<Timer>("PowerCooldown");
_timeScaleAimInAirTimer = GetNode<Timer>("TimeScaleAimInAir");
_simpleDashCooldownTimer = GetNode<Timer>("DashCooldown");
_airborneDashCooldownTimer = GetNode<Timer>("AirborneDashCooldown");
///////////////////////////
// Initialize components //
///////////////////////////
// General use stuff
TweenQueueSystem.Init(this);
// Camera stuff
HeadSystem.Init();
@@ -318,7 +348,7 @@ public partial class PlayerController : CharacterBody3D
_gravity = (float)ProjectSettings.GetSetting("physics/3d/default_gravity");
MantleSystem.Init();
StairsSystem.Init(stairsBelowRayCast3D, stairsAheadRayCast3D, cameraSmooth);
DashSystem.Init(HeadSystem, camera, TweenQueueSystem);
DashSystem.Init(HeadSystem, camera);
WeaponSystem.Init(HeadSystem, camera);
WallHugSystem.Init();
@@ -339,6 +369,7 @@ public partial class PlayerController : CharacterBody3D
_grounded.StateEntered += OnGrounded;
_grounded.StatePhysicsProcessing += HandleGrounded;
_airborne.StatePhysicsProcessing += HandleAirborne;
_onWall.StatePhysicsProcessing += HandleOnWall;
_coyoteEnabled.StateEntered += StartCoyoteTime;
_timeScaleAimInAirTimer.Timeout += ResetTimeScale;
@@ -359,6 +390,9 @@ public partial class PlayerController : CharacterBody3D
_megaJump.StateEntered += OnMegaJumpStarted;
_megaJump.StatePhysicsProcessing += HandleMegaJump;
_mantling.StateEntered += OnMantleStarted;
_mantling.StatePhysicsProcessing += HandleMantling;
_simpleDash.StateEntered += OnSimpleDashStarted;
_simpleDash.StatePhysicsProcessing += HandleSimpleDash;
@@ -370,15 +404,26 @@ public partial class PlayerController : CharacterBody3D
_aimedDash.StateExited += OnAimedDashFinished;
_simpleDashCooldownTimer.Timeout += DashCooldownTimeout;
_airborneDashCooldownTimer.Timeout += AirborneDashCooldownTimeout;
_onWall.StateEntered += OnWallStarted;
_onWall.StateExited += OnWallStopped;
_onWallHuggingCoyoteEnabled.StateEntered += OnWallHuggingStarted;
_onWallHuggingCoyoteEnabled.StatePhysicsProcessing += HandleWallHugging;
_onWallHugging.StatePhysicsProcessing += HandleWallHugging;
_onWallHanging.StatePhysicsProcessing += HandleWallHanging;
_onWallRunningCoyoteEnabled.StateEntered += OnWallRunningStarted;
_onWallRunningCoyoteEnabled.StatePhysicsProcessing += HandleWallRunning;
_onWallRunning.StatePhysicsProcessing += HandleWallRunning;
_onJumpFromWall.Taken += OnJumpFromWall;
_onJumpFromWallCoyote.Taken += OnJumpFromWallCoyote;
_onJumpFromWallRunCoyote.Taken += OnJumpFromWallCoyote;
_onJumpFromWall1.Taken += OnJumpFromWall;
_onJumpFromWall2.Taken += OnJumpFromWall;
_onJumpFromWall3.Taken += OnJumpFromWall;
_onMegajumpFromWall.Taken += OnMegajumpFromWall;
_onLeaveWallFromRun.Taken += OnLeaveWallFromRun;
_onLeaveWallFromRunCoyote.Taken += OnLeaveWallFromRun;
}
public void SetAllowedInputsAll()
@@ -425,16 +470,37 @@ public partial class PlayerController : CharacterBody3D
if (_simpleDashCooldownTimer.IsStopped())
_simpleDashCooldownTimer.Start();
if (_currentJumpBufferFrames > 0)
{
_currentJumpBufferFrames = 0;
PerformJump();
}
}
public void DashCooldownTimeout()
{
_canDash = true;
}
public void AirborneDashCooldownTimeout()
{
_canDashAirborne = true;
}
public bool IsPlayerInputtingForward()
{
return GetMoveInput().Z < -0.5f;
}
public bool IsTryingToMantle()
{
return MantleSystem.IsMantlePossible && IsPlayerInputtingForward() && _isJumpInputPressed;
}
public void HandleGrounded(float delta)
{
MoveOnGround(delta);
// if (IsTryingToMantle()) _playerState.SendEvent("mantle");
if (!isOnFloorCustom())
_playerState.SendEvent("start_falling");
}
@@ -445,8 +511,13 @@ public partial class PlayerController : CharacterBody3D
if (isOnFloorCustom())
_playerState.SendEvent("grounded");
if (IsTryingToMantle()) _playerState.SendEvent("mantle");
if (!WallHugSystem.IsWallHugging())
{
_isWallJumpAvailable = true; // reset wall jump if we left the wall
return;
}
// Going upwards, we stay simply airborne
if (Velocity.AngleTo(Vector3.Up) < Math.PI / 4)
@@ -469,14 +540,25 @@ public partial class PlayerController : CharacterBody3D
// If all else fail and we go down, we hug
if (Velocity.Y < 0 && !_coyoteEnabled.Active)
{
_playerState.SendEvent("wall_hug");
}
}
public void HandleOnWall(float delta)
{
if (IsTryingToMantle()) _playerState.SendEvent("mantle");
}
private Vector3 _wallHugStartLocation = Vector3.Zero;
private Vector3 _wallHugStartNormal = Vector3.Zero;
private Vector3 _wallHugStartProjectedVelocity = Vector3.Zero;
private Vector3 _currentWallContactPoint = Vector3.Zero;
public void OnWallHuggingStarted()
{
GetTree().CreateTimer(CoyoteTime).Timeout += CoyoteExpired;
}
public void OnWallRunningStarted()
{
GetTree().CreateTimer(CoyoteTime).Timeout += CoyoteExpired;
}
public void OnWallDetected()
{
@@ -486,11 +568,15 @@ public partial class PlayerController : CharacterBody3D
return;
var newWallNormal = WallHugSystem.WallHugNormal.UnwrapOr(Vector3.Up);
if (newWallNormal.AngleTo(_wallHugStartNormal) > Mathf.Pi/4) return;
_wallHugStartNormal = newWallNormal;
}
public void OnWallStarted()
{
if (!WallHugSystem.IsWallHugging())
return;
_wallHugStartNormal = WallHugSystem.WallHugNormal.UnwrapOr(Vector3.Up);
_currentWallContactPoint = WallHugSystem.WallHugLocation.UnwrapOr(Vector3.Zero);
_wallHugStartLocation = _currentWallContactPoint + _wallHugStartNormal * _playerRadius;
@@ -499,10 +585,11 @@ public partial class PlayerController : CharacterBody3D
public void OnWallStopped()
{
_wallHugStartLocation = Vector3.Zero;
_currentWallContactPoint = Vector3.Zero;
_wallHugStartNormal = Vector3.Zero;
_wallHugStartProjectedVelocity = Vector3.Zero;
}
public void OnLeaveWallFromRun()
{
SimpleDashInDirection(Velocity.Normalized());
}
public void HandleWallHugging(float delta)
@@ -558,18 +645,20 @@ public partial class PlayerController : CharacterBody3D
Velocity = Vector3.Zero;
GlobalPosition = _wallHugStartLocation;
}
private Option<Vector3> _plannedMantleLocation = Option<Vector3>.None;
// Jump
public void OnInputJumpStarted()
{
if (CanMantle())
_currentJumpBufferFrames = InputBufferFrames;
_isJumpInputPressed = true;
PerformJump();
}
public void PerformJump()
{
if (MantleSystem.IsMantlePossible)
{
var location = _plannedMantleLocation.UnwrapOr(Vector3.Zero);
if (location == Vector3.Zero)
return; // For some reason CanMantle can return an invalid location so fuck off I guess
MantleToLocation(location);
_playerState.SendEvent("mantle");
return;
}
@@ -578,16 +667,23 @@ public partial class PlayerController : CharacterBody3D
_playerState.SendEvent("megajump");
return;
}
if (_onWall.Active && !_isWallJumpAvailable && IsFacingWall()) return;
_playerState.SendEvent("jump");
}
public bool IsFacingWall()
{
return _wallHugStartNormal.Dot(GetGlobalForwardFacingVector()) < -0.5f;
}
public void OnInputJumpOngoing()
{
}
public void OnInputJumpEnded()
{
_isJumpInputPressed = false;
_playerState.SendEvent("jump_ended");
}
@@ -603,7 +699,7 @@ public partial class PlayerController : CharacterBody3D
public void OnDoubleJumpStarted()
{
_canDash = true;
_canDashAirborne = true;
// _canDashAirborne = true;
OnJumpStarted(DoubleJumpStartVelocity);
}
public void OnMegaJumpStarted()
@@ -625,11 +721,24 @@ public partial class PlayerController : CharacterBody3D
var currentHorizontalVelocity = new Vector2(Velocity.X, Velocity.Z);
var wallJumpHorizontalVelocity = new Vector2(jumpVector.X, jumpVector.Z);
SetHorizontalVelocity(currentHorizontalVelocity + wallJumpHorizontalVelocity);;
SetHorizontalVelocity(currentHorizontalVelocity + wallJumpHorizontalVelocity);
}
public void OnJumpFromWallCoyote()
{
_isWallJumpAvailable = false;
}
public void OnJumpFromWall()
{
ComputeJumpFromWallHSpeed(WallJumpStartVelocity);
if (!IsFacingWall())
{
ComputeJumpFromWallHSpeed(WallJumpStartVelocity);
}
// Remove the ability to dash straight away so you cannot scale up the wall
_canDashAirborne = false;
_airborneDashCooldownTimer.Start();
_isWallJumpAvailable = false;
}
public void OnMegajumpFromWall()
{
@@ -687,8 +796,70 @@ public partial class PlayerController : CharacterBody3D
z: velocity.Y);
}
private Path _mantlePath;
private bool _customMantle;
private Transform3D _customMantleStartTransform;
private Curve3D _customMantleCurve;
private Vector3 _mantleStartPosition;
public void OnMantleStarted()
{
HeadSystem.OnMantle();
_mantlePath = MantlePath.Instantiate() as Path;
if (_mantlePath == null)
{
GD.PrintErr("Failed to instantiate MantlePath");
return;
}
var transform = _customMantle ? _customMantleStartTransform : MantleSystem.GlobalTransform;
var curve = _customMantle ? _customMantleCurve : MantleSystem.MantleCurve;
GetTree().GetRoot().AddChild(_mantlePath);
_mantlePath.Setup(transform, curve);
_mantleStartPosition = GlobalPosition;
var tween = GetTree().CreateTween();
tween.SetTrans(Tween.TransitionType.Linear);
tween.SetEase(Tween.EaseType.InOut);
tween.TweenProperty(_mantlePath.PathFollow, "progress_ratio", 1, MantleTime);
tween.Finished += MantleFinished;
}
public void HandleMantling(float delta)
{
GlobalPosition = _mantlePath.Target.GlobalPosition;
}
public void SimpleDashInDirection(Vector3 direction)
{
SetVelocity(direction * SimpleDashStrength);
}
public void SimpleDash()
{
SimpleDashInDirection(GetInputGlobalHDirection());
}
public void MantleFinished()
{
_mantlePath.Teardown();
var isThereMovementInput = GetMoveInput().Length() > 0;
if (isThereMovementInput)
{
// If there's a movement input on Mantle, we dash in the direction the mantle took place
var positionDifference = GlobalPosition - _mantleStartPosition;
var directionHorizontal = new Vector3(positionDifference.X, 0, positionDifference.Z);
SimpleDashInDirection(directionHorizontal.Normalized());
}
_customMantle = false;
_playerState.SendEvent("grounded");
}
public void HandleJump(float delta, float gravityFactor, int hangFrames)
{
if (IsTryingToMantle()) _playerState.SendEvent("mantle");
// Update horizontal velocity
var horizontalVelocity = ComputeHVelocityAir(delta);
Velocity = new Vector3(horizontalVelocity.X, Velocity.Y, horizontalVelocity.Z);
@@ -715,8 +886,8 @@ public partial class PlayerController : CharacterBody3D
SetVerticalVelocity(Velocity.Y - 2.0f);
}
// Move back to Airborne state management when starting to go down again
if (_framesSinceJumpAtApex > hangFrames)
// Move back to Airborne state when starting to go down again or if input isn't held anymore (buffered jump)
if (_framesSinceJumpAtApex > hangFrames || !_isJumpInputPressed)
_playerState.SendEvent("jump_ended");
}
public void HandleSimpleJump(float delta)
@@ -907,15 +1078,18 @@ public partial class PlayerController : CharacterBody3D
if (WeaponSystem.IsPlantedUnderPlatform())
dashLocation += Vector3.Down * _playerHeight;
_wallHugStartNormal = WeaponSystem.PlantNormal;
_currentWallContactPoint = WeaponSystem.PlantLocation;
_wallHugStartLocation = dashLocation;
_wallHugStartProjectedVelocity = Velocity.Slide(_wallHugStartNormal);
var dashTween = CreatePositionTween(dashLocation, AimedDashTime);
dashTween.Finished += DashToPlantedWeaponTweenEnded;
}
public void RecoverWeapon()
{
GetTree().GetRoot().RemoveChild(WeaponRoot);
AddChild(WeaponRoot);
WeaponRoot.SetGlobalPosition(GlobalPosition);
RecoverChildNode(WeaponRoot);
WeaponSystem.ResetWeapon();
}
@@ -928,12 +1102,11 @@ public partial class PlayerController : CharacterBody3D
RecoverWeapon();
var resultingEvent = shouldDashToHanging ? "to_planted" : "dash_finished";
var resultingEvent = shouldDashToHanging ? "dash_to_planted" : "dash_finished";
_playerState.SendEvent(resultingEvent);
}
private Vector3 _preDashVelocity = Vector3.Zero;
public void OnAimedDashStarted()
{
// Adjusting for player height, where the middle of the capsule should get to the dash location instead of the
@@ -947,9 +1120,10 @@ public partial class PlayerController : CharacterBody3D
var dashTween = CreatePositionTween(correctedLocation, AimedDashTime);
// dashTween.TweenMethod(Callable.From<float>(AimedDashTweenOngoing), 0.0f, 1.0f, AimedDashTime);
dashTween.Finished += AimedDashTweenEnded;
_shouldMantleOnDashEnded = DashSystem.ShouldMantle;
_mantleLocation = DashSystem.PlannedMantleLocation;
_customMantle = DashSystem.ShouldMantle;
_customMantleCurve = DashSystem.MantleSystem.MantleCurve;
_customMantleStartTransform = DashSystem.MantleSystem.GlobalTransform;
}
Tween CreatePositionTween(Vector3 targetLocation, float tweenTime)
@@ -968,6 +1142,13 @@ public partial class PlayerController : CharacterBody3D
_playerState.SendEvent("dash_finished");
}
public void OnAimedDashFinished()
{
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? PostDashSpeed : _preDashVelocity.Length();
Velocity = _dashDirection * postDashVelocity;
if (_customMantle) _playerState.SendEvent("mantle");
}
public void PlaceWeaponForTutorial()
{
if (TutorialDone)
@@ -978,14 +1159,25 @@ public partial class PlayerController : CharacterBody3D
WeaponRoot.CallDeferred(Node3D.MethodName.SetGlobalPosition, TutorialWeaponTarget.GlobalPosition);
WeaponSystem.CallDeferred(WeaponSystem.MethodName.PlaceWeaponForTutorial, TutorialWeaponTarget.GlobalPosition);
}
public void RemoveChildNode(Node3D node)
{
RemoveChild(node);
GetTree().GetRoot().AddChild(node);
node.SetGlobalPosition(GlobalPosition);
}
public void RecoverChildNode(Node3D node)
{
GetTree().GetRoot().RemoveChild(node);
AddChild(node);
node.SetGlobalPosition(GlobalPosition);
}
public void ThrowWeapon()
{
_playerState.SendEvent("cancel_aim");
RemoveChild(WeaponRoot);
GetTree().GetRoot().AddChild(WeaponRoot);
WeaponRoot.SetGlobalPosition(GlobalPosition);
RemoveChildNode(WeaponRoot);
var weaponTargetLocation = DashSystem.HasHit ? DashSystem.CollisionPoint : DashSystem.PlannedLocation;
WeaponSystem.ThrowWeapon(
@@ -995,25 +1187,12 @@ public partial class PlayerController : CharacterBody3D
DashSystem.CollisionNormal);
}
public void OnAimedDashFinished()
{
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? PostDashSpeed : _preDashVelocity.Length();
Velocity = _dashDirection * postDashVelocity;
if (_shouldMantleOnDashEnded)
MantleToLocation(_mantleLocation);
}
public void OnSimpleDashStarted()
{
if (!_canDash)
return;
_canDash = false;
var dashStrength = SimpleDashStrength;
var direction = GetInputGlobalHDirection();
SetVelocity(direction * dashStrength);
SimpleDash();
}
public void HandleSimpleDash(float delta)
@@ -1041,9 +1220,6 @@ public partial class PlayerController : CharacterBody3D
public void OnPoweredDashFinished()
{
// Try mantling but don't know if this is useful
// if (CanMantle())
// MantleToLocation(MantleSystem.FindMantleForHeadRotation(HeadSystem.Rotation.Y).Unwrap());
}
public void FinishPoweredDash()
@@ -1081,28 +1257,6 @@ public partial class PlayerController : CharacterBody3D
_playerState.SendEvent("coyote_expired");
}
// Mantling
public bool CanMantle()
{
var mantleLocationResult = MantleSystem.FindMantleForHeadRotation(HeadSystem.Rotation.Y);
return mantleLocationResult.IsSome(out _);
}
private Vector3 _preMantleVelocity = Vector3.Zero;
public void MantleToLocation(Vector3 location)
{
HeadSystem.OnMantle();
_preMantleVelocity = Velocity;
var mantleTween = CreatePositionTween(location, MantleTime);
mantleTween.Finished += MantleFinished;
}
public void MantleFinished()
{
Velocity = _preMantleVelocity;
_playerState.SendEvent("grounded");
}
///////////////////////////
// Stateless logic ////////
///////////////////////////
@@ -1111,7 +1265,7 @@ public partial class PlayerController : CharacterBody3D
Vector2 inputLookDir = new Vector2(_inputRotateY, _inputRotateFloorplane);
var lookSensitivity = _isUsingGamepad ? _lookSensitivityMultiplier : _mouseSensitivityMultiplier;
var wallHugContactPoint = _onWallRunning.Active ? _currentWallContactPoint : Vector3.Zero;
var wallHugContactPoint = _onWallRunning.Active || _onWallRunningCoyoteEnabled.Active ? _currentWallContactPoint : Vector3.Zero;
var playerVelocity = GetGlobalMoveInput();
HeadSystem.LookAround(delta, inputLookDir, playerVelocity, wallHugContactPoint, lookSensitivity);
}
@@ -1191,7 +1345,7 @@ public partial class PlayerController : CharacterBody3D
Bobbing.CameraBobbingParams cameraBobbingParams = new Bobbing.CameraBobbingParams
{
Delta = delta,
IsOnFloorCustom = isOnFloorCustom() || _onWallRunning.Active,
IsOnFloorCustom = isOnFloorCustom() || _onWallRunning.Active || _onWallRunningCoyoteEnabled.Active,
Velocity = Velocity,
SettingsMultiplier = _headBobbingMultiplier
};
@@ -1246,16 +1400,23 @@ public partial class PlayerController : CharacterBody3D
{
WeaponRoot.SetRotation(HeadSystem.Rotation);
}
public Vector3 GetGlobalForwardFacingVector()
{
return Transform.Basis * HeadSystem.Transform.Basis * Vector3.Forward;
}
///////////////////////////
// Processes //////////////
///////////////////////////
public override void _PhysicsProcess(double delta)
{
if (_currentJumpBufferFrames > 0) _currentJumpBufferFrames -= 1;
LookAround(delta);
CameraModifications((float) delta);
HandleStairs((float) delta);
_plannedMantleLocation = MantleSystem.FindMantleForHeadRotation(HeadSystem.Rotation.Y);
MantleSystem.ProcessMantle(_grounded.Active);
if (WeaponSystem.InHandState.Active)
RotateWeaponWithPlayer();

25
scenes/path/Path.cs Normal file
View File

@@ -0,0 +1,25 @@
using Godot;
public partial class Path : Path3D
{
public PathFollow3D PathFollow { get; private set; }
public Marker3D Target { get; private set; }
public override void _Ready()
{
PathFollow = GetNode<PathFollow3D>("PathFollow");
Target = GetNode<Marker3D>("PathFollow/Target");
}
public void Setup(Transform3D globalTransform, Curve3D curve)
{
SetGlobalTransform(globalTransform);
SetCurve(curve);
PathFollow.ProgressRatio = 0;
}
public void Teardown()
{
QueueFree();
}
}

1
scenes/path/Path.cs.uid Normal file
View File

@@ -0,0 +1 @@
uid://djdr5bvfc8f0x

13
scenes/path/path.tscn Normal file
View File

@@ -0,0 +1,13 @@
[gd_scene load_steps=3 format=3 uid="uid://cf3rrgr1imvv4"]
[ext_resource type="Script" uid="uid://djdr5bvfc8f0x" path="res://scenes/path/Path.cs" id="1_kmlhi"]
[sub_resource type="Curve3D" id="Curve3D_u4rfr"]
[node name="Path" type="Path3D"]
curve = SubResource("Curve3D_u4rfr")
script = ExtResource("1_kmlhi")
[node name="PathFollow" type="PathFollow3D" parent="."]
[node name="Target" type="Marker3D" parent="PathFollow"]

View File

@@ -20,19 +20,17 @@ public partial class DashSystem: Node3D
public bool ShouldMantle { get; set; }
public Vector3 PlannedMantleLocation { get; set; }
public MantleSystem MantleSystem { get; set; }
private Node3D _head;
private ShapeCast3D _dashCast3D;
private ShapeCast3D _playerCast3D;
private Camera3D _camera;
private TweenQueueSystem _tweenQueueSystem;
private Vector3 _dashDirection = Vector3.Zero;
private ShapeCast3D _dashCastDrop;
private MeshInstance3D _dashDropIndicator;
private MeshInstance3D _dashDropLocationIndicator;
private MantleSystem _mantleSystem;
private MeshInstance3D _dashTarget;
private CpuParticles3D _dashIndicator;
private AnimationPlayer _dashIndicatorAnim;
@@ -48,13 +46,10 @@ public partial class DashSystem: Node3D
public delegate void DashProgressEventHandler(float progress);
private Vector3 _globalDashPosition = Vector3.Zero;
private float _playerHeight;
private float _playerRadius;
public float DashCastRadius { get; set; }
public void Init(Node3D head, Camera3D camera, TweenQueueSystem tweenQueueSystem)
public void Init(Node3D head, Camera3D camera)
{
_dashCast3D = GetNode<ShapeCast3D>("DashCast3D");
var dashShape = _dashCast3D.GetShape() as SphereShape3D;
@@ -66,17 +61,11 @@ public partial class DashSystem: Node3D
_dashDropLocationIndicator = GetNode<MeshInstance3D>("DashDropLocationIndicator");
_dashDropLocationIndicator.Visible = false;
_playerCast3D = GetNode<ShapeCast3D>("PlayerShapeCast3D");
var playerShape = _playerCast3D.GetShape() as CapsuleShape3D;
_playerHeight = playerShape!.Height;
_playerRadius = playerShape!.Radius;
_head = head;
_camera = camera;
_tweenQueueSystem = tweenQueueSystem;
_mantleSystem = GetNode<MantleSystem>("MantleSystem");
_mantleSystem.Init();
MantleSystem = GetNode<MantleSystem>("MantleSystem");
MantleSystem.Init();
_dashTarget = GetNode<MeshInstance3D>("DashTarget");
_dashTarget.SetVisible(false);
@@ -111,14 +100,15 @@ public partial class DashSystem: Node3D
(HasHit, PlannedLocation, CollisionPoint, CollisionNormal) = ComputeDashLocation();
ShouldMantle = false;
var mantleLocation = Vector3.Zero;
if (HasHit && Mathf.Abs(CollisionNormal.Y) < 0.5f)
{
var mantleResult = _mantleSystem.FindMantleLocationAtPoint(PlannedLocation, CollisionNormal);
ShouldMantle = mantleResult.IsSome(out mantleLocation);
}
PlannedMantleLocation = mantleLocation;
// TODO: Position mantle system to planned location, aligned with ground planned and facing the same way as the dash
// Then query it being careful when dashing underneath a platform and such
MantleSystem.SetGlobalPosition(PlannedLocation);
MantleSystem.SetRotation(new Vector3(
MantleSystem.Rotation.X,
_head.Rotation.Y,
MantleSystem.Rotation.Z));
MantleSystem.ProcessMantle(false);
ShouldMantle = MantleSystem.IsMantlePossible;
// Setup dash target
var targetColor = HasHit ? new Color(1f, 0.2f, 0.2f) : new Color(1f, 1f, 1f);
@@ -126,7 +116,7 @@ public partial class DashSystem: Node3D
var targetMaterial = (StandardMaterial3D) _dashTarget.GetSurfaceOverrideMaterial(0);
targetMaterial.SetAlbedo(targetColor);
_dashTarget.SetVisible(true);
var targetLocation = ShouldMantle ? PlannedMantleLocation : PlannedLocation;
var targetLocation = ShouldMantle ? MantleSystem.FirstMantleProfilePoint : PlannedLocation;
_dashTarget.SetGlobalPosition(targetLocation);
var shouldShowDropIndicator = !HasHit && !ShouldMantle;
@@ -162,6 +152,5 @@ public partial class DashSystem: Node3D
public void StartPreparingDash()
{
_dashTarget.SetVisible(true);
}
}

View File

@@ -1,7 +1,6 @@
[gd_scene load_steps=10 format=3 uid="uid://cqduhd4opgwvm"]
[gd_scene load_steps=9 format=3 uid="uid://cqduhd4opgwvm"]
[ext_resource type="Script" uid="uid://dwoppk8j5fxeg" path="res://systems/dash/DashSystem.cs" id="1_hwig2"]
[ext_resource type="Shape3D" uid="uid://keseacdcooot" path="res://player_controller/resources/PlayerShape.tres" id="2_jngg2"]
[ext_resource type="PackedScene" uid="uid://wq1okogkhc5l" path="res://systems/mantle/mantle_system.tscn" id="2_pff7b"]
[ext_resource type="PackedScene" uid="uid://hd0868f4pb63" path="res://systems/dash/dash_indicator.tscn" id="2_tqt6i"]
@@ -24,13 +23,6 @@ outer_radius = 0.5
script = ExtResource("1_hwig2")
DashIndicatorScene = ExtResource("2_tqt6i")
[node name="PlayerShapeCast3D" type="ShapeCast3D" parent="."]
visible = false
shape = ExtResource("2_jngg2")
target_position = Vector3(0, 0, 0)
collision_mask = 2
debug_shape_custom_color = Color(0.863327, 0.636844, 0, 1)
[node name="DashCast3D" type="ShapeCast3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
shape = SubResource("SphereShape3D_jngg2")

View File

@@ -82,7 +82,6 @@ func on_input_hit():
input_hit.emit()
func on_input_jump_started():
print("jump")
input_jump_started.emit()
func on_input_jump_ongoing():

View File

@@ -14,46 +14,96 @@ public partial class MantleSystem: Node3D
private ShapeCast3D _wallInFrontCast3D;
private ShapeCast3D _mantleCast3D;
private RayCast3D _mantleCheckCast3D;
private ShapeCast3D _inAirWallDetect;
private ShapeCast3D _groundedWallDetect;
public Curve3D MantleCurve { get; private set; }
public Vector3 FirstMantleProfilePoint { get; private set; } = Vector3.Zero;
public bool IsMantlePossible { get; private set; } = false;
public const int WallProfileCastCount = 7;
private ShapeCast3D[] _wallProfileShapecasts = new ShapeCast3D[WallProfileCastCount];
public void Init()
{
_wallInFrontCast3D = GetNode<ShapeCast3D>("WallInFrontCast3D");
_mantleCast3D = GetNode<ShapeCast3D>("MantleCast3D");
_inAirWallDetect = GetNode<ShapeCast3D>("InAirWallDetect");
_groundedWallDetect = GetNode<ShapeCast3D>("GroundedWallDetect");
for (int i = 0; i < _wallProfileShapecasts.Length; i++)
{
_wallProfileShapecasts[i] = GetNode<ShapeCast3D>($"WallProfileShapeCasts/ShapeCast{i + 1}");
}
}
public Option<Vector3> FindMantleForHeadRotation(float rotation)
private void SetCastsEnabled(bool enabled)
{
_wallInFrontCast3D.SetRotation(new Vector3(
_wallInFrontCast3D.Rotation.X,
rotation,
_wallInFrontCast3D.Rotation.Z));
if (!_wallInFrontCast3D.IsColliding())
foreach (var wallProfileShapecast in _wallProfileShapecasts)
{
return Option<Vector3>.None;
wallProfileShapecast.SetEnabled(enabled);
}
if (_wallInFrontCast3D.GetCollisionNormal(0).Y > 0.8f)
{
return Option<Vector3>.None;
}
var collisionPoint = _wallInFrontCast3D.GetCollisionPoint(0);
var collisionNormal = _wallInFrontCast3D.GetCollisionNormal(0);
return FindMantleLocationAtPoint(collisionPoint, collisionNormal);
}
public Option<Vector3> FindMantleLocationAtPoint(Vector3 point, Vector3 wallNormal)
public void ProcessMantle(bool isGrounded)
{
var horizontalEndLocation = point - wallNormal * MantleEndLocationDistanceFromWall;
var shapeCastStartLocation = horizontalEndLocation + Vector3.Up * MantleHeightCastStart;
_inAirWallDetect.SetEnabled(!isGrounded);
_groundedWallDetect.SetEnabled(isGrounded);
var isColliding = _inAirWallDetect.IsColliding() || _groundedWallDetect.IsColliding();
SetCastsEnabled(isColliding);
_mantleCast3D.SetGlobalPosition(shapeCastStartLocation);
var targetLocation = Vector3.Down * MantleHeightCastStart + Vector3.Up * MaxStepHeight;
_mantleCast3D.SetTargetPosition(targetLocation);
// Reset state
IsMantlePossible = false;
if (!isColliding) return;
if (_mantleCast3D.IsColliding() && _mantleCast3D.GetCollisionNormal(0).Y >= 0.1f)
return Option.Some(_mantleCast3D.GetCollisionPoint(0));
return Option<Vector3>.None;
// Check if face something wall-like that should be climbable
var collisionNormal = isGrounded ? _groundedWallDetect.GetCollisionNormal(0) : _inAirWallDetect.GetCollisionNormal(0);
if (collisionNormal.Y > 0.7f) return;
var spaceState = GetWorld3D().DirectSpaceState;
MantleCurve = new Curve3D();
MantleCurve.AddPoint(Vector3.Zero);
var hasFirstProfileHit = false;
var previousProfilePoint = GlobalPosition;
foreach (var wallProfileShapecast in _wallProfileShapecasts)
{
// Haven't met the wall yet
if (!wallProfileShapecast.IsColliding() && !hasFirstProfileHit) continue;
var globalTargetPosition = wallProfileShapecast.GlobalPosition + wallProfileShapecast.TargetPosition;
// Got to the other side of the wall, we stop there
if (!wallProfileShapecast.IsColliding())
{
// MantleCurve.AddPoint(ToLocal(globalTargetPosition));
break;
}
var profilePoint = wallProfileShapecast.GetCollisionPoint(0);
var profileNormal = wallProfileShapecast.GetCollisionNormal(0);
var shape = wallProfileShapecast.Shape as SphereShape3D;
var shapeRadius = shape == null ? 0.125f : shape.Radius;
var centerOfShape = profilePoint + profileNormal * shapeRadius;
// Check if we collided parallel to a wall
var isCollisionSameAsTarget = globalTargetPosition.IsEqualApprox(centerOfShape);
var isCollidingWithWall = profileNormal.Y < 0.1f;
if (isCollisionSameAsTarget || isCollidingWithWall) continue;
// Check if the path from the previous point makes us go through a wall
var query = PhysicsRayQueryParameters3D.Create(previousProfilePoint, centerOfShape, wallProfileShapecast.CollisionMask);
var result = spaceState.IntersectRay(query);
if (result.Count > 0) break; // We are going through a wall, we stop there
// We have a valid collision
if (!hasFirstProfileHit) FirstMantleProfilePoint = centerOfShape;
hasFirstProfileHit = true;
previousProfilePoint = centerOfShape;
MantleCurve.AddPoint(ToLocal(centerOfShape));
}
if (MantleCurve.PointCount == 1) return;
IsMantlePossible = true;
}
}

View File

@@ -0,0 +1,4 @@
[gd_resource type="SphereShape3D" format=3 uid="uid://dp2p8v7demb5j"]
[resource]
radius = 0.25

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=4 format=3 uid="uid://wq1okogkhc5l"]
[gd_scene load_steps=7 format=3 uid="uid://wq1okogkhc5l"]
[ext_resource type="Script" uid="uid://bja6tis1vaysu" path="res://systems/mantle/MantleSystem.cs" id="1_2oobp"]
@@ -8,12 +8,23 @@ height = 1.7
[sub_resource type="SphereShape3D" id="SphereShape3D_2oobp"]
radius = 0.75
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_2oobp"]
radius = 0.25
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_i32qj"]
radius = 0.25
height = 1.5
[sub_resource type="SphereShape3D" id="SphereShape3D_i32qj"]
radius = 0.125
[node name="MantleSystem" type="Node3D"]
script = ExtResource("1_2oobp")
MantleEndLocationDistanceFromWall = 0.2
MantleHeightCastStart = 3.0
[node name="MantleCast3D" type="ShapeCast3D" parent="."]
visible = false
shape = SubResource("CapsuleShape3D_4coqe")
target_position = Vector3(0, 0, 0)
max_results = 1
@@ -22,8 +33,72 @@ debug_shape_custom_color = Color(1, 0, 0, 1)
[node name="WallInFrontCast3D" type="ShapeCast3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
visible = false
shape = SubResource("SphereShape3D_2oobp")
target_position = Vector3(0, 0, -1.5)
max_results = 1
collision_mask = 2
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
[node name="InAirWallDetect" type="ShapeCast3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.01, 0)
shape = SubResource("CapsuleShape3D_2oobp")
target_position = Vector3(0, 0, -2)
collision_mask = 2
[node name="GroundedWallDetect" type="ShapeCast3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.26, 0)
shape = SubResource("CapsuleShape3D_i32qj")
target_position = Vector3(0, 0, -2)
collision_mask = 2
[node name="WallProfileShapeCasts" type="Node3D" parent="."]
[node name="ShapeCast1" type="ShapeCast3D" parent="WallProfileShapeCasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -0.5)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 2
[node name="ShapeCast2" type="ShapeCast3D" parent="WallProfileShapeCasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -0.75)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 2
[node name="ShapeCast3" type="ShapeCast3D" parent="WallProfileShapeCasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -1)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 2
[node name="ShapeCast4" type="ShapeCast3D" parent="WallProfileShapeCasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -1.25)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 2
[node name="ShapeCast5" type="ShapeCast3D" parent="WallProfileShapeCasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -1.5)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 2
[node name="ShapeCast6" type="ShapeCast3D" parent="WallProfileShapeCasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -1.75)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 2
[node name="ShapeCast7" type="ShapeCast3D" parent="WallProfileShapeCasts"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -2)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 2