var enemyplay=preload("res://scripts/EnemyBall.gd")
不能用enemyplay.play调用
得用
func _handle_pocketed(body: RigidBody2D):
if "Enemy" in body.name or "enemy" in body.name:
body.play("xiao")
body.play调用
错误提示说明你在某个地方用 EnemyBall.play() 或 WhiteBall.play() 这种"类名.方法"的形式调用了实例方法。play() 是每个球的实例方法,必须通过实例(比如 self.play() 或某个敌人对象.play())调用。
检查一下你的代码,你是不是写成了这样:
go
gdscript
# 错误写法
if something:
EnemyBall.play() # 错:EnemyBall 是类,不能直接用类名调用实例方法
要改成:
go
gdscript
# 正确写法
self.play("xiao") # 自己播放
# 或者
enemy_instance.play("xiao") # 特定敌人实例播放
go
extends Area2D
@onready var pocket_radius := _get_collision_radius()
@onready var table_rect: Rect2 = _get_table_rect()
var bodies_in_pocket := {}
var enemyplay=preload("res://scripts/EnemyBall.gd")
var whiteplay=preload("res://scripts/WhiteBall.gd")
func _get_collision_radius() -> float:
var shapes = find_children("*", "CollisionShape2D", true, false)
for shape in shapes:
if shape.shape is CircleShape2D:
return shape.shape.radius
return 10.0
func _get_table_rect() -> Rect2:
# 假设你的桌子 Sprite 路径是 "/root/Table/TableSprite"
var table_sprite = get_node_or_null("/root/Table/TableSprite")
if table_sprite and table_sprite is Sprite2D:
var texture = table_sprite.texture
if texture:
var tex_size = texture.get_size() * table_sprite.scale
# Sprite2D 的 global_position 是纹理中心,所以矩形左上角是中心减去一半尺寸
var top_left = table_sprite.global_position - tex_size / 2
var rect = Rect2(top_left, tex_size)
# 缩一点边距,让球不贴墙
return rect.grow(-70)
# 回退默认值
return Rect2(150, 250, 330, 610)
func _get_ball_radius(body: RigidBody2D) -> float:
for child in body.get_children():
if child is CollisionShape2D and child.shape is CircleShape2D:
return child.shape.radius
return 30.0
func _ready():
body_entered.connect(_on_body_entered)
body_exited.connect(_on_body_exited)
func _on_body_entered(body: Node2D):
if body is RigidBody2D:
bodies_in_pocket[body.get_instance_id()] = body
func _on_body_exited(body: Node2D):
if body is RigidBody2D:
bodies_in_pocket.erase(body.get_instance_id())
func _physics_process(_delta):
for id in bodies_in_pocket.keys():
var body = bodies_in_pocket[id]
if not is_instance_valid(body):
bodies_in_pocket.erase(id)
continue
# 获取CollisionShape2D的实际中心(Area2D位置 + Shape偏移)
var collision_shape = find_child("CollisionShape2D", false, false)
var pocket_center = global_position
if collision_shape:
pocket_center = global_position + collision_shape.position
var dist = pocket_center.distance_to(body.global_position)
var ball_radius = _get_ball_radius(body)
# 球进洞条件:球心到球袋中心距离 < 球袋半径(这样球至少有部分在袋内)
# 更严格可以减球半径: dist < pocket_radius - ball_radius
var threshold = pocket_radius
if dist < threshold:
print(body.name, " 进洞!距离:", dist, " 阈值:", threshold, " 球半径:", ball_radius, " 袋半径:", pocket_radius)
_handle_pocketed(body)
bodies_in_pocket.erase(id)
func _handle_pocketed(body: RigidBody2D):
if "Enemy" in body.name or "enemy" in body.name:
body.play("xiao")
print(body.name, " 进洞!")
# 通知Game敌人进洞,奖励耍赖币
var game = get_node_or_null("/root/Main/Game")
if game and game.has_signal("enemy_pocketed"):
game.emit_signal("enemy_pocketed")
body.queue_free()
else:
print(body.name, " 玩家进洞!")
# 1. 球立即消失
body.visible = false
body.set_physics_process(false)
# 扣一半血
var health_bar = body.find_child("HealthBar")
if health_bar:
health_bar.current_health *= 0.5
health_bar.health_bar.value = health_bar.current_health
health_bar.label.text = "%d/%d" % [health_bar.current_health, health_bar.max_health]
# 2. 显示提示
_show_pocket_message()
# 3. 3秒后重置球
await get_tree().create_timer(3.0).timeout
_reset_ball_to_table(body)
var _pocket_label: Label
func _show_pocket_message():
# 获取或创建提示Label
if not _pocket_label:
_pocket_label = Label.new()
_pocket_label.name = "PocketMessage"
_pocket_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_pocket_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_pocket_label.add_theme_font_size_override("font_size", 48)
_pocket_label.add_theme_color_override("font_color", Color.RED)
_pocket_label.add_theme_color_override("font_outline_color", Color.WHITE)
_pocket_label.add_theme_constant_override("outline_size", 8)
# 放在屏幕中央
var vp = get_viewport()
_pocket_label.set_anchors_preset(Control.PRESET_CENTER)
add_child(_pocket_label)
_pocket_label.text = "玩家进洞!"
_pocket_label.visible = true
# 等待后隐藏
await get_tree().create_timer(2.5).timeout
_pocket_label.visible = false
func _reset_ball_to_table(ball: RigidBody2D):
print("===== 重置球到桌面 =====")
# 直接用一个"硬"的安全中心点,或者动态取视图中心
#var screen_center = get_viewport().get_visible_rect().size / 2
# 随机偏移一个合理范围,例如 x:±200, y:±100
#var offset = Vector2(randf_range(-70, 70), randf_range(-70, 70))
var center = table_rect.get_center()
var offset = Vector2(randf_range(-60, 60), randf_range(-60, 60))
ball.global_position = center + offset
# 保险 clamp 防止出界
ball.global_position.x = clamp(ball.global_position.x, table_rect.position.x + 30, table_rect.end.x - 30)
ball.global_position.y = clamp(ball.global_position.y, table_rect.position.y + 30, table_rect.end.y - 30)
ball.linear_velocity = Vector2.ZERO
ball.angular_velocity = 0.0
ball.visible = true
ball.set_physics_process(true)
ball.contact_monitor = true
ball.max_contacts_reported = 10