diff --git a/components/Abstracts/EntityBase.tscn b/components/Abstracts/EntityBase.tscn
index 88673cd..ff3ede3 100644
--- a/components/Abstracts/EntityBase.tscn
+++ b/components/Abstracts/EntityBase.tscn
@@ -114,6 +114,9 @@ tree_root = SubResource("AnimationNodeBlendSpace1D_51ube")
anim_player = NodePath("..")
parameters/blend_position = 1.0
+[node name="weapons" type="Node2D" parent="texture"]
+unique_name_in_owner = true
+
[node name="movebox" type="CollisionShape2D" parent="."]
shape = SubResource("RectangleShape2D_ce3to")
diff --git a/components/Bullets/PurpleCrystal.tscn b/components/Bullets/PurpleCrystal.tscn
index b992a5a..9664231 100644
--- a/components/Bullets/PurpleCrystal.tscn
+++ b/components/Bullets/PurpleCrystal.tscn
@@ -1,6 +1,7 @@
-[gd_scene load_steps=5 format=3 uid="uid://uj0aqhm8wgy8"]
+[gd_scene load_steps=6 format=3 uid="uid://uj0aqhm8wgy8"]
[ext_resource type="PackedScene" uid="uid://crtdkysmnkith" path="res://components/Abstracts/BulletBase.tscn" id="1_45mh7"]
+[ext_resource type="Script" path="res://scripts/Contents/Bullets/PurpleCrystal.gd" id="2_4lnlm"]
[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"]
@@ -17,10 +18,13 @@ animations = [{
[sub_resource type="CircleShape2D" id="CircleShape2D_ty1as"]
[node name="PurpleCrystal" instance=ExtResource("1_45mh7")]
+script = ExtResource("2_4lnlm")
+speed = 5.0
+lifeDistance = 700.0
[node name="texture" parent="." index="0"]
sprite_frames = SubResource("SpriteFrames_r86b3")
[node name="hitbox" parent="." index="1"]
-position = Vector2(0, -13)
+position = Vector2(12, 0)
shape = SubResource("CircleShape2D_ty1as")
diff --git a/components/Characters/Chick.tscn b/components/Characters/Chick.tscn
new file mode 100644
index 0000000..26db075
--- /dev/null
+++ b/components/Characters/Chick.tscn
@@ -0,0 +1,36 @@
+[gd_scene load_steps=5 format=3 uid="uid://b0ncrvm8u4pox"]
+
+[ext_resource type="PackedScene" uid="uid://cvogxi7mktumf" path="res://components/Abstracts/EntityBase.tscn" id="1_goqmy"]
+[ext_resource type="Texture2D" uid="uid://7pkplcqqxvnp" path="res://resources/characters/chick/chick-a.svg" id="2_syddq"]
+[ext_resource type="Texture2D" uid="uid://dj5dvqb8gsedr" path="res://resources/characters/chick/chick-b.svg" id="3_064jv"]
+
+[sub_resource type="SpriteFrames" id="SpriteFrames_xji3d"]
+animations = [{
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("2_syddq")
+}],
+"loop": true,
+"name": &"idle",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("2_syddq")
+}, {
+"duration": 1.0,
+"texture": ExtResource("3_064jv")
+}],
+"loop": true,
+"name": &"walk",
+"speed": 5.0
+}]
+
+[node name="Chick" instance=ExtResource("1_goqmy")]
+
+[node name="texture" parent="." index="0"]
+sprite_frames = SubResource("SpriteFrames_xji3d")
+animation = &"walk"
+
+[node name="statebar" parent="." index="2" node_paths=PackedStringArray("entity")]
+entity = NodePath("..")
diff --git a/components/Characters/Rooster.tscn b/components/Characters/Rooster.tscn
index 339209d..fc44457 100644
--- a/components/Characters/Rooster.tscn
+++ b/components/Characters/Rooster.tscn
@@ -32,6 +32,7 @@ radius = 41.0122
[node name="Rooster" instance=ExtResource("1_e5pl8")]
script = ExtResource("2_oqdqd")
+cooldownUnit = 200.0
[node name="texture" parent="." index="0"]
position = Vector2(0, -70)
@@ -42,6 +43,9 @@ animation = &"walk"
position = Vector2(12, 16)
shape = SubResource("CircleShape2D_h1v0q")
+[node name="normal" type="Node2D" parent="texture/weapons" index="0"]
+position = Vector2(54, -45)
+
[node name="statebar" parent="." index="2" node_paths=PackedStringArray("entity")]
position = Vector2(0, -151)
entity = NodePath("..")
diff --git a/project.godot b/project.godot
index 7d49dac..02b55fe 100644
--- a/project.godot
+++ b/project.godot
@@ -41,6 +41,11 @@ m_right={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
]
}
+attack={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
+]
+}
[rendering]
diff --git a/resources/bullets/purple-crystal/frames/0.svg b/resources/bullets/purple-crystal/frames/0.svg
index 26ffcb7..b3c4e2a 100644
--- a/resources/bullets/purple-crystal/frames/0.svg
+++ b/resources/bullets/purple-crystal/frames/0.svg
@@ -1,27 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/scripts/Contents/Bullets/PurpleCrystal.gd b/scripts/Contents/Bullets/PurpleCrystal.gd
new file mode 100644
index 0000000..a38f4ea
--- /dev/null
+++ b/scripts/Contents/Bullets/PurpleCrystal.gd
@@ -0,0 +1,5 @@
+extends BulletBase
+class_name PurpleCrystal
+
+func ai():
+ forward(Vector2.from_angle(rotation))
diff --git a/scripts/Contents/Characters/Rooster.gd b/scripts/Contents/Characters/Rooster.gd
index 845628a..3a05283 100644
--- a/scripts/Contents/Characters/Rooster.gd
+++ b/scripts/Contents/Characters/Rooster.gd
@@ -10,3 +10,9 @@ func ai():
move(direction)
if direction.length() == 0:
texture.play("idle")
+ if Input.is_action_pressed("attack"):
+ tryAttack(0)
+func attack(type):
+ if type == 0:
+ var weaponPos = findWeaponAnchor("normal")
+ BulletBase.generate(preload("res://components/Bullets/PurpleCrystal.tscn"), self, weaponPos, (get_global_mouse_position() - weaponPos).angle())
diff --git a/scripts/Statemachine/BulletBase.gd b/scripts/Statemachine/BulletBase.gd
index ed6f36b..4b6e9ef 100644
--- a/scripts/Statemachine/BulletBase.gd
+++ b/scripts/Statemachine/BulletBase.gd
@@ -3,11 +3,26 @@ class_name BulletBase
@export var speed: float = 1
@export var damage: float = 10
+@export var lifeDistance: float = -1 # -1表示无限距离
+@export var lifeTime: float = -1 # -1表示无限时间
var launcher: EntityBase = null
+var spawnInWhen: float = 0
+var spawnInWhere: Vector2 = Vector2.ZERO
func _ready():
area_entered.connect(hit)
+ spawnInWhen = Time.get_ticks_msec()
+ spawnInWhere = position
+func _process(_delta: float) -> void:
+ if lifeTime > 0:
+ if Time.get_ticks_msec() - spawnInWhen >= lifeTime:
+ destroy()
+ if lifeDistance > 0:
+ if position.distance_to(spawnInWhere) >= lifeDistance:
+ destroy()
+func _physics_process(_delta: float) -> void:
+ ai()
func hit(target: Node):
var entity: EntityBase = EntityTool.fromHurtbox(target)
@@ -16,6 +31,13 @@ func hit(target: Node):
if GameRule.allowFriendlyFire:
if entity.isPlayer() == launcher.isPlayer(): return
entity.takeDamage(self)
+func forward(direction: Vector2):
+ position += direction.normalized() * speed * GameRule.bulletSpeedMultiplier
+
+func ai():
+ pass
+func destroy():
+ queue_free()
static func generate(
bullet: PackedScene,
diff --git a/scripts/Statemachine/EntityBase.gd b/scripts/Statemachine/EntityBase.gd
index 4c68434..796e5a2 100644
--- a/scripts/Statemachine/EntityBase.gd
+++ b/scripts/Statemachine/EntityBase.gd
@@ -1,10 +1,16 @@
extends CharacterBody2D
class_name EntityBase # 这是个抽象类
-@export var maxHealth: float = 100
-@export var movementSpeed: float = 1
+@export var fields: Dictionary = {
+ FieldStore.Entity.MAX_HEALTH: 100,
+ FieldStore.Entity.DAMAGE_MULTIPILER: 1,
+ FieldStore.Entity.MOVEMENT_SPEED: 1,
+ FieldStore.Entity.ATTACK_SPEED: 1,
+ FieldStore.Entity.CRIT_RATE: 0.05, # 0.05 = 5%
+ FieldStore.Entity.CRIT_DAMAGE: 2 # 2 = 200%
+} # 存一下词条
@export var isBoss: bool = false
-@export var weapons: Array[Node2D] = []
+@export var cooldownUnit: float = 100 # 100毫秒每次攻击
@onready var animatree: AnimationTree = $"%animatree"
@onready var texture: AnimatedSprite2D = $"%texture"
@@ -13,11 +19,12 @@ class_name EntityBase # 这是个抽象类
var health: float = 0
var lastDirection: int = 1
+var lastAttack: int = 0
func _ready():
- health = maxHealth
+ health = fields.get(FieldStore.Entity.MAX_HEALTH)
func _process(_delta):
- health = clamp(health, 0, maxHealth)
+ health = clamp(health, 0, fields.get(FieldStore.Entity.MAX_HEALTH))
animatree.set("parameters/blend_position", lerpf(animatree.get("parameters/blend_position"), lastDirection, 0.1))
func _physics_process(_delta: float) -> void:
velocity = Vector2.ZERO
@@ -26,7 +33,7 @@ func _physics_process(_delta: float) -> void:
# 通用方法
func move(direction: Vector2):
- velocity = direction.normalized() * movementSpeed * 150 * abs(animatree.get("parameters/blend_position"))
+ velocity = direction.normalized() * fields.get(FieldStore.Entity.MOVEMENT_SPEED) * 200 * abs(animatree.get("parameters/blend_position"))
var currentDirection = sign(direction.x)
if currentDirection != 0:
lastDirection = currentDirection
@@ -34,6 +41,22 @@ func takeDamage(bullet: BulletBase):
health -= bullet.damage
if health <= 0:
die()
+func isCooldowned():
+ return Time.get_ticks_msec() - lastAttack >= cooldownUnit
+func startCooldown():
+ var state = isCooldowned()
+ if state:
+ lastAttack = Time.get_ticks_msec()
+ return state
+func tryAttack(type: int):
+ if startCooldown():
+ attack(type)
+func findWeaponAnchor(weaponName: String):
+ var anchor = $"%weapons".get_node(weaponName)
+ if anchor is Node2D:
+ return (anchor.position + texture.position) * Vector2(animatree.get("parameters/blend_position"), 1) + position
+ else:
+ return Vector2.ZERO
# 关于分组
func isPlayer():
@@ -51,11 +74,14 @@ static func generate(
entity: PackedScene,
spawnPosition: Vector2,
spawnRotation: float,
+ isMob: bool = true,
addtoWorld: bool = true
):
- var instance = entity.instance()
+ var instance: EntityBase = entity.instance()
instance.position = spawnPosition
instance.rotation = spawnRotation
+ if isMob:
+ instance.add_to_group("mobs")
if addtoWorld:
WorldTool.rootNode.add_child(instance)
return instance
diff --git a/scripts/Tools/FieldStore.gd b/scripts/Tools/FieldStore.gd
new file mode 100644
index 0000000..35d4015
--- /dev/null
+++ b/scripts/Tools/FieldStore.gd
@@ -0,0 +1,10 @@
+class_name FieldStore
+
+enum Entity {
+ MAX_HEALTH,
+ DAMAGE_MULTIPILER,
+ MOVEMENT_SPEED,
+ ATTACK_SPEED,
+ CRIT_RATE,
+ CRIT_DAMAGE,
+}
\ No newline at end of file
diff --git a/scripts/Tools/GameRule.gd b/scripts/Tools/GameRule.gd
index 36757f1..c4a082b 100644
--- a/scripts/Tools/GameRule.gd
+++ b/scripts/Tools/GameRule.gd
@@ -1,3 +1,4 @@
class_name GameRule
-static var allowFriendlyFire: bool = false # 是否允许友军伤害
\ No newline at end of file
+static var allowFriendlyFire: bool = false # 是否允许友军伤害
+static var bulletSpeedMultiplier: float = 1 # 子弹速度倍率
\ No newline at end of file
diff --git a/scripts/Tools/WorldTool.gd b/scripts/Tools/WorldTool.gd
index 2b507a5..ee69dc3 100644
--- a/scripts/Tools/WorldTool.gd
+++ b/scripts/Tools/WorldTool.gd
@@ -5,5 +5,5 @@ static var rootNode: Node2D
static var tree: SceneTree
func _ready():
- tree = get_tree()
- rootNode = self
+ tree = get_tree()
+ rootNode = self
diff --git a/world.tscn b/world.tscn
index 2aac90e..0d5bc6e 100644
--- a/world.tscn
+++ b/world.tscn
@@ -1,10 +1,23 @@
-[gd_scene load_steps=3 format=3 uid="uid://dmxi1ikn6avig"]
+[gd_scene load_steps=4 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"]
+[ext_resource type="PackedScene" uid="uid://b0ncrvm8u4pox" path="res://components/Characters/Chick.tscn" id="3_jho84"]
[node name="world" type="Node2D"]
script = ExtResource("1_ei0ch")
[node name="rooster" parent="." groups=["players"] instance=ExtResource("1_7jr0n")]
position = Vector2(394, 274)
+
+[node name="chick" parent="." groups=["mobs"] instance=ExtResource("3_jho84")]
+position = Vector2(644, 391)
+
+[node name="Chick" parent="." instance=ExtResource("3_jho84")]
+position = Vector2(366, 547)
+
+[node name="Chick2" parent="." instance=ExtResource("3_jho84")]
+position = Vector2(686, 551)
+
+[node name="Chick3" parent="." instance=ExtResource("3_jho84")]
+position = Vector2(760, 200)