1
1
mirror of https://github.com/Rundll86/Dog-Lynx-And-HCN.git synced 2026-05-27 22:41:56 +08:00

feat: 添加深海角色和木制子弹相关功能

添加深海角色及其攻击逻辑,包括两种攻击方式:
1. 随机发射水泥子弹
2. 向目标发射三发追踪木制子弹
新增木制子弹资源及脚本,实现追踪效果
调整武器树和波次配置,将深海加入测试波次
优化水泥子弹和筷子子弹的动画效果
This commit is contained in:
2026-04-05 14:23:47 +08:00
parent e61cfecdd3
commit 3691a06f8b
15 changed files with 380 additions and 14 deletions
+98 -2
View File
@@ -1,6 +1,7 @@
[gd_scene format=3 uid="uid://dlrpoaw7tvk4f"]
[ext_resource type="PackedScene" uid="uid://crtdkysmnkith" path="res://components/Abstracts/BulletBase.tscn" id="1_aqfa8"]
[ext_resource type="Script" uid="uid://c1yuakupcia1u" path="res://scripts/Contents/Bullets/Cement.gd" id="2_4j0u0"]
[ext_resource type="Texture2D" uid="uid://u2x7yggx8ga2" path="res://resources/bullets/cement/cement.png" id="2_rsq0g"]
[sub_resource type="SpriteFrames" id="SpriteFrames_4j0u0"]
@@ -14,11 +15,106 @@ animations = [{
"speed": 5.0
}]
[sub_resource type="Animation" id="Animation_rsq0g"]
length = 0.001
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0)
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("%texture/..:speed")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [10.0]
}
[sub_resource type="Animation" id="Animation_4j0u0"]
resource_name = "destroy"
length = 0.5
step = 0.1
[sub_resource type="Animation" id="Animation_rxm0l"]
resource_name = "loop"
loop_mode = 1
step = 0.1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 6.28319]
}
[sub_resource type="Animation" id="Animation_7mqyx"]
resource_name = "spawn"
length = 10.0
step = 0.1
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"handle_modes": PackedInt32Array(0, 2),
"points": PackedFloat32Array(0, -0.25, 0, 0, 0, 12.56, -1, 0, 0, 0),
"times": PackedFloat32Array(0, 1)
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("%texture/..:speed")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [10.0, 0.0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_g12wc"]
_data = {
&"RESET": SubResource("Animation_rsq0g"),
&"destroy": SubResource("Animation_4j0u0"),
&"loop": SubResource("Animation_rxm0l"),
&"spawn": SubResource("Animation_7mqyx")
}
[sub_resource type="CircleShape2D" id="CircleShape2D_b8r1x"]
radius = 76.105194
[node name="Cement" unique_id=5571707 instance=ExtResource("1_aqfa8")]
script = ExtResource("2_4j0u0")
baseDamage = 0.0
penerate = 1.0
autoSpawnAnimation = true
freeAfterSpawn = true
[node name="texture" parent="." index="0" unique_id=162977358]
scale = Vector2(0.3, 0.3)
scale = Vector2(0.7, 0.7)
sprite_frames = SubResource("SpriteFrames_4j0u0")
[node name="animator" parent="texture" index="0" unique_id=1114087117]
libraries/ = SubResource("AnimationLibrary_g12wc")
[node name="hitbox" parent="." index="1" unique_id=175349408]
disabled = true
shape = SubResource("CircleShape2D_b8r1x")
+146 -3
View File
@@ -2,6 +2,7 @@
[ext_resource type="PackedScene" uid="uid://crtdkysmnkith" path="res://components/Abstracts/BulletBase.tscn" id="1_mb274"]
[ext_resource type="Texture2D" uid="uid://c51735ydp13rw" path="res://resources/bullets/kuaizi/kuaizi.png" id="2_vrapo"]
[ext_resource type="AudioStream" uid="uid://cmyq248jgd6kj" path="res://resources/sounds/effect/kuaizi.mp3" id="3_7qns6"]
[sub_resource type="SpriteFrames" id="SpriteFrames_7qns6"]
animations = [{
@@ -14,14 +15,156 @@ animations = [{
"speed": 5.0
}]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_vrapo"]
size = Vector2(164, 20)
[sub_resource type="Animation" id="Animation_vrapo"]
length = 0.001
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0)
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath(".:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(0, 0)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath(".:modulate")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("%hitbox:disabled")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
[sub_resource type="Animation" id="Animation_7qns6"]
resource_name = "destroy"
length = 0.5
step = 0.1
[sub_resource type="Animation" id="Animation_lfw6u"]
resource_name = "loop"
loop_mode = 1
step = 0.1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 6.28319]
}
[sub_resource type="Animation" id="Animation_riea1"]
resource_name = "spawn"
step = 0.05
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.15),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(-400, 0), Vector2(-100, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath(".:modulate")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.15),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)]
}
tracks/2/type = "audio"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("audio")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"clips": [{
"end_offset": 0.0,
"start_offset": 0.0,
"stream": ExtResource("3_7qns6")
}],
"times": PackedFloat32Array(0.11914943)
}
tracks/2/use_blend = true
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("%hitbox:disabled")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.15),
"transitions": PackedFloat32Array(1, 1),
"update": 1,
"values": [true, false]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_ygnl7"]
_data = {
&"RESET": SubResource("Animation_vrapo"),
&"destroy": SubResource("Animation_7qns6"),
&"loop": SubResource("Animation_lfw6u"),
&"spawn": SubResource("Animation_riea1")
}
[sub_resource type="CircleShape2D" id="CircleShape2D_7qns6"]
radius = 35.128338
[node name="Kuaizi" unique_id=5571707 instance=ExtResource("1_mb274")]
displayName = "筷子"
penerate = 1.0
autoSpawnAnimation = true
freeAfterSpawn = true
[node name="texture" parent="." index="0" unique_id=162977358]
scale = Vector2(0.3, 0.3)
sprite_frames = SubResource("SpriteFrames_7qns6")
[node name="animator" parent="texture" index="0" unique_id=1114087117]
libraries/ = SubResource("AnimationLibrary_ygnl7")
[node name="hitbox" parent="." index="1" unique_id=175349408]
shape = SubResource("RectangleShape2D_vrapo")
shape = SubResource("CircleShape2D_7qns6")
+32
View File
@@ -0,0 +1,32 @@
[gd_scene format=3 uid="uid://jmpm68e3um3k"]
[ext_resource type="PackedScene" uid="uid://crtdkysmnkith" path="res://components/Abstracts/BulletBase.tscn" id="1_yfmqu"]
[ext_resource type="Script" uid="uid://bkopn3gee3qp1" path="res://scripts/Contents/Bullets/Wood.gd" id="2_f5eiv"]
[ext_resource type="Texture2D" uid="uid://bols4gt28y3a" path="res://resources/bullets/wood/wood.png" id="3_dol0b"]
[sub_resource type="SpriteFrames" id="SpriteFrames_dth5r"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": ExtResource("3_dol0b")
}],
"loop": true,
"name": &"default",
"speed": 5.0
}]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_8j03k"]
size = Vector2(244, 32)
[node name="Wood" unique_id=5571707 instance=ExtResource("1_yfmqu")]
script = ExtResource("2_f5eiv")
displayName = "浮木"
penerate = 1.0
lifeTime = 5000.0
[node name="texture" parent="." index="0" unique_id=162977358]
scale = Vector2(0.4, 0.4)
sprite_frames = SubResource("SpriteFrames_dth5r")
[node name="hitbox" parent="." index="1" unique_id=175349408]
shape = SubResource("RectangleShape2D_8j03k")
+3
View File
@@ -1,6 +1,7 @@
[gd_scene format=3 uid="uid://nl5h1vcfnn60"]
[ext_resource type="PackedScene" uid="uid://cvogxi7mktumf" path="res://components/Abstracts/EntityBase.tscn" id="1_g8my0"]
[ext_resource type="Script" uid="uid://be0o0iwf26hvx" path="res://scripts/Contents/Characters/Deepsea.gd" id="2_1qdp4"]
[ext_resource type="Texture2D" uid="uid://c6kpcsu1yohak" path="res://resources/characters/deepsea/0.png" id="2_5y3f7"]
[sub_resource type="SpriteFrames" id="SpriteFrames_5y3f7"]
@@ -20,6 +21,8 @@ animations = [{
size = Vector2(165, 349)
[node name="Deepsea" unique_id=1544856335 instance=ExtResource("1_g8my0")]
script = ExtResource("2_1qdp4")
displayName = "深海"
[node name="texture" parent="." index="3"]
sprite_frames = SubResource("SpriteFrames_5y3f7")
+1 -2
View File
@@ -16,7 +16,7 @@ store = {
"atk": 20,
"count": 1.0,
"max": 3.0,
"rate": 0.25
"rate": 1.0
}
storeType = {
"atk": 1,
@@ -38,7 +38,6 @@ descriptionTemplate = "进行[b]格挡[/b],化解飞来的子弹。
sources = Array[String](["Nine Sols", "Terraria"])
tease = "卸劲反伤"
cooldown = 250.0
debugRebuild = true
[node name="avatar" parent="container/info" parent_id_path=PackedInt32Array(1625294072) index="0" unique_id=1021985889]
texture = ExtResource("3_nwamk")
Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

+40
View File
@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bols4gt28y3a"
path="res://.godot/imported/wood.png-1a1cc6e969e42c76808ea00501677f1c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://resources/bullets/wood/wood.png"
dest_files=["res://.godot/imported/wood.png-1a1cc6e969e42c76808ea00501677f1c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
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/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
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
Binary file not shown.
+19
View File
@@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://cmyq248jgd6kj"
path="res://.godot/imported/kuaizi.mp3-4067c01afde7dcc44c9d3255ec893ecc.mp3str"
[deps]
source_file="res://resources/sounds/effect/kuaizi.mp3"
dest_files=["res://.godot/imported/kuaizi.mp3-4067c01afde7dcc44c9d3255ec893ecc.mp3str"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4
+11
View File
@@ -0,0 +1,11 @@
extends BulletBase
class_name CementBullet
func succeedToHit(_dmg: float, _entity: EntityBase):
for i in 3:
BulletBase.generate(ComponentManager.getBullet("Kuaizi"), launcher, position + MathTool.sampleInCircle(50), deg_to_rad(90) + deg_to_rad(randf_range(-1, 1) * 10))
await TickTool.millseconds(200)
await TickTool.millseconds(1000)
tryDestroy()
func ai():
PresetBulletAI.forward(self , rotation)
+1
View File
@@ -0,0 +1 @@
uid://c1yuakupcia1u
+13
View File
@@ -0,0 +1,13 @@
extends BulletBase
class_name WoodBullet
var speedV2: Vector2 = Vector2.ZERO
func spawn():
speedV2 = Vector2.from_angle(rotation) * 10
func ai():
if is_instance_valid(launcher.currentFocusedBoss):
speedV2 += (launcher.currentFocusedBoss.position - launcher.position).normalized() * 1
speed = speedV2.length() / 2.0
rotation = speedV2.angle()
PresetBulletAI.forward(self , rotation)
+1
View File
@@ -0,0 +1 @@
uid://bkopn3gee3qp1
+8 -1
View File
@@ -5,8 +5,15 @@ func register():
fields[FieldStore.Entity.MAX_HEALTH] = 2000
fields[FieldStore.Entity.MOVEMENT_SPEED] = 0.9
fields[FieldStore.Entity.OFFSET_SHOOT] = 2
attackCooldownMap[0] = 1000
attackCooldownMap[1] = 2000
func ai():
PresetEntityAI.follow(self , currentFocusedBoss)
for i in 2:
tryAttack(i)
func attack(type: int):
if type == 0:
pass
BulletBase.generate(ComponentManager.getBullet("Cement"), self , position, deg_to_rad(randf_range(0, 360)))
elif type == 1:
for i in 3:
BulletBase.generate(ComponentManager.getBullet("Wood"), self , position, position.angle_to_point(currentFocusedBoss.position) + i * deg_to_rad(20))
+7 -6
View File
@@ -32,11 +32,12 @@ static var WAVE_NORMAL = [
Wave.create("Bear", 0, 0, true, 29, INF, 23),
]
static var WAVE_TESTBOSS_ALL = [
Wave.create("Kernyr", 0, 0, true, 0, INF, 5),
Wave.create("CyberCat", 0, 0, true, 1, INF, 5),
Wave.create("Chick", 0, 0, true, 2, INF, 5),
Wave.create("KukeMC", 0, 0, true, 3, INF, 5),
Wave.create("Bear", 0, 0, true, 4, INF, 5),
Wave.create("Deepsea", 0, 0, true, 0, INF, 6),
Wave.create("Kernyr", 0, 0, true, 1, INF, 6),
Wave.create("CyberCat", 0, 0, true, 2, INF, 6),
Wave.create("Chick", 0, 0, true, 3, INF, 6),
Wave.create("KukeMC", 0, 0, true, 4, INF, 6),
Wave.create("Bear", 0, 0, true, 5, INF, 6),
]
static var WAVE_TESTBOSS_KUKE = [
Wave.create("KukeMC", 0, 0, true, 0, INF, 1),
@@ -59,7 +60,7 @@ static var WAVE_MOWING = [
]
static var WAVE_EMPTY = []
static var waveReleaseConfig = [WAVE_TESTBOSS_ALL, 1]
static var waveDebugConfig = [WAVE_MOWING, 1]
static var waveDebugConfig = [WAVE_TESTBOSS_ALL, 1]
static var current: int = startWith(waveReleaseConfig[1]) if WorldManager.isRelease() else startWith(waveDebugConfig[1])
static var data = waveReleaseConfig[0] if WorldManager.isRelease() else waveDebugConfig[0]