diff --git a/components/Abstracts/EffectBase.tscn b/components/Abstracts/EffectBase.tscn index 1183bc6..646b143 100644 --- a/components/Abstracts/EffectBase.tscn +++ b/components/Abstracts/EffectBase.tscn @@ -7,6 +7,11 @@ [node name="EffectBase" type="Node2D"] script = ExtResource("1_pt2rk") +[node name="sounds" type="Node2D" parent="."] +unique_name_in_owner = true + +[node name="spawn" type="AudioStreamPlayer2D" parent="sounds"] + [node name="particles" type="GPUParticles2D" parent="."] unique_name_in_owner = true amount = 30 diff --git a/components/Abstracts/EntityBase.tscn b/components/Abstracts/EntityBase.tscn index 0bc70a6..2418b84 100644 --- a/components/Abstracts/EntityBase.tscn +++ b/components/Abstracts/EntityBase.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=18 format=3 uid="uid://cvogxi7mktumf"] +[gd_scene load_steps=27 format=3 uid="uid://cvogxi7mktumf"] [ext_resource type="Script" path="res://scripts/Statemachine/EntityBase.gd" id="1_mvol6"] [ext_resource type="Texture2D" uid="uid://dwwpkn4q07ja2" path="res://icon.svg" id="2_7lpu0"] @@ -169,6 +169,49 @@ _data = { "hurt": SubResource("Animation_wl2we") } +[sub_resource type="Curve" id="Curve_cs3iy"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="CurveTexture" id="CurveTexture_r5gvu"] +curve = SubResource("Curve_cs3iy") + +[sub_resource type="Curve" id="Curve_uf1fy"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="CurveTexture" id="CurveTexture_cofpe"] +curve = SubResource("Curve_uf1fy") + +[sub_resource type="Gradient" id="Gradient_nkkgg"] +colors = PackedColorArray(1, 0, 0, 1, 1, 0.84375, 0, 1) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_j74g5"] +gradient = SubResource("Gradient_nkkgg") + +[sub_resource type="Gradient" id="Gradient_m6h1v"] +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_j8vyx"] +gradient = SubResource("Gradient_m6h1v") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_kndb2"] +particle_flag_disable_z = true +emission_shape = 1 +emission_sphere_radius = 50.0 +angle_min = 1.07288e-05 +angle_max = 360.0 +angle_curve = SubResource("CurveTexture_cofpe") +direction = Vector3(-1, 0, 0) +spread = 15.0 +initial_velocity_max = 100.0 +gravity = Vector3(0, 0, 0) +scale_min = 5.0 +scale_max = 15.0 +color_ramp = SubResource("GradientTexture1D_j8vyx") +color_initial_ramp = SubResource("GradientTexture1D_j74g5") +alpha_curve = SubResource("CurveTexture_r5gvu") + [sub_resource type="CircleShape2D" id="CircleShape2D_34h7q"] [node name="EntityBase" type="CharacterBody2D"] @@ -225,6 +268,12 @@ libraries = { [node name="weapons" type="Node2D" parent="texture"] unique_name_in_owner = true +[node name="trailParticle" type="GPUParticles2D" parent="texture"] +unique_name_in_owner = true +z_index = -1 +amount = 300 +process_material = SubResource("ParticleProcessMaterial_kndb2") + [node name="statebar" parent="." instance=ExtResource("2_uje1g")] unique_name_in_owner = true position = Vector2(0, -100) diff --git a/components/Bullets/ChickSprint.tscn b/components/Bullets/ChickSprint.tscn new file mode 100644 index 0000000..f10a605 --- /dev/null +++ b/components/Bullets/ChickSprint.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=4 format=3 uid="uid://dpww053pxchsb"] + +[ext_resource type="PackedScene" uid="uid://crtdkysmnkith" path="res://components/Abstracts/BulletBase.tscn" id="1_hvhrf"] +[ext_resource type="Script" path="res://scripts/Contents/Bullets/ChickSprint.gd" id="2_fecvj"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_rirs4"] +radius = 63.1269 + +[node name="ChickSprint" instance=ExtResource("1_hvhrf")] +script = ExtResource("2_fecvj") + +[node name="hitbox" parent="." index="1"] +shape = SubResource("CircleShape2D_rirs4") diff --git a/components/Characters/Chick.tscn b/components/Characters/Chick.tscn index b423d73..b49b80e 100644 --- a/components/Characters/Chick.tscn +++ b/components/Characters/Chick.tscn @@ -48,7 +48,6 @@ volume_db = -10.0 [node name="texture" parent="." index="1"] position = Vector2(0, -37) sprite_frames = SubResource("SpriteFrames_xji3d") -animation = &"walk" [node name="normal" type="Node2D" parent="texture/weapons" index="0"] position = Vector2(30, -12) diff --git a/components/Effects/AttackStar.tscn b/components/Effects/AttackStar.tscn new file mode 100644 index 0000000..7f84028 --- /dev/null +++ b/components/Effects/AttackStar.tscn @@ -0,0 +1,40 @@ +[gd_scene load_steps=9 format=3 uid="uid://bkwy3rwkihf4m"] + +[ext_resource type="PackedScene" uid="uid://bcvuuy2m0pke0" path="res://components/Abstracts/EffectBase.tscn" id="1_gbycc"] +[ext_resource type="Texture2D" uid="uid://chqmaeivt84b5" path="res://components/UI/attackstar.svg" id="2_2ws80"] +[ext_resource type="AudioStream" uid="uid://cn876dtp1ypqx" path="res://resources/sounds/effect/Collect.wav" id="2_nxkfo"] + +[sub_resource type="Curve" id="Curve_2biku"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.2, 1), 0.0, 0.0, 0, 0, Vector2(0.8, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="CurveTexture" id="CurveTexture_77moo"] +curve = SubResource("Curve_2biku") + +[sub_resource type="Curve" id="Curve_e8ols"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.2, 1), 0.0, 0.0, 0, 0, Vector2(0.8, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="CurveTexture" id="CurveTexture_3oeed"] +curve = SubResource("Curve_e8ols") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_bt5eu"] +particle_flag_disable_z = true +direction = Vector3(0, -1, 0) +initial_velocity_min = 10.0 +initial_velocity_max = 50.0 +gravity = Vector3(0, 0, 0) +scale_curve = SubResource("CurveTexture_3oeed") +alpha_curve = SubResource("CurveTexture_77moo") + +[node name="AttackStar" instance=ExtResource("1_gbycc")] +spawnSound = "spawn" + +[node name="spawn" parent="sounds" index="0"] +stream = ExtResource("2_nxkfo") +volume_db = 10.0 + +[node name="particles" parent="." index="1"] +amount = 1 +process_material = SubResource("ParticleProcessMaterial_bt5eu") +texture = ExtResource("2_2ws80") diff --git a/components/Scenes/World.tscn b/components/Scenes/World.tscn index 8965791..0f127b9 100644 --- a/components/Scenes/World.tscn +++ b/components/Scenes/World.tscn @@ -85,7 +85,7 @@ libraries = { } [node name="background" type="Sprite2D" parent="."] -z_index = -1 +z_index = -100 texture = ExtResource("6_p0nkj") [node name="rooster" parent="." groups=["players"] instance=ExtResource("3_5ui6q")] diff --git a/components/UI/attackstar.svg b/components/UI/attackstar.svg new file mode 100644 index 0000000..9fc53d5 --- /dev/null +++ b/components/UI/attackstar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/components/UI/attackstar.svg.import b/components/UI/attackstar.svg.import new file mode 100644 index 0000000..3946d02 --- /dev/null +++ b/components/UI/attackstar.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://chqmaeivt84b5" +path="res://.godot/imported/attackstar.svg-b1221cbc7b9ccfacea37ada0859e9b08.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://components/UI/attackstar.svg" +dest_files=["res://.godot/imported/attackstar.svg-b1221cbc7b9ccfacea37ada0859e9b08.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/Contents/Bullets/ChickSprint.gd b/scripts/Contents/Bullets/ChickSprint.gd new file mode 100644 index 0000000..4df4e75 --- /dev/null +++ b/scripts/Contents/Bullets/ChickSprint.gd @@ -0,0 +1,11 @@ +extends BulletBase +class_name ChickSprint + +func register(): + speed = 0 + damage = 30 + penerate = 1 +func ai(): + PresetsAI.lockLauncher(self, launcher, true) + if !launcher.sprinting: + tryDestroy() diff --git a/scripts/Contents/Characters/Chick.gd b/scripts/Contents/Characters/Chick.gd index b1f3f68..a5c6d38 100644 --- a/scripts/Contents/Characters/Chick.gd +++ b/scripts/Contents/Characters/Chick.gd @@ -8,9 +8,11 @@ const laserCount = 4 func register(): fields[FieldStore.Entity.MAX_HEALTH] = 2000 fields[FieldStore.Entity.MOVEMENT_SPEED] = 0.35 - attackCooldownMap[0] = 2000 + attackCooldownMap[0] = 500 attackCooldownMap[1] = 6000 attackCooldownMap[2] = 100 + attackCooldownMap[3] = 500 + sprintMultiplier = 60 func spawn(): texture.play("walk") @@ -21,7 +23,8 @@ func ai(): elif currentFocusedBoss.position.distance_to(position) < 700: tryAttack(1) else: - tryAttack(0) + var method = MathTool.randc_from([0, 3]) + tryAttack(method, method == 3) func attack(type): if type == 0: var weaponPos = findWeaponAnchor("normal") @@ -36,4 +39,11 @@ func attack(type): firepot.global_rotation = target firepot.shot() BulletBase.generate(preload("res://components/Bullets/FireScan.tscn"), self, weaponPos, target) + elif type == 3: + trailing = true + BulletBase.generate(preload("res://components/Bullets/ChickSprint.tscn"), self, position, 0) + await trySprint() + trailing = false return true +func sprint(): + move((currentFocusedBoss.position - position).normalized() * sprintMultiplier, true) diff --git a/scripts/Contents/Wave.gd b/scripts/Contents/Wave.gd index 045b592..ed7882f 100644 --- a/scripts/Contents/Wave.gd +++ b/scripts/Contents/Wave.gd @@ -11,8 +11,9 @@ var per: int = 0 static var current: int = 0 static var data: Array[Wave] = [ # entity, minCount, maxCount, isBoss, from, to, per - create(preload("res://components/Characters/Hen.tscn"), 1, 5, false, 0, INF, 1), - create(preload("res://components/Characters/Chick.tscn"), 0, 0, true, 8, INF, 6), + # create(preload("res://components/Characters/Hen.tscn"), 1, 5, false, 0, INF, 1), + # create(preload("res://components/Characters/Chick.tscn"), 0, 0, true, 8, INF, 6), + create(preload("res://components/Characters/Chick.tscn"), 1, 1, true, 0, INF, 1), ] static func create( diff --git a/scripts/Statemachine/EffectController.gd b/scripts/Statemachine/EffectController.gd index f171683..1fa53c7 100644 --- a/scripts/Statemachine/EffectController.gd +++ b/scripts/Statemachine/EffectController.gd @@ -2,12 +2,17 @@ extends Node2D class_name EffectController @export var oneShot: bool = true +@export var spawnSound: String = "" @onready var particles: GPUParticles2D = $"%particles" +@onready var sounds = $"%sounds" func _ready(): particles.emitting = false particles.one_shot = oneShot + var sound = sounds.get_node_or_null(spawnSound) + if sound and sound.stream: + sound.play() func shot(): var cloned = particles.duplicate() as GPUParticles2D cloned.emitting = true diff --git a/scripts/Statemachine/EntityBase.gd b/scripts/Statemachine/EntityBase.gd index f3665eb..1be7707 100644 --- a/scripts/Statemachine/EntityBase.gd +++ b/scripts/Statemachine/EntityBase.gd @@ -55,7 +55,7 @@ var inventoryMax = { @export var defaultCooldownUnit: float = 100 @export var isBoss: bool = false @export var displayName: String = "未知实体" -@export var sprintMultiplier: float = 4 +@export var sprintMultiplier: float = 3 @export var drops: Array[ItemStore.ItemType] = [] @export var dropCounts: Array[Vector2] = [] @export var appleCount: Vector2i = Vector2(0, 2) # 死亡后掉落的苹果数量 @@ -67,15 +67,18 @@ var inventoryMax = { @onready var sounds: Node2D = $"%sounds" @onready var hurtAnimator: AnimationPlayer = $"%hurtAnimator" @onready var damageAnchor: Node2D = $"%damageAnchor" +@onready var trailParticle: GPUParticles2D = $"%trailParticle" var statebar: EntityStateBar var health: float = 0 var energy: float = 0 var sprinting: bool = false +var trailing: bool = false var lastDirection: int = 1 var lastAttack: int = 0 var currentFocusedBoss: EntityBase = null +var charginup: bool = false func _ready(): register() @@ -127,10 +130,11 @@ func _physics_process(_delta: float) -> void: sprinting = false else: velocity = Vector2.ZERO - if isPlayer() or is_instance_valid(currentFocusedBoss): + if (isPlayer() or is_instance_valid(currentFocusedBoss)) and not charginup: ai() move_and_slide() storeEnergy(0.01 * fields.get(FieldStore.Entity.ENERGY_REGENERATION)) + trailParticle.emitting = trailing # 通用方法 func applyLevel(): @@ -187,16 +191,22 @@ func startCooldown(type: int): if state: lastAttack = WorldManager.getTime() return state -func tryAttack(type: int): +func tryAttack(type: int, needChargeUp: bool = false): var state = startCooldown(type) if state: - if attack(type): + if needChargeUp: + charginup = true + await EffectController.create(preload("res://components/Effects/AttackStar.tscn"), damageAnchor.global_position).shot() + charginup = false + else: playSound("attack" + str(type)) + attack(type) return state func trySprint(): playSound("sprint") sprint() sprinting = true + await TickTool.until(func(): return !sprinting) func tryDie(by: BulletBase): for drop in range(min(len(drops), len(dropCounts))): var item = drops[drop] diff --git a/scripts/Tools/TickTool.gd b/scripts/Tools/TickTool.gd index 2a68894..5da04ef 100644 --- a/scripts/Tools/TickTool.gd +++ b/scripts/Tools/TickTool.gd @@ -5,3 +5,6 @@ static func millseconds(ms: int): static func frame(count: int = 1): for i in range(count): await WorldManager.tree.physics_frame +static func until(predicate: Callable): + while not predicate.call(): + await frame()