Add EnemyControllerComponent and PeriodicShootingComponent; implement enemy shooting behavior and bullet spawning

This commit is contained in:
2025-09-13 13:53:40 +02:00
parent db2a090acc
commit e6f8989d16
9 changed files with 94 additions and 111 deletions

View File

@@ -1,13 +1,15 @@
[gd_scene load_steps=5 format=3 uid="uid://dstko446qydsc"] [gd_scene load_steps=5 format=3 uid="uid://dstko446qydsc"]
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_6gptm"] [ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_6gptm"]
[ext_resource type="Script" uid="uid://ctfrbj52ejay4" path="res://scripts/components/DestroyableComponent.cs" id="2_q37h7"] [ext_resource type="Script" uid="uid://bnaxy8cw3wrko" path="res://scripts/components/PeriodicShootingComponent.cs" id="2_q37h7"]
[ext_resource type="Script" uid="uid://dgb8bqcri7nsj" path="res://scripts/components/HealthComponent.cs" id="3_bhwy3"] [ext_resource type="PackedScene" uid="uid://bhc7y4xugu4q7" path="res://objects/entities/bullet.tscn" id="3_bhwy3"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_j5sus"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_j5sus"]
size = Vector2(16, 16) size = Vector2(16, 16)
[node name="Cannon" type="StaticBody2D"] [node name="Cannon" type="StaticBody2D"]
collision_layer = 0
collision_mask = 0
[node name="Sprite2D" type="Sprite2D" parent="."] [node name="Sprite2D" type="Sprite2D" parent="."]
texture = ExtResource("1_6gptm") texture = ExtResource("1_6gptm")
@@ -15,12 +17,17 @@ hframes = 12
vframes = 12 vframes = 12
frame = 42 frame = 42
[node name="DestroyableComponent" type="Node" parent="." node_paths=PackedStringArray("Health")]
script = ExtResource("2_q37h7")
Health = NodePath("../HealthComponent")
[node name="HealthComponent" type="Node2D" parent="."]
script = ExtResource("3_bhwy3")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."] [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("RectangleShape2D_j5sus") shape = SubResource("RectangleShape2D_j5sus")
[node name="PeriodicShootingComponent" type="Node" parent="." node_paths=PackedStringArray("BulletSpawnPointRight")]
script = ExtResource("2_q37h7")
BulletScene = ExtResource("3_bhwy3")
ShootInterval = 3.5
ShootDirection = Vector2(0, -1)
BulletSpawnPointRight = NodePath("../Bullet spawn")
ShootingIntervalVariation = 0.3
metadata/_custom_type_script = "uid://bnaxy8cw3wrko"
[node name="Bullet spawn" type="Marker2D" parent="."]
position = Vector2(0, -16)

View File

@@ -1,33 +0,0 @@
[gd_scene load_steps=5 format=3 uid="uid://dfwpha0d18dmn"]
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_rwgpm"]
[ext_resource type="Script" uid="uid://2i7p7v135u7c" path="res://scripts/components/DamageComponent.cs" id="2_hrj61"]
[ext_resource type="Script" uid="uid://df1llrbm80e02" path="res://scripts/components/BeamComponent.cs" id="3_hrj61"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ptfn7"]
size = Vector2(8, 16)
[node name="Cannon Ray" type="Area2D"]
collision_layer = 0
collision_mask = 5
[node name="Sprite2D" type="Sprite2D" parent="."]
texture_repeat = 2
texture = ExtResource("1_rwgpm")
region_enabled = true
region_rect = Rect2(176, 64, 16, 16)
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("RectangleShape2D_ptfn7")
[node name="DamageComponent" type="Node" parent="." node_paths=PackedStringArray("Area")]
script = ExtResource("2_hrj61")
Area = NodePath("..")
[node name="BeamComponent" type="Node2D" parent="." node_paths=PackedStringArray("Root", "Sprite", "CollisionShape")]
position = Vector2(0, -8)
script = ExtResource("3_hrj61")
ExpansionSpeed = 16.0
Root = NodePath(".")
Sprite = NodePath("../Sprite2D")
CollisionShape = NodePath("../CollisionShape2D")

View File

@@ -1,35 +0,0 @@
[gd_scene load_steps=5 format=3 uid="uid://d3lt4rhxduv44"]
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_l5x2w"]
[ext_resource type="Script" uid="uid://2i7p7v135u7c" path="res://scripts/components/DamageComponent.cs" id="2_0kbpg"]
[ext_resource type="Script" uid="uid://df1llrbm80e02" path="res://scripts/components/BeamComponent.cs" id="3_0kbpg"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ptfn7"]
size = Vector2(16, 8)
[node name="Cannon Ray" type="Area2D"]
collision_layer = 0
collision_mask = 5
[node name="Sprite2D" type="Sprite2D" parent="."]
texture_repeat = 2
rotation = 1.5708
texture = ExtResource("1_l5x2w")
region_enabled = true
region_rect = Rect2(176, 64, 16, 16)
region_filter_clip_enabled = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("RectangleShape2D_ptfn7")
[node name="DamageComponent" type="Node" parent="." node_paths=PackedStringArray("Area")]
script = ExtResource("2_0kbpg")
Area = NodePath("..")
[node name="BeamComponent" type="Node2D" parent="." node_paths=PackedStringArray("Root", "Sprite", "CollisionShape")]
position = Vector2(8, 0)
script = ExtResource("3_0kbpg")
ExpansionSpeed = 16.0
Root = NodePath("..")
Sprite = NodePath("../Sprite2D")
CollisionShape = NodePath("../CollisionShape2D")

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=28 format=3 uid="uid://bwdlmualj6xbw"] [gd_scene load_steps=29 format=3 uid="uid://bwdlmualj6xbw"]
[ext_resource type="Shader" uid="uid://bs4xvm4qkurpr" path="res://shaders/hit_flash.tres" id="1_ep4yr"] [ext_resource type="Shader" uid="uid://bs4xvm4qkurpr" path="res://shaders/hit_flash.tres" id="1_ep4yr"]
[ext_resource type="Texture2D" uid="uid://cu72810eyk4dx" path="res://sprites/enemy-robot.png" id="2_hjtwe"] [ext_resource type="Texture2D" uid="uid://cu72810eyk4dx" path="res://sprites/enemy-robot.png" id="2_hjtwe"]
@@ -19,6 +19,7 @@
[ext_resource type="PackedScene" uid="uid://ck6nml06tm6ue" path="res://objects/fxs/ice_fx.tscn" id="16_68hnm"] [ext_resource type="PackedScene" uid="uid://ck6nml06tm6ue" path="res://objects/fxs/ice_fx.tscn" id="16_68hnm"]
[ext_resource type="PackedScene" uid="uid://b12tppjkkqpt4" path="res://objects/fxs/hit_particles.tscn" id="18_pxaaa"] [ext_resource type="PackedScene" uid="uid://b12tppjkkqpt4" path="res://objects/fxs/hit_particles.tscn" id="18_pxaaa"]
[ext_resource type="Script" uid="uid://cgfynrn68lp12" path="res://scripts/components/KnockbackComponent.cs" id="19_xku20"] [ext_resource type="Script" uid="uid://cgfynrn68lp12" path="res://scripts/components/KnockbackComponent.cs" id="19_xku20"]
[ext_resource type="Script" uid="uid://bhbgjr8ty2n85" path="res://scripts/components/EnemyControllerComponent.cs" id="20_5lji2"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_pwwji"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_pwwji"]
size = Vector2(25, 31) size = Vector2(25, 31)
@@ -97,13 +98,12 @@ RightRay = NodePath("../Right Ray")
LeftWallRay = NodePath("../Left Wall Ray") LeftWallRay = NodePath("../Left Wall Ray")
RightWallRay = NodePath("../Right Wall Ray") RightWallRay = NodePath("../Right Wall Ray")
[node name="PeriodicShootingComponent" type="Node" parent="." node_paths=PackedStringArray("SideToSideMovement", "BulletSpawnRight", "BulletSpawnLeft")] [node name="PeriodicShootingComponent" type="Node" parent="." node_paths=PackedStringArray("BulletSpawnPointRight", "BulletSpawnPointLeft")]
script = ExtResource("6_lgbyy") script = ExtResource("6_lgbyy")
BulletScene = ExtResource("7_r48kf") BulletScene = ExtResource("7_r48kf")
SideToSideMovement = NodePath("../SideToSideMovement") BulletSpawnPointRight = NodePath("../Sprite2D/right bullet spawn")
BulletSpawnRight = NodePath("../Sprite2D/right bullet spawn") BulletSpawnPointLeft = NodePath("../Sprite2D/left bullet spawn")
BulletSpawnLeft = NodePath("../Sprite2D/left bullet spawn") ShootingIntervalVariation = 0.3
ShootingIntervalVariation = 0.1
[node name="EnemyDeathComponent" type="Node" parent="." node_paths=PackedStringArray("CollisionShape", "Health")] [node name="EnemyDeathComponent" type="Node" parent="." node_paths=PackedStringArray("CollisionShape", "Health")]
script = ExtResource("8_pxaaa") script = ExtResource("8_pxaaa")
@@ -187,3 +187,9 @@ process_material = SubResource("ParticleProcessMaterial_pxaaa")
[node name="KnockbackComponent" type="Node" parent="."] [node name="KnockbackComponent" type="Node" parent="."]
script = ExtResource("19_xku20") script = ExtResource("19_xku20")
metadata/_custom_type_script = "uid://cgfynrn68lp12" metadata/_custom_type_script = "uid://cgfynrn68lp12"
[node name="EnemyControllerComponent" type="Node" parent="." node_paths=PackedStringArray("MovementComponent", "ShootingComponent")]
script = ExtResource("20_5lji2")
MovementComponent = NodePath("../SideToSideMovement")
ShootingComponent = NodePath("../PeriodicShootingComponent")
metadata/_custom_type_script = "uid://bhbgjr8ty2n85"

View File

@@ -1,4 +1,4 @@
[gd_resource type="TileSet" load_steps=16 format=3 uid="uid://bc5a20s6kuy8e"] [gd_resource type="TileSet" load_steps=17 format=3 uid="uid://bc5a20s6kuy8e"]
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_ej5iv"] [ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_ej5iv"]
[ext_resource type="PackedScene" uid="uid://54w4wisfj8v8" path="res://objects/entities/coin.tscn" id="2_31a0q"] [ext_resource type="PackedScene" uid="uid://54w4wisfj8v8" path="res://objects/entities/coin.tscn" id="2_31a0q"]
@@ -9,6 +9,7 @@
[ext_resource type="PackedScene" uid="uid://c0j1yun5s7kns" path="res://objects/entities/bouncing_mushroom.tscn" id="5_ov0dn"] [ext_resource type="PackedScene" uid="uid://c0j1yun5s7kns" path="res://objects/entities/bouncing_mushroom.tscn" id="5_ov0dn"]
[ext_resource type="PackedScene" uid="uid://d08dfqmirnd66" path="res://objects/entities/big_treasure.tscn" id="5_xxibl"] [ext_resource type="PackedScene" uid="uid://d08dfqmirnd66" path="res://objects/entities/big_treasure.tscn" id="5_xxibl"]
[ext_resource type="PackedScene" uid="uid://073ts5cxtwbl" path="res://objects/entities/treasure.tscn" id="6_fmgww"] [ext_resource type="PackedScene" uid="uid://073ts5cxtwbl" path="res://objects/entities/treasure.tscn" id="6_fmgww"]
[ext_resource type="PackedScene" uid="uid://dstko446qydsc" path="res://objects/entities/cannon.tscn" id="6_xxibl"]
[ext_resource type="PackedScene" uid="uid://cm3rixnnev1pg" path="res://objects/entities/jump_pad.tscn" id="7_0kjxj"] [ext_resource type="PackedScene" uid="uid://cm3rixnnev1pg" path="res://objects/entities/jump_pad.tscn" id="7_0kjxj"]
[ext_resource type="PackedScene" uid="uid://to2xnqev0pu1" path="res://objects/entities/cage.tscn" id="8_83o0w"] [ext_resource type="PackedScene" uid="uid://to2xnqev0pu1" path="res://objects/entities/cage.tscn" id="8_83o0w"]
[ext_resource type="PackedScene" uid="uid://bd51frym6mm7v" path="res://objects/entities/lever.tscn" id="9_at40q"] [ext_resource type="PackedScene" uid="uid://bd51frym6mm7v" path="res://objects/entities/lever.tscn" id="9_at40q"]
@@ -151,6 +152,7 @@ scenes/9/scene = ExtResource("10_ivcjr")
scenes/10/scene = ExtResource("3_31a0q") scenes/10/scene = ExtResource("3_31a0q")
scenes/11/scene = ExtResource("4_x63lh") scenes/11/scene = ExtResource("4_x63lh")
scenes/12/scene = ExtResource("5_ov0dn") scenes/12/scene = ExtResource("5_ov0dn")
scenes/13/scene = ExtResource("6_xxibl")
[resource] [resource]
physics_layer_0/collision_layer = 1 physics_layer_0/collision_layer = 1

View File

@@ -65,7 +65,6 @@ polygon = PackedVector2Array(-214, -1594, 571, -1596, 571, 321, -220, 317)
[node name="WorldEnvironment" parent="." instance=ExtResource("2_yd68a")] [node name="WorldEnvironment" parent="." instance=ExtResource("2_yd68a")]
[node name="UI Layer" parent="." instance=ExtResource("3_qbt57")] [node name="UI Layer" parent="." instance=ExtResource("3_qbt57")]
visible = false
[node name="HUD" parent="UI Layer" index="0" node_paths=PackedStringArray("Health")] [node name="HUD" parent="UI Layer" index="0" node_paths=PackedStringArray("Health")]
Health = NodePath("../../Brick Player/HealthComponent") Health = NodePath("../../Brick Player/HealthComponent")
@@ -124,7 +123,7 @@ tile_map_data = PackedByteArray("AAAjABMAAQAEAAMAAAAjABIAAQAEAAIAAAAjABEAAQAEAAI
tile_set = ExtResource("9_tmn5u") tile_set = ExtResource("9_tmn5u")
[node name="Entities layer" type="TileMapLayer" parent="."] [node name="Entities layer" type="TileMapLayer" parent="."]
tile_map_data = PackedByteArray("AAANAAEAAQAAAAAADAA=") tile_map_data = PackedByteArray("AAANAAEAAQAAAAAADAAWAPP/AQAAAAAADAAYAAIAAQAAAAAADQA=")
tile_set = ExtResource("10_yka2u") tile_set = ExtResource("10_yka2u")
[node name="Foreground layer" type="TileMapLayer" parent="."] [node name="Foreground layer" type="TileMapLayer" parent="."]

View File

@@ -0,0 +1,20 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class EnemyControllerComponent : Node
{
[Export] public SideToSideMovementComponent MovementComponent { get; set; }
[Export] public PeriodicShootingComponent ShootingComponent { get; set; }
public override void _Process(double delta)
{
if (MovementComponent == null || ShootingComponent == null) return;
if (MovementComponent.Direction != Vector2.Zero)
{
ShootingComponent.ShootDirection = MovementComponent.Direction;
}
}
}

View File

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

View File

@@ -1,3 +1,4 @@
using System;
using Godot; using Godot;
namespace Mr.BrickAdventures.scripts.components; namespace Mr.BrickAdventures.scripts.components;
@@ -8,31 +9,27 @@ public partial class PeriodicShootingComponent : Node
[Export] public PackedScene BulletScene { get; set; } [Export] public PackedScene BulletScene { get; set; }
[Export] public float ShootInterval { get; set; } = 1.0f; [Export] public float ShootInterval { get; set; } = 1.0f;
[Export] public Vector2 ShootDirection { get; set; } = Vector2.Right; [Export] public Vector2 ShootDirection { get; set; } = Vector2.Right;
[Export] public SideToSideMovementComponent SideToSideMovement { get; set; } [Export] public Node2D BulletSpawnPointRight { get; set; }
[Export] public Node2D BulletSpawnRight { get; set; } [Export] public Node2D BulletSpawnPointLeft { get; set; }
[Export] public Node2D BulletSpawnLeft { get; set; }
[Export] public float ShootingIntervalVariation { get; set; } = 0.0f; [Export] public float ShootingIntervalVariation { get; set; } = 0.0f;
private Timer _timer; private Timer _timer;
private RandomNumberGenerator _rng;
public override void _Ready() public override void _Ready()
{ {
_rng = new RandomNumberGenerator();
SetupTimer(); SetupTimer();
} }
public override void _Process(double delta)
{
if (SideToSideMovement == null) return;
ShootDirection = SideToSideMovement.Direction != Vector2.Zero ? SideToSideMovement.Direction : Vector2.Right;
}
private void SetupTimer() private void SetupTimer()
{ {
_timer = new Timer(); _timer = new Timer
_timer.WaitTime = GetShootInterval(); {
_timer.OneShot = false; WaitTime = GetNextShootInterval(),
_timer.Autostart = true; OneShot = false,
Autostart = true
};
_timer.Timeout += OnTimerTimeout; _timer.Timeout += OnTimerTimeout;
AddChild(_timer); AddChild(_timer);
} }
@@ -40,33 +37,52 @@ public partial class PeriodicShootingComponent : Node
private void OnTimerTimeout() private void OnTimerTimeout()
{ {
Shoot(); Shoot();
_timer.Start(); _timer.WaitTime = GetNextShootInterval();
} }
private double GetShootInterval() private double GetNextShootInterval()
{ {
if (ShootingIntervalVariation == 0f) return ShootInterval; if (ShootingIntervalVariation <= 0f)
{
return ShootInterval;
}
var rng = new RandomNumberGenerator(); return Math.Max(0.01, ShootInterval + _rng.RandfRange(-ShootingIntervalVariation, ShootingIntervalVariation));
return ShootInterval + rng.RandfRange(-ShootingIntervalVariation, ShootingIntervalVariation);
} }
private void Shoot() private void Shoot()
{ {
if (BulletScene == null)
{
GD.PushError("PeriodicShootingComponent: BulletScene is not set.");
return;
}
if (ShootDirection == Vector2.Zero) return; if (ShootDirection == Vector2.Zero) return;
var spawnNode = (ShootDirection.X >= 0 || BulletSpawnPointLeft == null)
? BulletSpawnPointRight
: BulletSpawnPointLeft;
if (spawnNode == null)
{
GD.PrintErr("PeriodicShootingComponent: A suitable bullet spawn point is not set.");
return;
}
var root = Owner as Node2D; var spawnPosition = spawnNode.GlobalPosition;
var owner = Owner as Node2D;
var ownerRotation = owner?.Rotation ?? 0f;
var bulletInstance = BulletScene.Instantiate<Node2D>(); var bulletInstance = BulletScene.Instantiate<Node2D>();
var launchComponent = bulletInstance.GetNodeOrNull<LaunchComponent>("LaunchComponent"); if (bulletInstance.GetNodeOrNull<LaunchComponent>("LaunchComponent") is { } launchComponent)
var spawnPosition = ShootDirection == Vector2.Right ? BulletSpawnRight.GlobalPosition : BulletSpawnLeft.GlobalPosition;
if (launchComponent != null)
{ {
launchComponent.InitialDirection = ShootDirection; launchComponent.InitialDirection = ShootDirection;
launchComponent.SpawnPosition = spawnPosition; launchComponent.SpawnPosition = spawnPosition;
if (root != null) launchComponent.SpawnRotation = root.Rotation; launchComponent.SpawnRotation = ownerRotation;
} }
bulletInstance.Position = spawnPosition; bulletInstance.GlobalPosition = spawnPosition;
GetTree().CurrentScene.AddChild(bulletInstance); GetTree().CurrentScene.AddChild(bulletInstance);
} }
} }