godot 调用class方法得用实例 不能用脚本引用

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
相关推荐
刘欣的博客3 小时前
Godot的Normalized()函数说明
godot·normalized函数说明
GLDbalala19 小时前
Unity基于自定义管线实现风格化水
unity·游戏引擎
WMX101220 小时前
Unity-登录界面UI制作
ui·unity·游戏引擎
Kurisu5751 天前
深海迷航2修改器 2026.5.16最新破解版加修改器免费下载 一键转存 永久更新 (看到速转存 资源随时走丢)
游戏·游戏引擎·游戏程序·修改器·关卡设计
吾日吾身三摆烂1 天前
Unity协程(Coroutine)底层原理全解析
unity·游戏引擎
UWA1 天前
Unity小游戏优化简谱 | 吃透底层逻辑,告别掉帧与流失
unity·性能优化·游戏引擎·小游戏开发
归真仙人1 天前
【UE】Lightmass可执行文件已经过时
ue5·游戏引擎·ue4·虚幻·unreal engine
风酥糖1 天前
Godot游戏练习01-第34节-开始引入AI开发
人工智能·游戏·godot
WiChP2 天前
【V0.1B9】从零开始的2D游戏引擎开发之路
c++·游戏引擎
winlife_3 天前
Unity 域重载会清空一切:Editor 工具如何让状态在重载后续命
unity·游戏引擎