1
1
mirror of https://github.com/Rundll86/Dog-Lynx-And-HCN.git synced 2026-05-28 06:51:54 +08:00

Compare commits

...

6 Commits

Author SHA1 Message Date
fallingshrimp 2f3912da34 fix(Feed): 修复countOf函数中乘数应用的逻辑错误
当基础值为正数时使用乘法,为负数时使用除法,确保计算结果的正确性
2026-05-05 07:31:35 +08:00
fallingshrimp 75fbef8895 fix(EntityBase): 修复玩家角色死亡时被立即移除的问题
修改tryDie方法,仅当非玩家角色时才调用queue_free
同时更新牧羊犬角色的标语和配置
2026-05-05 07:14:41 +08:00
fallingshrimp 14deb2de71 feat: 添加暂停面板类名并优化字段显示逻辑
修复TipBox销毁时的动画冲突问题
重构游戏重启逻辑以包含库存保存
移除GameOver面板中的重复库存保存代码
优化UIState中的字段显示控制和提示清除功能
2026-05-05 07:04:32 +08:00
fallingshrimp cc103f274b fix: 调整MuyangDog的子弹检测范围并修复UIState字段显示问题
修复MuyangDog角色子弹检测范围从400减少到300以平衡游戏难度
在UIState中添加字段动画播放状态检查,防止动画冲突
2026-05-05 06:54:09 +08:00
fallingshrimp 30527a18a8 feat: 添加游戏控制和管理功能
- 新增GameControl节点用于统一处理游戏重启和退出
- 添加GameBusManager管理游戏重启时的资源清理
- 修改Pause和GameOver面板使用新的GameControl
- 为EffectController和ItemDropped添加分组管理
- 统一使用WorldManager管理游戏时间
2026-05-05 06:51:48 +08:00
fallingshrimp f6e71507ce chore: 清理无用文件和更新游戏规则脚本
删除不再需要的图片、批处理文件和日志文件
更新todo.md移除已完成的任务项
在GameRule.gd中添加helpText静态变量
2026-05-05 06:24:55 +08:00
31 changed files with 131 additions and 135 deletions
+3 -2
View File
@@ -17,11 +17,12 @@ corner_detail = 1
[node name="MuyangDog" unique_id=1046363300 instance=ExtResource("1_wq25g")]
theme_override_styles/panel = SubResource("StyleBoxFlat_fi2nw")
displayName = "牧羊犬"
slogan = "以身挡险,恪守使命不离不弃"
slogan = "恪守使命不离不弃"
avatar = ExtResource("2_fi2nw")
description = "每3秒发动格挡,弹反一切子弹。"
fields = Array[int]([0, 8, 3])
fieldValues = Array[float]([50.0, 0.15, -0.2])
clickToRebuild = true
[node name="avatarTexture" parent="wrapper" parent_id_path=PackedInt32Array(2023039659) index="0" unique_id=1334645594]
texture = ExtResource("2_fi2nw")
@@ -30,7 +31,7 @@ texture = ExtResource("2_fi2nw")
text = "牧羊犬"
[node name="sloganLabel" parent="wrapper/infoContainer/VBoxContainer" parent_id_path=PackedInt32Array(533915880) index="1" unique_id=280562204]
text = "“以身挡险,恪守使命不离不弃”"
text = "“恪守使命不离不弃”"
[node name="descriptionLabel" parent="wrapper/infoContainer" parent_id_path=PackedInt32Array(143242635) index="1" unique_id=808054282]
text = "每3秒发动格挡,弹反一切子弹。"
@@ -1,9 +1,10 @@
[gd_scene format=3 uid="uid://beo6s1kudbbve"]
[gd_scene format=3 uid="uid://b14x2fai2bagp"]
[ext_resource type="PackedScene" uid="uid://d3qojeqa3difn" path="res://components/Abstracts/FullscreenPanelBase.tscn" id="1_u2ynr"]
[ext_resource type="Script" uid="uid://bub7ku5qf2tpo" path="res://scripts/Contents/Panels/GameOver.gd" id="2_6cd45"]
[ext_resource type="FontFile" uid="uid://v3frxpuvtj5o" path="res://resources/fonts/syht-bold.ttf" id="3_2arur"]
[ext_resource type="AudioStream" uid="uid://dbso1w8hvgilg" path="res://resources/sounds/effect/Lose.wav" id="3_n4aax"]
[ext_resource type="PackedScene" uid="uid://braggv3vafd83" path="res://components/UI/GameControl.tscn" id="4_idc4g"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7gbuu"]
bg_color = Color(1, 0, 0, 0.3)
@@ -48,21 +49,9 @@ text = "[color=gray]死亡原因[/color]"
fit_content = true
autowrap_mode = 0
[node name="gameControl" type="HBoxContainer" parent="content/wrapper/container/wrapper" index="1" unique_id=2129714003]
layout_mode = 2
alignment = 1
[node name="returnBtn" type="Button" parent="content/wrapper/container/wrapper/gameControl" index="0" unique_id=1955688444]
[node name="gameControl" parent="content/wrapper/container/wrapper/death" index="2" unique_id=1187018703 instance=ExtResource("4_idc4g")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
text = "重新开始游戏"
[node name="exitBtn" type="Button" parent="content/wrapper/container/wrapper/gameControl" index="1" unique_id=1303303813]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
text = "退出游戏"
[node name="audio" type="AudioStreamPlayer2D" parent="." index="2" unique_id=2020590816]
unique_name_in_owner = true
@@ -1,14 +1,15 @@
[gd_scene load_steps=5 format=3 uid="uid://cksonrrx38k36"]
[gd_scene format=3 uid="uid://cksonrrx38k36"]
[ext_resource type="PackedScene" uid="uid://d3qojeqa3difn" path="res://components/Abstracts/FullscreenPanelBase.tscn" id="1_q0gd0"]
[ext_resource type="Script" path="res://scripts/Contents/Panels/Pause.gd" id="2_lg6qs"]
[ext_resource type="Script" uid="uid://ba0tgtpjp34k8" path="res://scripts/Contents/Panels/Pause.gd" id="2_lg6qs"]
[ext_resource type="FontFile" uid="uid://v3frxpuvtj5o" path="res://resources/fonts/syht-bold.ttf" id="3_jxeor"]
[ext_resource type="PackedScene" uid="uid://braggv3vafd83" path="res://components/UI/GameControl.tscn" id="4_tij4f"]
[sub_resource type="LabelSettings" id="LabelSettings_hsvpc"]
font = ExtResource("3_jxeor")
font_size = 50
[node name="Pause" instance=ExtResource("1_q0gd0")]
[node name="Pause" unique_id=518412591 instance=ExtResource("1_q0gd0")]
offset_top = 0.0
offset_bottom = 0.0
script = ExtResource("2_lg6qs")
@@ -16,14 +17,12 @@ script = ExtResource("2_lg6qs")
[node name="wrapper" parent="content" index="1"]
theme_override_constants/separation = 10
[node name="text" type="Label" parent="content/wrapper" index="0"]
[node name="text" type="Label" parent="content/wrapper" index="0" unique_id=884780519]
layout_mode = 2
size_flags_horizontal = 4
text = "已暂停"
label_settings = SubResource("LabelSettings_hsvpc")
[node name="aboutBtn" type="Button" parent="content/wrapper" index="1"]
[node name="gameControl" parent="content/wrapper" index="1" unique_id=1187018703 instance=ExtResource("4_tij4f")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
text = "关于↗"
+19
View File
@@ -0,0 +1,19 @@
[gd_scene format=3 uid="uid://braggv3vafd83"]
[ext_resource type="Script" uid="uid://b63fkg0waovo" path="res://scripts/Statemachine/GameControl.gd" id="1_t5a04"]
[node name="GameControl" type="HBoxContainer" unique_id=1187018703]
size_flags_horizontal = 4
script = ExtResource("1_t5a04")
[node name="returnBtn" type="Button" parent="." unique_id=2089710932]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
text = "重新开始游戏"
[node name="exitBtn" type="Button" parent="." unique_id=100260653]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
text = "退出游戏"
-5
View File
@@ -1,5 +0,0 @@
# Playlog
## 2025/9/30
平衡性已调整,可3个boss同窗无伤打完。
-4
View File
@@ -1,4 +0,0 @@
@echo off
cd build/web
python -m http.server 8080
View File
+1 -1
View File
@@ -6,7 +6,7 @@ func ai():
super.ai()
if parryCounter.isCooldowned():
var track = getTrackingAnchor()
var bullet = BulletTool.findClosetBulletCanDamage(track, get_tree(), self , 400)
var bullet = BulletTool.findClosetBulletCanDamage(track, get_tree(), self , 300)
if is_instance_valid(bullet):
BulletBase.generate(ComponentManager.getBullet("Parrier"), self , track, track.angle_to_point(bullet.position))
parryCounter.start()
+2 -2
View File
@@ -52,7 +52,7 @@ func tryLaunch(action: String, weaponIndex: int):
var weapon = weapons[weaponIndex]
if weapon.emitType == Weapon.EmitType.CHARGE:
if weapon.canAttackBy(self ):
chargeStartTime[weaponIndex] = Time.get_ticks_msec()
chargeStartTime[weaponIndex] = WorldManager.getTime()
chargeParticle.emitting = true
chargeParticle.speed_scale = 1
elif weapon.emitType == Weapon.EmitType.CLICK_SHOOT || weapon.emitType == Weapon.EmitType.HOLD_LOOP:
@@ -70,7 +70,7 @@ func tryLaunch(action: String, weaponIndex: int):
if weapon.emitType == Weapon.EmitType.CHARGE:
if chargeStartTime.has(weaponIndex):
var startTime = chargeStartTime[weaponIndex]
var endTime = Time.get_ticks_msec()
var endTime = WorldManager.getTime()
var chargedTime = endTime - startTime
chargeStartTime.erase(weaponIndex)
weapon.chargedTime = chargedTime * self.fields.get(FieldStore.Entity.CHARGE_SPEED)
+2 -2
View File
@@ -52,7 +52,7 @@ func tryLaunch(action: String, weaponIndex: int):
var weapon = weapons[weaponIndex]
if weapon.emitType == Weapon.EmitType.CHARGE:
if weapon.canAttackBy(self ):
chargeStartTime[weaponIndex] = Time.get_ticks_msec()
chargeStartTime[weaponIndex] = WorldManager.getTime()
chargeParticle.emitting = true
chargeParticle.speed_scale = 1
elif weapon.emitType == Weapon.EmitType.CLICK_SHOOT || weapon.emitType == Weapon.EmitType.HOLD_LOOP:
@@ -70,7 +70,7 @@ func tryLaunch(action: String, weaponIndex: int):
if weapon.emitType == Weapon.EmitType.CHARGE:
if chargeStartTime.has(weaponIndex):
var startTime = chargeStartTime[weaponIndex]
var endTime = Time.get_ticks_msec()
var endTime = WorldManager.getTime()
var chargedTime = endTime - startTime
chargeStartTime.erase(weaponIndex)
weapon.chargedTime = chargedTime * self.fields.get(FieldStore.Entity.CHARGE_SPEED)
+2 -21
View File
@@ -3,30 +3,11 @@ extends FullscreenPanelBase
@onready var audio: AudioStreamPlayer2D = $%audio
@onready var deadreason: RichTextLabel = $%deadreason
@onready var returnBtn: Button = $%returnBtn
@onready var exitBtn: Button = $%exitBtn
func _ready():
returnBtn.pressed.connect(
func():
returnBtn.disabled = true
for bullet in get_tree().get_nodes_in_group("bullets"):
bullet.queue_free()
for entity in get_tree().get_nodes_in_group("entities"):
entity.queue_free()
UIState.setPanel("Starter")
)
exitBtn.pressed.connect(
func():
get_tree().quit()
)
@onready var gameControl: GameControl = $%gameControl
func beforeOpen(args: Array = []):
audio.play()
var reasonTemplate = MathTool.randomChoiceFrom(GameRule.deadReasons)
deadreason.text = ("[color=gray]" + reasonTemplate + "凶手是[b]%s[/b]的[b]%s[/b]。[/color]") % args
for item in OutGameStorage.inventory:
OutGameStorage.inventory[item] += UIState.player.inventory[item]
func afterOpen(_args: Array = []):
returnBtn.disabled = false
exitBtn.disabled = false
gameControl.enable()
+4 -6
View File
@@ -1,10 +1,8 @@
@tool
extends FullscreenPanelBase
class_name PausePanel
@onready var aboutBtn: Button = $"%aboutBtn"
@onready var gameControl: GameControl = $%gameControl
func _ready():
aboutBtn.pressed.connect(
func():
UIState.setPanel("Thanks")
)
func afterOpen(_args: Array = []):
gameControl.enable()
+2 -2
View File
@@ -8,10 +8,10 @@ var distance: float = 200
var bullets: Array[BulletBase] = []
func start():
startTime = Time.get_ticks_msec()
startTime = WorldManager.getTime()
running = true
func lifetime():
return Time.get_ticks_msec() - startTime
return WorldManager.getTime() - startTime
func getStateAngle(index: int):
return lifetime() / period * deg_to_rad(360) - deg_to_rad(360.0 * index / len(bullets))
func forceFilter():
+1
View File
@@ -59,4 +59,5 @@ static func create(scene: PackedScene, spawnPosition: Vector2, parent: Node = nu
parent.add_child(cloned)
else:
WorldManager.rootNode.add_child(cloned)
cloned.add_to_group("effects")
return cloned
+2 -1
View File
@@ -448,7 +448,8 @@ func tryDie(by: BulletBase = null):
UIState.showTip("[b]%s[/b] 已被打败!" % displayName, TipBox.MessageType.CONGRATULATION)
elif isPlayer():
UIState.showTip("[b]%s[/b] 似了😭。" % displayName, TipBox.MessageType.ERROR)
queue_free()
if !isPlayer():
queue_free()
func tryHeal(count: float):
playSound("heal")
healed.emit(heal(count * fields.get(FieldStore.Entity.HEAL_ABILITY)))
+25
View File
@@ -0,0 +1,25 @@
extends Control
class_name GameControl
@onready var returnBtn: Button = $%returnBtn
@onready var exitBtn: Button = $%exitBtn
func _ready():
returnBtn.pressed.connect(
func():
disable()
GameBusManager.restart(get_tree())
)
exitBtn.pressed.connect(
func():
disable()
get_tree().quit()
)
enable()
func enable():
returnBtn.disabled = false
exitBtn.disabled = false
func disable():
returnBtn.disabled = true
exitBtn.disabled = true
+1
View File
@@ -0,0 +1 @@
uid://b63fkg0waovo
+1
View File
@@ -64,6 +64,7 @@ static func generate(
WorldManager.rootNode.call_deferred("add_child", instance)
instance.add_to_group("drops")
instance.refindPlayer(WorldManager.tree)
instance.add_to_group("items")
return instance
static func getDrops() -> Array[ItemDropped]:
var result: Array[ItemDropped] = []
+1
View File
@@ -31,6 +31,7 @@ func _process(_delta):
label.text = text
func destroy():
if animator.is_playing(): return
animator.play("hide")
await animator.animation_finished
queue_free()
+24 -11
View File
@@ -15,6 +15,8 @@ static var tips: VBoxContainer
static var itemsContainer: Control
static var energyContainer: Control
static var showingFields: bool = false
func _ready():
bossbar = $%bossbar
panels = $%panels
@@ -43,17 +45,23 @@ func _physics_process(_delta):
bossbar.visible = true
itemsContainer.visible = true
energyContainer.visible = true
if Input.is_action_just_pressed("showFields"):
for i in fields.get_children():
fields.remove_child(i)
for i in player.fields:
if player.fields[i] == EntityBase.TITLE_FLAG:
fields.add_child(QuickUI.graySmallText(i))
else:
fields.add_child(FieldShow.create(i, player.fields[i], false, player, true))
fieldsAnimator.play("show")
if Input.is_action_just_released("showFields"):
fieldsAnimator.play("hide")
if !fieldsAnimator.is_playing():
if showingFields:
if Input.is_action_just_released("showFields") || !(currentPanel is PausePanel):
showingFields = false
fieldsAnimator.play("hide")
else:
if Input.is_action_just_pressed("showFields") || currentPanel is PausePanel:
showingFields = true
for i in fields.get_children():
fields.remove_child(i)
for i in player.fields:
if player.fields[i] == EntityBase.TITLE_FLAG:
fields.add_child(QuickUI.graySmallText(i))
else:
fields.add_child(FieldShow.create(i, player.fields[i], false, player, true))
fieldsAnimator.play("show")
if Input.is_action_just_pressed("pause"):
if currentPanel:
if currentPanel is MakeFeedPanel:
@@ -95,5 +103,10 @@ static func closeCurrentPanel():
static func showTip(text: String, messageType: TipBox.MessageType = TipBox.MessageType.INFO):
var box = TipBox.create(text, messageType)
tips.add_child(box)
await box.animator.animation_finished
await TickTool.millseconds(500 * len(text))
box.destroy()
static func clearTips():
for child in tips.get_children():
if child is TipBox:
child.destroy()
+2 -1
View File
@@ -72,7 +72,8 @@ func apply(entity: EntityBase):
selected.emit(allHave)
return allHave
func countOf(index: int) -> int:
return ceil(costCounts[index] * multipiler())
var base = costCounts[index]
return ceil(base * multipiler()) if base > 0 else floor(base / multipiler())
func multipiler() -> float:
if is_instance_valid(UIState.player):
return 1 - UIState.player.fields.get(FieldStore.Entity.PRICE_REDUCTION)
+1
View File
@@ -1,6 +1,7 @@
class_name GameRule
static var deadReasons: Array = JsonTool.parseJson("res://resources/constants/deadReasons.json")
static var helpText: String
static var difficultyRange: Vector2 = Vector2(-20, 50) # 难度倍数范围,包括最小值和最大值,负数则降低难度
static var difficulty: float = 1 # 难度倍数,可以写小数
static var allowFriendlyFire: bool = false # 是否允许友军伤害
+5 -1
View File
@@ -7,6 +7,7 @@ class_name CameraManager
@onready var animator: AnimationPlayer = $"%animator"
var shakeIntensity: float = 0
var shaking: bool = false
static var instance: CameraManager = null
@@ -25,8 +26,11 @@ static func shake(millseconds: float, intensity: float = 10, steper: Callable =
await TickTool.until(
func():
instance.shakeIntensity = steper.call(instance.shakeIntensity, intensity, 1 - (WorldManager.getTime() - startTime) / millseconds)
return WorldManager.getTime() - startTime >= millseconds
return WorldManager.getTime() - startTime >= millseconds || !instance.shaking
)
instance.shakeIntensity = 0
static func shakeStop():
instance.shaking = false
instance.shakeIntensity = 0
static func playAnimation(animation: String):
instance.animator.play(animation)
+17
View File
@@ -0,0 +1,17 @@
class_name GameBusManager
static func restart(tree: SceneTree):
for bullet in tree.get_nodes_in_group("bullets"):
bullet.queue_free()
for entity in tree.get_nodes_in_group("entities"):
entity.queue_free()
for effect in tree.get_nodes_in_group("effects"):
effect.queue_free()
for item in tree.get_nodes_in_group("items"):
item.queue_free()
OutGameStorage.saveInventory()
CameraManager.shakeStop()
WorldManager.timeRestart()
UIState.setPanel("Starter")
@@ -0,0 +1 @@
uid://cf1agt55tt4pu
+2
View File
@@ -38,6 +38,8 @@ func spawn(node: Node):
func justReturn(data):
return ArrayTool.parseEncodedObject(data)[0]
static func timeRestart():
runningTime = 0
static func getTime():
return runningTime
static func spawnNode(node: Node):
+4
View File
@@ -19,3 +19,7 @@ static var upgradableFieldsLevel = ArrayTool.fill(upgradableFieldsAdvance, func(
static var maxInitialFeedCount: int = 3
static var maxInitialWeaponCount: int = 3
static var inventory = ArrayTool.fill(upgradableFieldsCost, func(_k): return 0)
static func saveInventory():
for item in OutGameStorage.inventory:
OutGameStorage.inventory[item] += UIState.player.inventory[item]
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 KiB

-40
View File
@@ -1,40 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dkawfjwj80sqj"
path="res://.godot/imported/sjt.png-1b93f593cde723b537a6010a0c0d0d60.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://sjt.png"
dest_files=["res://.godot/imported/sjt.png-1b93f593cde723b537a6010a0c0d0d60.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
BIN
View File
Binary file not shown.
-15
View File
@@ -1,18 +1,3 @@
# Todo
1. 完成Godockly UGC框架。
2. 设计新boss
## 新boss
主题:强大的防御能力+近战攻击。
### 招式
1. 使用**扫帚**进行4段挥舞攻击,上挑-下批-短戳-突刺(cooldown=6s
2. **扫帚**蓄力0.5s,向玩家冲刺,**距离足够近或冲刺结束**后挥出武器(蓄力+攻击互斥)
3. 召唤3把**扫帚炮**,每0.2s释放发射一柱**灰尘射线**cooldown=10s
4. 召唤**自旋扫帚**,每1秒旋转1圈,此时boss移速+100%cooldown=8s,蓄力)
5. 发射**扫帚回旋镖**,可飞行1秒后回旋(攻击互斥)
6. 发动**格挡**,抵挡玩家的近战或射弹伤害(cooldown=2s
7. 发动**闪避**,侧向冲刺躲避离自身最近的玩家子弹(cooldown=5s