From ef8fd0db9ffd805f43337ca82d7a1d5a7a4533c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=A8=E8=90=BD=E5=9F=BA=E5=9B=B4=E8=99=BE?= <3161880837@qq.com> Date: Tue, 26 Aug 2025 11:39:47 +0800 Subject: [PATCH] feat: Enhance game mechanics and structure - Added `ColorBar` class for visual representation of values. - Expanded `EntityBase` with new properties: `isBoss` and `weapons`, and implemented damage handling and entity generation methods. - Updated `EntityStateBar` to use `ColorBar` for health representation. - Introduced `BulletBase` scene and script for bullet mechanics, including damage handling and generation. - Created `WorldTool` for managing the game world and root node. - Implemented `EntityTool` for retrieving entities from hurtboxes. - Added `GameRule` for managing game rules like friendly fire. - Updated scene files to reflect new structures and added necessary resources. --- components/Abstracts/BulletBase.tscn | 16 ++++++++ components/Bullets/PurpleCrystal.tscn | 26 +++++++++++++ resources/bullets/diamond/frames/0.svg | 25 +++++++++++++ resources/bullets/diamond/frames/0.svg.import | 37 +++++++++++++++++++ resources/bullets/purple-crystal/frames/0.svg | 27 ++++++++++++++ .../purple-crystal/frames/0.svg.import | 37 +++++++++++++++++++ scripts/Statemachine/BulletBase.gd | 33 +++++++++++++++++ scripts/Statemachine/ColorBar.gd | 1 + scripts/Statemachine/EntityBase.gd | 25 +++++++++++++ scripts/Statemachine/EntityStateBar.gd | 2 +- scripts/Tools/EntityTool.gd | 10 +++++ scripts/Tools/GameRule.gd | 3 ++ scripts/Tools/WorldTool.gd | 9 +++++ world.tscn | 6 ++- 14 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 components/Abstracts/BulletBase.tscn create mode 100644 components/Bullets/PurpleCrystal.tscn create mode 100644 resources/bullets/diamond/frames/0.svg create mode 100644 resources/bullets/diamond/frames/0.svg.import create mode 100644 resources/bullets/purple-crystal/frames/0.svg create mode 100644 resources/bullets/purple-crystal/frames/0.svg.import create mode 100644 scripts/Statemachine/BulletBase.gd create mode 100644 scripts/Tools/EntityTool.gd create mode 100644 scripts/Tools/GameRule.gd create mode 100644 scripts/Tools/WorldTool.gd diff --git a/components/Abstracts/BulletBase.tscn b/components/Abstracts/BulletBase.tscn new file mode 100644 index 0000000..5b39fc6 --- /dev/null +++ b/components/Abstracts/BulletBase.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=4 format=3 uid="uid://crtdkysmnkith"] + +[ext_resource type="Script" path="res://scripts/Statemachine/BulletBase.gd" id="1_pklpq"] + +[sub_resource type="SpriteFrames" id="SpriteFrames_vypy3"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_ecl7m"] + +[node name="BulletBase" type="Area2D"] +script = ExtResource("1_pklpq") + +[node name="texture" type="AnimatedSprite2D" parent="."] +sprite_frames = SubResource("SpriteFrames_vypy3") + +[node name="hitbox" type="CollisionShape2D" parent="."] +shape = SubResource("CircleShape2D_ecl7m") diff --git a/components/Bullets/PurpleCrystal.tscn b/components/Bullets/PurpleCrystal.tscn new file mode 100644 index 0000000..b992a5a --- /dev/null +++ b/components/Bullets/PurpleCrystal.tscn @@ -0,0 +1,26 @@ +[gd_scene load_steps=5 format=3 uid="uid://uj0aqhm8wgy8"] + +[ext_resource type="PackedScene" uid="uid://crtdkysmnkith" path="res://components/Abstracts/BulletBase.tscn" id="1_45mh7"] +[ext_resource type="Texture2D" uid="uid://c7hyatbuieaj" path="res://resources/bullets/purple-crystal/frames/0.svg" id="2_ca3pq"] + +[sub_resource type="SpriteFrames" id="SpriteFrames_r86b3"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": ExtResource("2_ca3pq") +}], +"loop": true, +"name": &"default", +"speed": 5.0 +}] + +[sub_resource type="CircleShape2D" id="CircleShape2D_ty1as"] + +[node name="PurpleCrystal" instance=ExtResource("1_45mh7")] + +[node name="texture" parent="." index="0"] +sprite_frames = SubResource("SpriteFrames_r86b3") + +[node name="hitbox" parent="." index="1"] +position = Vector2(0, -13) +shape = SubResource("CircleShape2D_ty1as") diff --git a/resources/bullets/diamond/frames/0.svg b/resources/bullets/diamond/frames/0.svg new file mode 100644 index 0000000..c31e15c --- /dev/null +++ b/resources/bullets/diamond/frames/0.svg @@ -0,0 +1,25 @@ + + + + + crystal-a + Created with Sketch. + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/bullets/diamond/frames/0.svg.import b/resources/bullets/diamond/frames/0.svg.import new file mode 100644 index 0000000..5b559f1 --- /dev/null +++ b/resources/bullets/diamond/frames/0.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dfptmc7clhtx7" +path="res://.godot/imported/0.svg-b76264cbe10324fb670faecc659cdc73.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://resources/bullets/diamond/frames/0.svg" +dest_files=["res://.godot/imported/0.svg-b76264cbe10324fb670faecc659cdc73.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/resources/bullets/purple-crystal/frames/0.svg b/resources/bullets/purple-crystal/frames/0.svg new file mode 100644 index 0000000..26ffcb7 --- /dev/null +++ b/resources/bullets/purple-crystal/frames/0.svg @@ -0,0 +1,27 @@ + + + + + crystal-b + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/bullets/purple-crystal/frames/0.svg.import b/resources/bullets/purple-crystal/frames/0.svg.import new file mode 100644 index 0000000..49db2bb --- /dev/null +++ b/resources/bullets/purple-crystal/frames/0.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c7hyatbuieaj" +path="res://.godot/imported/0.svg-ba68a30343badda4169c625106c39869.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://resources/bullets/purple-crystal/frames/0.svg" +dest_files=["res://.godot/imported/0.svg-ba68a30343badda4169c625106c39869.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/scripts/Statemachine/BulletBase.gd b/scripts/Statemachine/BulletBase.gd new file mode 100644 index 0000000..ed6f36b --- /dev/null +++ b/scripts/Statemachine/BulletBase.gd @@ -0,0 +1,33 @@ +extends Area2D +class_name BulletBase + +@export var speed: float = 1 +@export var damage: float = 10 + +var launcher: EntityBase = null + +func _ready(): + area_entered.connect(hit) + +func hit(target: Node): + var entity: EntityBase = EntityTool.fromHurtbox(target) + if !entity || !launcher: return + if entity == launcher: return + if GameRule.allowFriendlyFire: + if entity.isPlayer() == launcher.isPlayer(): return + entity.takeDamage(self) + +static func generate( + bullet: PackedScene, + launchBy: EntityBase, + spawnPosition: Vector2, + spawnRotation: float, + addToWorld: bool = true + ): + var instance: BulletBase = bullet.instantiate() + instance.launcher = launchBy + instance.position = spawnPosition + instance.rotation = spawnRotation + if addToWorld: + WorldTool.rootNode.add_child(instance) + return instance diff --git a/scripts/Statemachine/ColorBar.gd b/scripts/Statemachine/ColorBar.gd index 9275e26..b73fb29 100644 --- a/scripts/Statemachine/ColorBar.gd +++ b/scripts/Statemachine/ColorBar.gd @@ -1,5 +1,6 @@ @tool extends Control +class_name ColorBar @export var minValue: float = 0 @export var maxValue: float = 100 diff --git a/scripts/Statemachine/EntityBase.gd b/scripts/Statemachine/EntityBase.gd index 99f5008..4c68434 100644 --- a/scripts/Statemachine/EntityBase.gd +++ b/scripts/Statemachine/EntityBase.gd @@ -3,6 +3,8 @@ class_name EntityBase # 这是个抽象类 @export var maxHealth: float = 100 @export var movementSpeed: float = 1 +@export var isBoss: bool = false +@export var weapons: Array[Node2D] = [] @onready var animatree: AnimationTree = $"%animatree" @onready var texture: AnimatedSprite2D = $"%texture" @@ -28,9 +30,32 @@ func move(direction: Vector2): var currentDirection = sign(direction.x) if currentDirection != 0: lastDirection = currentDirection +func takeDamage(bullet: BulletBase): + health -= bullet.damage + if health <= 0: + die() + +# 关于分组 +func isPlayer(): + return is_in_group("players") # 抽象方法 func ai(): pass func attack(_type: int): pass +func die(): + queue_free() + +static func generate( + entity: PackedScene, + spawnPosition: Vector2, + spawnRotation: float, + addtoWorld: bool = true +): + var instance = entity.instance() + instance.position = spawnPosition + instance.rotation = spawnRotation + if addtoWorld: + WorldTool.rootNode.add_child(instance) + return instance diff --git a/scripts/Statemachine/EntityStateBar.gd b/scripts/Statemachine/EntityStateBar.gd index 1881c6e..a9de469 100644 --- a/scripts/Statemachine/EntityStateBar.gd +++ b/scripts/Statemachine/EntityStateBar.gd @@ -2,7 +2,7 @@ extends Node2D @export var entity: EntityBase -@onready var healthBar = $"%health" +@onready var healthBar: ColorBar = $"%health" func _process(_delta): if entity: diff --git a/scripts/Tools/EntityTool.gd b/scripts/Tools/EntityTool.gd new file mode 100644 index 0000000..0e77464 --- /dev/null +++ b/scripts/Tools/EntityTool.gd @@ -0,0 +1,10 @@ +class_name EntityTool + +static func fromHurtbox(node: Node) -> EntityBase: + if node is Area2D: + var texture = node.get_parent() + if texture is AnimatedSprite2D: + var entity = texture.get_parent() + if entity is EntityBase: + return entity as EntityBase + return null \ No newline at end of file diff --git a/scripts/Tools/GameRule.gd b/scripts/Tools/GameRule.gd new file mode 100644 index 0000000..36757f1 --- /dev/null +++ b/scripts/Tools/GameRule.gd @@ -0,0 +1,3 @@ +class_name GameRule + +static var allowFriendlyFire: bool = false # 是否允许友军伤害 \ No newline at end of file diff --git a/scripts/Tools/WorldTool.gd b/scripts/Tools/WorldTool.gd new file mode 100644 index 0000000..2b507a5 --- /dev/null +++ b/scripts/Tools/WorldTool.gd @@ -0,0 +1,9 @@ +extends Node2D +class_name WorldTool + +static var rootNode: Node2D +static var tree: SceneTree + +func _ready(): + tree = get_tree() + rootNode = self diff --git a/world.tscn b/world.tscn index 9072d21..2aac90e 100644 --- a/world.tscn +++ b/world.tscn @@ -1,8 +1,10 @@ -[gd_scene load_steps=2 format=3 uid="uid://dmxi1ikn6avig"] +[gd_scene load_steps=3 format=3 uid="uid://dmxi1ikn6avig"] [ext_resource type="PackedScene" uid="uid://bm7ymrri6pykb" path="res://components/Characters/Rooster.tscn" id="1_7jr0n"] +[ext_resource type="Script" path="res://scripts/Tools/WorldTool.gd" id="1_ei0ch"] [node name="world" type="Node2D"] +script = ExtResource("1_ei0ch") -[node name="rooster" parent="." instance=ExtResource("1_7jr0n")] +[node name="rooster" parent="." groups=["players"] instance=ExtResource("1_7jr0n")] position = Vector2(394, 274)