Compare commits

...

8 Commits

Author SHA1 Message Date
=
b58f4412f2 Fixed enemy ai bugs 2026-01-29 06:20:48 -07:00
=
4392367ef6 Consolodated jump logic 2026-01-28 13:15:32 -07:00
=
6a00e320b3 Optimized enemy code 2026-01-28 12:56:43 -07:00
=
88ecd78c4e Enemy is consious of relative player location 2026-01-27 20:47:30 -07:00
=
47a1e88b5f optimized enemy code 2026-01-27 09:58:47 -07:00
=
4ca341f416 Added 2 new enemy movement sets including jumping 2026-01-27 09:22:14 -07:00
=
0506824cf1 Got most basic enemy movement working 2026-01-27 08:26:35 -07:00
=
318397ee29 TileMapLayer collisions with area2d sucessfull 2026-01-26 13:15:45 -07:00
5 changed files with 312 additions and 72 deletions

File diff suppressed because one or more lines are too long

View File

@@ -5,62 +5,69 @@ public partial class IQEnemy : CharacterBody2D
{
// Misc
float GlobalTimer;
Node2D VAH; // Shorthand refrence
// Enemy Stats
public int IQ;
public float HP;
public float MaxHP;
float RegenerationAmmount;
float RegenerationInterval;
float WalkSpeed;
float JumpHeight;
float MaxHP, RegenerationAmmount, RegenerationInterval, WalkSpeed, JumpHeight, JumpInterval, DetectionRange;
// Enemy Conditions
float CurrentYVelocity;
float PreviousYVelocity;
bool GroundDetected;
bool LedgeDetected;
bool GroundDetected, LedgeDetected, WallDetected, CanJump;
String FacingDirection;
// Enemy Abilities
bool AbilityJump = false;
bool AbilityMove = false;
bool AbilityAttack = false;
bool AbilityDash = false;
bool AbilityCloak = false;
bool AbilityTeleport = false;
bool AbilityRegenerate = false;
bool AbilityJump, AbilityMove, AbilityAttack, AbilityDash, AbilityCloak, AbilityTeleport, AbilityRegenerate;
public override void _Ready()
{
// Read & Set Abilities
if (HasMeta("AbilityJump")) AbilityJump = (bool)GetMeta("AbilityJump");
else AbilityJump = true;
if (HasMeta("AbilityMove")) AbilityMove = (bool)GetMeta("AbilityMove");
else AbilityMove = true;
if (HasMeta("AbilityAttack")) AbilityAttack = (bool)GetMeta("AbilityAttack");
else AbilityAttack = true;
if (HasMeta("AbilityDash")) AbilityDash = (bool)GetMeta("AbilityDash");
else AbilityDash = false;
if (HasMeta("AbilityCloak")) AbilityCloak = (bool)GetMeta("AbilityCloak");
else AbilityCloak = false;
if (HasMeta("AbilityTeleport")) AbilityTeleport = (bool)GetMeta("AbilityTeleport");
else AbilityTeleport = false;
if (HasMeta("AbilityRegenerate")) AbilityRegenerate = (bool)GetMeta("AbilityRegenerate");
else AbilityRegenerate = true;
if (HasMeta("RegenerationAmmount")) RegenerationAmmount = (float)GetMeta("RegenerationAmmount");
else RegenerationAmmount = 1.0f;
if (HasMeta("RegenerationInterval")) RegenerationInterval = (float)GetMeta("RegenerationInterval");
else RegenerationInterval = 1.0f;
if (HasMeta("WalkSpeed")) WalkSpeed = (float)GetMeta("WalkSpeed");
else WalkSpeed = 10.0f;
else WalkSpeed = 20.0f;
if (HasMeta("JumpHeight")) JumpHeight = (float)GetMeta("JumpHeight");
else JumpHeight = 10.0f;
else JumpHeight = 250.0f;
if (HasMeta("JumpInterval")) JumpInterval = (float)GetMeta("JumpInterval");
else JumpInterval = 1.0f;
if (HasMeta("DetectionRange")) DetectionRange = (float)GetMeta("DetectionRange");
else DetectionRange = 100.0f;
JumpHeight *= -1;
// Read and set stats
if (HasMeta("MaxHP")) MaxHP = (float)GetMeta("MaxHP");
// Set up ground detection
GetNode<Area2D>("GroundDetector").AreaEntered += OnGroundEntered;
GetNode<Area2D>("GroundDetector").AreaExited += OnGroundExited;
FacingDirection = "RIGHT";
VAH = GetNode<Node2D>("VisualsAndHitboxes");
GetNode<Area2D>("LedgeDetector").AreaEntered += OnLedgeEntered;
GetNode<Area2D>("LedgeDetector").AreaExited += OnLedgeExited;
// Set up collision detection
VAH.GetNode<Area2D>("GroundDetector").BodyEntered += OnGroundEntered; // Ground
VAH.GetNode<Area2D>("GroundDetector").BodyExited += OnGroundExited;
VAH.GetNode<Area2D>("LedgeDetector").BodyEntered += OnLedgeEntered; // Ledge
VAH.GetNode<Area2D>("LedgeDetector").BodyExited += OnLedgeExited;
VAH.GetNode<Area2D>("WallDetector").BodyEntered += OnWallEntered; // Wall
VAH.GetNode<Area2D>("WallDetector").BodyExited += OnWallExited;
GroundDetected = true;
LedgeDetected = true;
GroundDetected = false;
LedgeDetected = false;
WallDetected = false;
CanJump = AbilityJump;
// Apply IQ based permenant modifiers
IQ = (int)GetMeta("IQ"); // Read IQ
@@ -69,9 +76,12 @@ public partial class IQEnemy : CharacterBody2D
HP = MaxHP;
if (IQ >= 100 && HasMeta("RegenerationInterval")) RegenerationInterval *= 0.9f;
if (IQ >= 100 && HasMeta("RegenerationAmmount")) RegenerationAmmount *= 1.05f; // 5% increase
WalkSpeed += IQ / 10;
JumpHeight += IQ / 15;
}
public override void _Process(double delta)
public override void _PhysicsProcess(double delta)
{
// Update Timer
GlobalTimer = GetTree().Root.GetNode<CommonData>("CommonData").GlobalTimer;
@@ -81,24 +91,93 @@ public partial class IQEnemy : CharacterBody2D
// Regenerate Health
if (AbilityRegenerate){
if (GlobalTimer % RegenerationInterval == 0){Regenerate(RegenerationAmmount);}
if (GlobalTimer % RegenerationInterval == 0) Regenerate(RegenerationAmmount);
}
// Jump Cooldown
if (AbilityJump){
if (GlobalTimer % JumpInterval == 0) CanJump = true;
}
// Movement
// Add gravity.
if (GroundDetected == false){Velocity = new Vector2(Velocity[0],-1);}
if (IQ <= 20){ // Goomba ahh diddy blud
if (GroundDetected && LedgeDetected == false) {Flip("ANY");}
if (Scale[0] > 0){Velocity = new Vector2(WalkSpeed, Velocity[1]);} // Facing right
if (Scale[0] < 0){Velocity = new Vector2(-1 * WalkSpeed, Velocity[1]);} // Facing left
if (GroundDetected == false) Velocity = new Vector2(Velocity[0],Velocity[1] + 10);
#region 20IQ
if (AbilityMove){
if (IQ >= 0 && IQ <= 20){ // Goomba ahh diddy blud
if (GroundDetected && LedgeDetected == false) Flip(); // Flip when presented with a ledge
if (WallDetected) Flip(); // Flip when comeing in contact with a wall
if (GroundDetected) Velocity = new Vector2(WalkSpeed * VAH.Scale[0], Velocity[1]); // Walk
}
MoveAndSlide();
#endregion
#region 30IQ
if (IQ > 20 && IQ <= 30){ // Goomba w/ hopps (no judy)
Velocity = new Vector2(WalkSpeed * VAH.Scale[0], Velocity[1]); // Walk
if (WallDetected && GroundDetected && Velocity[1] == 0) Jump(0.0f);
if (WallDetected && GroundDetected && Velocity[1] > 0) Flip(); // Wall too high
}
#endregion
#region 40IQ
if (IQ > 30 && IQ <= 40){ // Adds jumping when reaching edge as feature (also adding directional x force)
Velocity = (GroundDetected) ? new Vector2(WalkSpeed * VAH.Scale[0], Velocity[1]) : new Vector2 (Velocity[0] + 0.05f, Velocity[1]); // Walk on ground : air
if (WallDetected && GroundDetected) Jump(0.0f);
if (GroundDetected && LedgeDetected == false) Jump(50.0f * VAH.Scale[0]); // Jump at ledge with x motion
if (WallDetected && GroundDetected && Velocity[1] > 0) Flip(); // Wall too high
}
#endregion
#region 60IQ
if (IQ > 40 && IQ <= 60){ // Concious of what side of the enemy the player is on
if (DetectsPlayer()){ // Pursuing Player
var CurrentLevel = GetTree().Root.GetChildren();
float DistanceFromPlayerX = GlobalPosition[0] - CurrentLevel[2].GetNode<Node2D>("Player").GlobalPosition[0];
if (DistanceFromPlayerX > (30.0f / (IQ / 4))) if (VAH.Scale[0] > 0)Flip(); // left of player
if (DistanceFromPlayerX < (-30.0f / (IQ / 4))) if (VAH.Scale[0] < 0)Flip(); // right of player
if (DistanceFromPlayerX < (-30.0f / (IQ / 4)) && GroundDetected && GlobalPosition[1] > CurrentLevel[2].GetNode<Node2D>("Player").GlobalPosition[1]) Jump(0.0f); // Jump when player is overhead
} else{ // Patrol
if (WallDetected && GroundDetected && Velocity[1] > 0)Flip(); // Wall too high (flips when it lands on the ground in front of a wall)
}
// Common Behaviors
Velocity = (GroundDetected) ? new Vector2(WalkSpeed * VAH.Scale[0], Velocity[1]) : new Vector2 (Velocity[0] + 0.05f, Velocity[1]); // Walk on ground : air
if (WallDetected && GroundDetected) Jump(0.0f); // Jump when touching a wall
if (GroundDetected && LedgeDetected == false) Jump(50.0f * VAH.Scale[0]); // Jump at ledge with x motion
}
#endregion
#region 80IQ
if (IQ > 60 && IQ <= 80){ // Maintain distance to avoid melee attacks and optimise ranged attacks
}
#endregion
#region 1000IQ
if (IQ > 80 && IQ <= 100){ // Basic Pathfinding
}
#endregion
#region 120IQ
if (IQ > 100 && IQ <= 120){ // Advanced Pathfindinhg
}
#endregion
#region 140IQ
if (IQ > 120 && IQ <= 140){ // Advanced movement options
}
}
#endregion
MoveAndSlide(); // Updates physics applied this frame
}
void Flip(string facing){
if (facing == "ANY") Scale = new Vector2(Scale[0] * -1,1);
if (facing == "RIGHT") Scale = new Vector2(1,1);
if (facing =="LEFT") Scale = new Vector2(-1,1);
void Flip(){
VAH.Scale = new Vector2(-1 * VAH.Scale[0],1);
WallDetected = false;
LedgeDetected = true;
if (FacingDirection == "RIGHT"){FacingDirection = "LEFT";}
else if (FacingDirection == "LEFT"){FacingDirection = "RIGHT";}
}
void Jump(float xMagnitude){
if (GroundDetected && CanJump) {Velocity = new Vector2(Velocity[0] + xMagnitude, JumpHeight);
CanJump = false;}
}
bool DetectsPlayer(){
var CurrentLevel = GetTree().Root.GetChildren();
return (GlobalPosition.DistanceTo(CurrentLevel[2].GetNode<Node2D>("Player").GlobalPosition) <= DetectionRange) ? true : false;
}
public void Regenerate(float ammount){
@@ -116,9 +195,12 @@ public partial class IQEnemy : CharacterBody2D
}
// Ground Detection
public void OnGroundEntered(Area2D area){if (area.CollisionLayer == 0) GroundDetected = true;}
public void OnGroundExited(Area2D area){if (area.CollisionLayer == 0) GroundDetected = false;}
public void OnGroundEntered(Node2D body){if (body is TileMapLayer tileLayer) GroundDetected = true;}
public void OnGroundExited(Node2D body){if (body is TileMapLayer tileLayer) GroundDetected = false;}
// Ledge Detection
public void OnLedgeEntered(Area2D area){if (area.CollisionLayer == 0) LedgeDetected = true;}
public void OnLedgeExited(Area2D area){if (area.CollisionLayer == 0) LedgeDetected = false;}
public void OnLedgeEntered(Node2D body){if (body is TileMapLayer tileLayer) LedgeDetected = true;}
public void OnLedgeExited(Node2D body){if (body is TileMapLayer tileLayer) LedgeDetected = false;}
// Wall Detection
public void OnWallEntered(Node2D body){if (body is TileMapLayer tileLayer) WallDetected = true;}
public void OnWallExited(Node2D body){if (body is TileMapLayer tileLayer) WallDetected = false;}
}

View File

@@ -3,9 +3,8 @@
[ext_resource type="Script" uid="uid://cy22d14qd0f48" path="res://Assets/Scenes/DEVSCENES/IQEnemy.cs" id="1_p53ib"]
[ext_resource type="Texture2D" uid="uid://c0pno0ac25r7i" path="res://Assets/Sprites/knight.png" id="2_o0b1e"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_bc7hl"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_41iyt"]
size = Vector2(14, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_a1e3t"]
atlas = ExtResource("2_o0b1e")
@@ -127,42 +126,52 @@ animations = [{
"speed": 5.0
}]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_bc7hl"]
[node name="IQEnemy" type="CharacterBody2D"]
collision_layer = 8
collision_mask = 3
script = ExtResource("1_p53ib")
metadata/IQ = 20
metadata/AbilityRegenerate = true
[node name="GroundDetector" type="Area2D" parent="."]
position = Vector2(1.1368684e-13, 10.999999)
scale = Vector2(0.099999994, 0.099999994)
[node name="CollisionShape2D" type="CollisionShape2D" parent="GroundDetector"]
scale = Vector2(0.99999994, 0.99999994)
shape = SubResource("RectangleShape2D_bc7hl")
[node name="LedgeDetector" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="LedgeDetector"]
position = Vector2(12, 12)
scale = Vector2(0.1, 0.1)
shape = SubResource("RectangleShape2D_bc7hl")
[node name="WallDetector" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="WallDetector"]
position = Vector2(12, 9.536743e-07)
scale = Vector2(0.1, 0.1)
shape = SubResource("RectangleShape2D_bc7hl")
metadata/_edit_vertical_guides_ = [-36.0]
[node name="Hitbox" type="CollisionShape2D" parent="."]
position = Vector2(0, 2)
shape = SubResource("RectangleShape2D_41iyt")
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
[node name="VisualsAndHitboxes" type="Node2D" parent="."]
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="VisualsAndHitboxes"]
position = Vector2(9.536743e-07, -1.9999999)
scale = Vector2(0.99999994, 0.99999994)
sprite_frames = SubResource("SpriteFrames_rqn21")
autoplay = "default"
frame = 1
frame_progress = 0.9866207
[node name="GroundDetector" type="Area2D" parent="VisualsAndHitboxes"]
position = Vector2(1.1368684e-13, 11.000001)
scale = Vector2(0.099999994, 0.099999994)
collision_layer = 0
[node name="CollisionShape2D" type="CollisionShape2D" parent="VisualsAndHitboxes/GroundDetector"]
position = Vector2(0, 19.999992)
scale = Vector2(0.99999994, 0.99999994)
shape = SubResource("RectangleShape2D_bc7hl")
[node name="LedgeDetector" type="Area2D" parent="VisualsAndHitboxes"]
collision_layer = 0
[node name="CollisionShape2D" type="CollisionShape2D" parent="VisualsAndHitboxes/LedgeDetector"]
position = Vector2(11, 13)
scale = Vector2(0.1, 0.1)
shape = SubResource("RectangleShape2D_bc7hl")
[node name="WallDetector" type="Area2D" parent="VisualsAndHitboxes"]
collision_layer = 0
[node name="CollisionShape2D" type="CollisionShape2D" parent="VisualsAndHitboxes/WallDetector"]
position = Vector2(11, 9.536743e-07)
scale = Vector2(0.1, 0.1)
shape = SubResource("RectangleShape2D_bc7hl")

View File

@@ -130,7 +130,8 @@ animations = [{
size = Vector2(12, 28)
[node name="Player" type="CharacterBody2D"]
collision_layer = 2
collision_layer = 4
collision_mask = 3
script = ExtResource("1_b2ifw")
[node name="AreaDetector" type="Area2D" parent="."]

View File

@@ -33,8 +33,8 @@ public partial class CommonData : Node
GetTree().Root.CallDeferred(Node.MethodName.AddChild, inst);
// Start game by loading the main menu
//scene = GD.Load<PackedScene>("res://Assets/Scenes/MenusAndLevels/MainMenu.tscn");
scene = GD.Load<PackedScene>("res://Assets/Scenes/DEVSCENES/EnemyTest.tscn");
scene = GD.Load<PackedScene>("res://Assets/Scenes/MenusAndLevels/MainMenu.tscn");
//scene = GD.Load<PackedScene>("res://Assets/Scenes/DEVSCENES/EnemyTest.tscn");
inst = scene.Instantiate();
GetTree().Root.CallDeferred(Node.MethodName.AddChild, inst);
PlayMusic("MainMenu");