improved AI
parent
b18b011133
commit
dc5c06dafa
Binary file not shown.
|
@ -0,0 +1,27 @@
|
|||
[gd_resource type="ParticleProcessMaterial" load_steps=3 format=3 uid="uid://b64pfv5ocwegv"]
|
||||
|
||||
[sub_resource type="Gradient" id="Gradient_p5otp"]
|
||||
offsets = PackedFloat32Array(0, 0.2, 0.5, 0.6, 0.7, 0.8, 1)
|
||||
colors = PackedColorArray(0.105882, 0.0470588, 0.117647, 0, 0.105882, 0.0470588, 0.117647, 1, 0.105882, 0.0470588, 0.117647, 1, 0.0509804, 0.258824, 0.109804, 1, 0.396078, 0.658824, 0.309804, 1, 0.745098, 0.85098, 0.513726, 1, 0.745098, 0.85098, 0.513726, 0)
|
||||
|
||||
[sub_resource type="GradientTexture1D" id="GradientTexture1D_4a2pn"]
|
||||
gradient = SubResource("Gradient_p5otp")
|
||||
|
||||
[resource]
|
||||
lifetime_randomness = 0.5
|
||||
emission_shape = 6
|
||||
emission_ring_axis = Vector3(0, 0, 1)
|
||||
emission_ring_height = 1.0
|
||||
emission_ring_radius = 128.0
|
||||
emission_ring_inner_radius = 64.0
|
||||
particle_flag_disable_z = true
|
||||
direction = Vector3(2, 1, 0)
|
||||
gravity = Vector3(32, 32, 0)
|
||||
initial_velocity_min = 32.0
|
||||
initial_velocity_max = 64.0
|
||||
angular_velocity_max = 30.0
|
||||
orbit_velocity_min = 0.0
|
||||
orbit_velocity_max = 0.0
|
||||
color_ramp = SubResource("GradientTexture1D_4a2pn")
|
||||
turbulence_enabled = true
|
||||
turbulence_noise_speed = Vector3(1, 0, 0)
|
|
@ -19,6 +19,15 @@ public partial class Doc : Boss
|
|||
get => base.IsActive;
|
||||
set
|
||||
{
|
||||
// if player not alive or doesn't exist then don't activate
|
||||
if (!this.GetWorld()?.CurrentPlayer?.IsAlive ?? true)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
base.IsActive = value;
|
||||
var introState = BossStateMachine
|
||||
.GetNode<State.NPC.Doc.DocIntroState>("Intro");
|
||||
|
@ -101,10 +110,12 @@ public partial class Doc : Boss
|
|||
};
|
||||
|
||||
|
||||
CanAttack = false;
|
||||
|
||||
// when we are hurt, start the boss fight
|
||||
Hurt += (Events.HurtArgs args) =>
|
||||
{
|
||||
if (!IsActive)
|
||||
if (this.GetWorld().CurrentPlayer.IsAlive && !IsActive)
|
||||
{
|
||||
IsActive = true;
|
||||
Inventory.SelectedItem = Lance;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=69 format=3 uid="uid://d2skjvvx6fal0"]
|
||||
[gd_scene load_steps=68 format=3 uid="uid://d2skjvvx6fal0"]
|
||||
|
||||
[ext_resource type="Script" path="res://Characters/Doc.cs" id="2_3elet"]
|
||||
[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_5jxom"]
|
||||
|
@ -34,7 +34,6 @@
|
|||
[ext_resource type="Script" path="res://State/Thinker/AttackState.cs" id="21_ij3bp"]
|
||||
[ext_resource type="Animation" uid="uid://8e8r3y1imvsx" path="res://Assets/Animations/stun.res" id="21_ixn4k"]
|
||||
[ext_resource type="PackedScene" uid="uid://p7oijq6dbvvk" path="res://Items/Weapons/DocLance.tscn" id="24_2es2r"]
|
||||
[ext_resource type="PackedScene" uid="uid://bauucuqvjwbxp" path="res://Items/Weapons/DocLanceHold.tscn" id="26_0tntj"]
|
||||
[ext_resource type="AudioStream" uid="uid://cqj44je3mvk60" path="res://Assets/Sounds/rauuul.wav" id="26_js7p2"]
|
||||
[ext_resource type="PackedScene" uid="uid://dldnp8eunxj3q" path="res://BoundingBoxes/InteractionTrigger.tscn" id="33_08dyq"]
|
||||
|
||||
|
@ -555,7 +554,7 @@ size = Vector2(16, 19)
|
|||
[sub_resource type="CircleShape2D" id="CircleShape2D_8hwat"]
|
||||
radius = 16.0
|
||||
|
||||
[node name="Doc" type="CharacterBody2D" node_paths=PackedStringArray("Lance", "BossStateMachine", "ThinkerStateMachine", "Sprite", "Inventory", "StateMachine", "Hurtbox")]
|
||||
[node name="Doc" type="CharacterBody2D" node_paths=PackedStringArray("Lance", "BossStateMachine", "DefaultSelectedItem", "ThinkerStateMachine", "Sprite", "Inventory", "StateMachine", "Hurtbox")]
|
||||
y_sort_enabled = true
|
||||
texture_filter = 3
|
||||
material = SubResource("ShaderMaterial_7n7iy")
|
||||
|
@ -566,6 +565,7 @@ Lance = NodePath("Inventory/DocLance")
|
|||
BossStateMachine = NodePath("BossStateMachine")
|
||||
BossName = "Doc, The Two-Time"
|
||||
Music = ExtResource("3_eo4lg")
|
||||
DefaultSelectedItem = NodePath("Inventory/DocLance")
|
||||
ThinkerStateMachine = NodePath("ThinkerStateMachine")
|
||||
HandTexture = ExtResource("4_8lqj6")
|
||||
Health = 900.0
|
||||
|
@ -669,12 +669,16 @@ NPC = NodePath("../..")
|
|||
script = ExtResource("20_dy57x")
|
||||
InitialState = NodePath("Attack")
|
||||
|
||||
[node name="Idle" type="Node" parent="ThinkerStateMachine"]
|
||||
|
||||
[node name="Attack" type="Node" parent="ThinkerStateMachine" node_paths=PackedStringArray("NPC")]
|
||||
script = ExtResource("21_ij3bp")
|
||||
NPC = NodePath("../..")
|
||||
|
||||
[node name="DashDefensive" type="Node" parent="ThinkerStateMachine" node_paths=PackedStringArray("NPC")]
|
||||
script = ExtResource("20_12htp")
|
||||
MaxDistanceToTarget = 256.0
|
||||
UseItemDistance = 64.0
|
||||
NPC = NodePath("../..")
|
||||
|
||||
[node name="Animations" type="Node" parent="."]
|
||||
|
@ -750,7 +754,6 @@ attenuation = 0.5
|
|||
stream = ExtResource("9_stm0e")
|
||||
|
||||
[node name="Sprite" type="Sprite2D" parent="."]
|
||||
modulate = Color(1, 1, 1, 0.5)
|
||||
y_sort_enabled = true
|
||||
use_parent_material = true
|
||||
position = Vector2(-0.5, 0)
|
||||
|
@ -777,8 +780,6 @@ script = ExtResource("8_r8ejq")
|
|||
[node name="DocLance" parent="Inventory" instance=ExtResource("24_2es2r")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="DocLanceHold" parent="Inventory" instance=ExtResource("26_0tntj")]
|
||||
|
||||
[node name="InteractionTrigger" parent="." instance=ExtResource("33_08dyq")]
|
||||
|
||||
[node name="CollisionShape2D" parent="InteractionTrigger" index="0"]
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
[ext_resource type="Script" path="res://State/Character/NPCIdleState.cs" id="4_47f2d"]
|
||||
[ext_resource type="Script" path="res://State/Character/NPCMoveState.cs" id="5_iphm1"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/ThinkerStateMachine.cs" id="6_6516i"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/BlockAttackState.cs" id="7_vgjig"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/CenturionAttackState.cs" id="7_n2slg"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/IdleState.cs" id="8_5neew"]
|
||||
[ext_resource type="Script" path="res://Utils/AnimationManager.cs" id="9_fgnr2"]
|
||||
[ext_resource type="Animation" uid="uid://8e8r3y1imvsx" path="res://Assets/Animations/stun.res" id="10_1erll"]
|
||||
|
@ -308,8 +308,11 @@ Character = NodePath("../..")
|
|||
script = ExtResource("6_6516i")
|
||||
InitialState = NodePath("Idle")
|
||||
|
||||
[node name="Attack" type="Node" parent="ThinkerStateMachine" node_paths=PackedStringArray("PassiveState", "PursueState", "NPC")]
|
||||
script = ExtResource("7_vgjig")
|
||||
[node name="Attack" type="Node" parent="ThinkerStateMachine" node_paths=PackedStringArray("NavigationAgent", "PassiveState", "PursueState", "NPC")]
|
||||
script = ExtResource("7_n2slg")
|
||||
FollowTeammate = true
|
||||
NavigationAgent = NodePath("../../NavigationAgent2D")
|
||||
PathfindingDistance = 4.0
|
||||
PreferredWeightDistance = 24.0
|
||||
MaxDistanceToTarget = 128.0
|
||||
UseItemDistance = 48.0
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=41 format=3 uid="uid://cdj50hb84aujp"]
|
||||
[gd_scene load_steps=43 format=3 uid="uid://cdj50hb84aujp"]
|
||||
|
||||
[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="1_hvgeb"]
|
||||
[ext_resource type="Script" path="res://Characters/Enemy.cs" id="2_h5w5n"]
|
||||
|
@ -6,9 +6,11 @@
|
|||
[ext_resource type="Script" path="res://State/Character/NPCIdleState.cs" id="4_1ngkf"]
|
||||
[ext_resource type="Script" path="res://State/Character/NPCMoveState.cs" id="5_wcpa1"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/ThinkerStateMachine.cs" id="6_121gp"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/AttackState.cs" id="8_8a6v2"]
|
||||
[ext_resource type="Script" path="res://State/Character/CharacterDashState.cs" id="6_pwguk"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/DashDefensive.cs" id="8_n8t7f"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/IdleState.cs" id="9_ewnq3"]
|
||||
[ext_resource type="Script" path="res://Utils/AnimationManager.cs" id="9_ssmee"]
|
||||
[ext_resource type="Script" path="res://State/Thinker/PursueState.cs" id="9_u7gxx"]
|
||||
[ext_resource type="Animation" uid="uid://8e8r3y1imvsx" path="res://Assets/Animations/stun.res" id="10_oplmj"]
|
||||
[ext_resource type="Material" uid="uid://bat28samf7ukd" path="res://Assets/Sprites/Particles/NPCDamageProcessMaterial.tres" id="11_qcw5x"]
|
||||
[ext_resource type="Texture2D" uid="uid://bd8l8kafb42dt" path="res://Assets/Sprites/Particles/circle.png" id="12_rlelw"]
|
||||
|
@ -142,18 +144,6 @@ tracks/3/keys = {
|
|||
"update": 1,
|
||||
"values": [false]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("Sprites/Node2D/Character:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [8]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_lhc4c"]
|
||||
resource_name = "death"
|
||||
|
@ -225,18 +215,6 @@ tracks/2/keys = {
|
|||
"method": &"restart"
|
||||
}]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = false
|
||||
tracks/3/path = NodePath("Sprites/Node2D/Character:frame")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [8]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_rc55s"]
|
||||
_data = {
|
||||
|
@ -306,11 +284,12 @@ script = ExtResource("2_h5w5n")
|
|||
DefaultSelectedItem = NodePath("Inventory/DocLance")
|
||||
ThinkerStateMachine = NodePath("ThinkerStateMachine")
|
||||
Speed = 56.0
|
||||
Health = 170.0
|
||||
Health = 130.0
|
||||
Sprite = NodePath("Sprites/Node2D/Character")
|
||||
Inventory = NodePath("Inventory")
|
||||
StateMachine = NodePath("StateMachine")
|
||||
Hurtbox = NodePath("Hurtbox")
|
||||
metadata/_edit_vertical_guides_ = []
|
||||
|
||||
[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState", "Character")]
|
||||
script = ExtResource("3_04p3j")
|
||||
|
@ -327,21 +306,28 @@ script = ExtResource("5_wcpa1")
|
|||
IdleState = NodePath("../Idle")
|
||||
Character = NodePath("../..")
|
||||
|
||||
[node name="Dash" type="Node" parent="StateMachine" node_paths=PackedStringArray("IdleState", "Character")]
|
||||
script = ExtResource("6_pwguk")
|
||||
IdleState = NodePath("../Idle")
|
||||
TimeToDash = 0.1
|
||||
VelocityModifier = 4.0
|
||||
Character = NodePath("../..")
|
||||
|
||||
[node name="ThinkerStateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
|
||||
script = ExtResource("6_121gp")
|
||||
InitialState = NodePath("Idle")
|
||||
|
||||
[node name="Attack" type="Node" parent="ThinkerStateMachine" node_paths=PackedStringArray("PassiveState", "PursueState", "NPC")]
|
||||
script = ExtResource("8_8a6v2")
|
||||
script = ExtResource("8_n8t7f")
|
||||
MaxDistanceToTarget = 128.0
|
||||
UseItemDistance = 64.0
|
||||
PassiveState = NodePath("../Idle")
|
||||
PursueState = NodePath("../Idle")
|
||||
PursueState = NodePath("../Pursue")
|
||||
NPC = NodePath("../..")
|
||||
|
||||
[node name="Idle" type="Node" parent="ThinkerStateMachine" node_paths=PackedStringArray("PursueState", "NavigationAgent", "NPC")]
|
||||
script = ExtResource("9_ewnq3")
|
||||
PursueState = NodePath("../Attack")
|
||||
PursueState = NodePath("../Pursue")
|
||||
MinTargetDistance = 24.0
|
||||
PursueOnLineOfSight = true
|
||||
MinLineOfSightDistance = 256.0
|
||||
|
@ -349,9 +335,17 @@ ShouldReturnToOriginalPosition = true
|
|||
NavigationAgent = NodePath("../../NavigationAgent2D")
|
||||
NPC = NodePath("../..")
|
||||
|
||||
[node name="Pursue" type="Node" parent="ThinkerStateMachine" node_paths=PackedStringArray("NavigationAgent", "AttackState", "PassiveState", "NPC")]
|
||||
script = ExtResource("9_u7gxx")
|
||||
NavigationAgent = NodePath("../../NavigationAgent2D")
|
||||
AttackState = NodePath("../Attack")
|
||||
PassiveState = NodePath("../Idle")
|
||||
MinDistanceToTarget = 72.0
|
||||
MaxDistanceFromOrigin = 128.0
|
||||
NPC = NodePath("../..")
|
||||
|
||||
[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
|
||||
target_desired_distance = 16.0
|
||||
debug_enabled = true
|
||||
|
||||
[node name="Animations" type="Node" parent="."]
|
||||
script = ExtResource("9_ssmee")
|
||||
|
|
|
@ -48,6 +48,15 @@ public sealed partial class Player : Character
|
|||
};
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
base._Process(delta);
|
||||
|
||||
var mod = Sprite.SelfModulate;
|
||||
mod.A = 1 - (Stealth / 2);
|
||||
Sprite.SelfModulate = mod;
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (StateMachine != null)
|
||||
|
|
|
@ -38,4 +38,9 @@ public static class Node2DExtensions
|
|||
node.GlobalPosition = position;
|
||||
return node;
|
||||
}
|
||||
|
||||
public static float DistanceTo(this Node2D node, Node2D other)
|
||||
{
|
||||
return node.GlobalPosition.DistanceTo(other.GlobalPosition);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -23,7 +23,7 @@ public partial class CharacterDashState : CharacterState
|
|||
_timeLeftToDash = TimeToDash;
|
||||
// dash the direction we were previously moving in
|
||||
DashDirection = Character.Direction;
|
||||
Character.MovementAnimation.Play("dash");
|
||||
Character.MovementAnimation.TryPlay("dash");
|
||||
Character.MovementAnimation.Queue("idle");
|
||||
|
||||
// create ghost effect
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
using Godot;
|
||||
using SupaLidlGame.Extensions;
|
||||
|
||||
namespace SupaLidlGame.State.Thinker;
|
||||
|
||||
public partial class CenturionAttackState : BlockAttackState
|
||||
{
|
||||
[Export]
|
||||
public bool FollowTeammate { get; set; } = false;
|
||||
|
||||
[Export]
|
||||
public NavigationAgent2D NavigationAgent { get; set; }
|
||||
|
||||
[Export]
|
||||
public float PathfindingDistance { get; set; } = 64;
|
||||
|
||||
protected Characters.Character _bestTeammate = null;
|
||||
|
||||
public Characters.Character FindBestTeammate()
|
||||
{
|
||||
float bestScore = float.MaxValue;
|
||||
Characters.Character bestChar = null;
|
||||
var world = this.GetWorld();
|
||||
|
||||
foreach (Node node in world.CurrentMap.Entities.GetChildren())
|
||||
{
|
||||
if (node != NPC && node is Characters.Character character)
|
||||
{
|
||||
if (!IsInstanceValid(character) || !character.IsAlive)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (character.Faction == NPC.Faction)
|
||||
{
|
||||
float score = NPC.Position.DistanceTo(character.Position);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
bestChar = character;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _bestTeammate = bestChar;
|
||||
}
|
||||
|
||||
public override ThinkerState Think()
|
||||
{
|
||||
base.Think();
|
||||
|
||||
var teammate = FindBestTeammate();
|
||||
if (teammate is not null)
|
||||
{
|
||||
UpdateWeights(teammate.GlobalPosition);
|
||||
NavigationAgent.TargetPosition = teammate.GlobalPosition;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override ThinkerState Process(double delta)
|
||||
{
|
||||
if (_bestTeammate is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
float dist = NPC.DistanceTo(_bestTeammate);
|
||||
if (NPC.DistanceTo(_bestTeammate) < PathfindingDistance)
|
||||
{
|
||||
// move to weighted position
|
||||
return base.Process(delta);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override ThinkerState PhysicsProcess(double delta)
|
||||
{
|
||||
if (_bestTeammate is not null)
|
||||
{
|
||||
float dist = NPC.DistanceTo(_bestTeammate);
|
||||
if (dist >= PathfindingDistance)
|
||||
{
|
||||
var nextPos = NavigationAgent.GetNextPathPosition();
|
||||
NPC.Direction = NPC.GlobalPosition.DirectionTo(nextPos);
|
||||
}
|
||||
}
|
||||
|
||||
return base.PhysicsProcess(delta);
|
||||
}
|
||||
}
|
|
@ -25,9 +25,22 @@ public partial class DashDefensive : AttackState
|
|||
Vector2 pos = bestTarget.GlobalPosition;
|
||||
NPC.Target = pos - NPC.GlobalPosition;
|
||||
Vector2 dir = NPC.GlobalPosition.DirectionTo(pos);
|
||||
float dist = NPC.GlobalPosition.DistanceSquaredTo(pos);
|
||||
float dist = NPC.GlobalPosition.DistanceTo(pos);
|
||||
UpdateWeights(pos);
|
||||
|
||||
if (dist > MaxDistanceToTarget)
|
||||
{
|
||||
if (PursueState is not null)
|
||||
{
|
||||
return PursueState;
|
||||
}
|
||||
|
||||
if (PassiveState is not null)
|
||||
{
|
||||
return PassiveState;
|
||||
}
|
||||
}
|
||||
|
||||
if (NPC.CanAttack && NPC.StunTime <= 0)
|
||||
{
|
||||
bool isTargetStunned = bestTarget.StunTime > 0;
|
||||
|
@ -48,17 +61,16 @@ public partial class DashDefensive : AttackState
|
|||
|
||||
// doc will still dash if you are farther than normal but
|
||||
// moving towards him
|
||||
float distThreshold = 2500 - (dot * 400);
|
||||
|
||||
// or just directly dash towards you if you are too far
|
||||
float distTowardsThreshold = 22500;
|
||||
float distThreshold = 50 - (dot * 20);
|
||||
|
||||
// dash towards if lance in anticipate state
|
||||
// or just directly dash towards you if you are too far
|
||||
shouldDashTowards = (isTargetStunned || _dashedAway) &&
|
||||
swordState is State.Weapon.SwordAnticipateState ||
|
||||
dist > distTowardsThreshold;
|
||||
dist > MaxDistanceToTarget;
|
||||
|
||||
shouldDashAway = dist < distThreshold && !isTargetStunned;
|
||||
shouldDashAway = dist < distThreshold && !isTargetStunned &&
|
||||
swordState is not State.Weapon.SwordAnticipateState;
|
||||
|
||||
//if (!isTargetStunned && dist < 2500 && !_dashedAway)
|
||||
if (shouldDashAway && !shouldDashTowards)
|
||||
|
@ -83,10 +95,14 @@ public partial class DashDefensive : AttackState
|
|||
DashTo(NPC.GlobalPosition.DirectionTo(newPos));
|
||||
_dashedAway = false;
|
||||
}
|
||||
else if (isTargetStunned)
|
||||
{
|
||||
NPC.UseCurrentItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return PursueState ?? PassiveState;
|
||||
}
|
||||
|
||||
private void DashTo(Vector2 direction)
|
||||
|
|
Loading…
Reference in New Issue