Dont understand why dont working highscore(without saving)

Godot Version

3
Highscore

extends Node2D

# High score variable
var high_score := 0

# Reference to the label node
onready var high_score_label = get_node("/root/Game/Control/Highscore")

func _ready():
	# Initialize the label with the current high score
	_update_high_score_label()

func _update_high_score_label():
	# Update the label text
	high_score_label.text = "High Score: %d" % high_score

func _on_player_score_increased(new_score: int):
	# Check if the new score is higher than the current high score
	if new_score > high_score:
		high_score = new_score
		_update_high_score_label()

Line2d

extends Line2D

var drawing = false
var custom_points = []
onready var score_label = get_node("/root/Game/Control/Score")  # Score label
onready var center_point = get_node("/root/Game/Control/Star")   # Center point of the circle
onready var animation_player = get_node("/root/Game/Control/AnimationPlayer")  # Animation player
onready var blackhole = get_node("/root/Game/Control/Blackhole") 
onready var explosion = get_node("/root/Game/Control/Explosion") 


var min_circle_points = 10  # Minimum number of points to consider a circle
var line_thickness = 10  # Initial line thickness
var start_angle = 0.0  # Start angle for circle drawing
var angle_covered = 0.0  # Total angle covered during drawing
var last_angle = 0.0  # Last angle position
var total_sign = 0.0  # Total movement direction
var error_change_direction = false  # Error check state
var is_animation_playing = false  # Track if animation is currently playing

func _ready():
	self.width = line_thickness  # Set the initial line thickness
	self.default_color = Color(1, 1, 1)  # Set the line color to white
	if animation_player:
		animation_player.connect("animation_finished", self, "_on_animation_finished")
	else:
		print("Error: AnimationPlayer node is not assigned")
	
	# Initialize the score label
	score_label.text = "Score: 0"

func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and event.pressed:
			drawing = true
			error_change_direction = false  # Reset error check
			custom_points = []  # Clear previous points
			start_angle = get_angle()  # Save the start angle
			angle_covered = 0.0  # Reset angle coverage
			total_sign = 0.0  # Reset sign count
			last_angle = start_angle  # Initialize last angle
			if is_animation_playing:
				_reset_animation()  # Reset the animation if it is playing
			score_label.text = "Score: 0"  # Reset the score label
		elif event.button_index == BUTTON_LEFT and not event.pressed:
			drawing = false
			_on_draw_finished()

	if event is InputEventMouseMotion and drawing:
		custom_points.append(event.position)
		update()
		_on_draw_in_progress()

func _draw():
	if custom_points.size() > 1:
		draw_polyline(custom_points, self.default_color, line_thickness)  # Always draw the line white

func _on_draw_in_progress():
	var perfection_score = calculate_perfection()
	score_label.text = "%0.1f" % perfection_score  # Update score label with the current score

	var current_angle = get_angle()

	var angle_diff1 = fmod(current_angle + 360.0, 360.0) - fmod(last_angle + 360.0, 360.0)
	var angle_diff2 = fmod(current_angle + 540.0, 360.0) - fmod(last_angle + 540.0, 360.0)
	var sign_diff = 0

	if abs(angle_diff1) <= abs(angle_diff2):
		sign_diff = sign(angle_diff1)
	else:
		sign_diff = sign(angle_diff2)

	total_sign += sign_diff

	if abs(total_sign) < custom_points.size() * 0.75 and custom_points.size() > 3:
		error_change_direction = true
		drawing = false
		_on_draw_finished()

	var angle_diff = min(abs(angle_diff1), abs(angle_diff2))
	angle_covered += sign_diff * angle_diff
	last_angle = current_angle

	if abs(angle_covered) >= 360.0:
		drawing = false
		_on_draw_finished()

func _on_draw_finished():
	if error_change_direction or abs(angle_covered) < 340.0:
		score_label.text = "It's not a circle"
		custom_points = []
		return

	var perfection_score = calculate_perfection()

	if perfection_score >= 50:
		_play_explosion_animation()  # Play explosion animation when score is 50 or more
		explosion.visible = true

	if is_near_complete_circle():
		print("Completed a circle!")
		custom_points = []



func is_near_complete_circle():
	if custom_points.size() < min_circle_points:
		return false

	var center = Vector2()
	for point in custom_points:
		center += point
	center /= custom_points.size()

	var total_distance = 0.0
	for point in custom_points:
		total_distance += center.distance_to(point)
	var average_radius = total_distance / custom_points.size()

	var max_deviation = 0.0
	for point in custom_points:
		var distance = center.distance_to(point)
		max_deviation = max(max_deviation, abs(distance - average_radius))

	return max_deviation < 15

func calculate_perfection():
	if custom_points.size() < 3:
		return 0

	var center = Vector2()
	for point in custom_points:
		center += point
	center /= custom_points.size()

	var total_distance = 0.0
	for point in custom_points:
		total_distance += center.distance_to(point)
	var average_distance = total_distance / custom_points.size()

	var deviation = 0.0
	for point in custom_points:
		deviation += abs(center.distance_to(point) - average_distance)
	var average_deviation = deviation / custom_points.size()

	return max(0, min(100, 100 - average_deviation))

func get_angle():
	if not center_point:
		print("Error: center_point is null")
		return 0

	var center_position = center_point.global_position
	return center_position.angle_to_point(get_global_mouse_position()) * 180.0 / PI

func _play_explosion_animation():
	if animation_player:
		animation_player.play("Explosion")
		is_animation_playing = true  # Mark animation as playing
	else:
		print("Error: AnimationPlayer node is not assigned")

func _reset_animation():
	if animation_player:
		animation_player.stop()  # Stop the current animation
		is_animation_playing = false  # Mark animation as stopped
		blackhole.visible = false  # Hide the blackhole
		explosion.visible = false  # Hide the explosion
		center_point.visible = true  # Show the center point
		print("Animation reset.")  # Debug print to verify reset
	else:
		print("Error: AnimationPlayer node is not assigned")

func _on_animation_finished(anim_name):
	print("Animation finished: " + anim_name)
	if anim_name == "Explosion":
		blackhole.visible = true
		explosion.visible = false
		center_point.visible = false
		animation_player.play("Blackhole")
	elif anim_name == "Blackhole":
		is_animation_playing = false  # Reset animation playing state
		blackhole.visible = true  # Ensure blackhole is visible after animation ends
		center_point.visible = false  # Hide the center point
		print("Blackhole animation finished.")

And i am using an plugin Igbgui

extends Node
#Instant Games Bridge by Mewton Games, GUI Node by Repin Develop v1.11
#Добавьте данную сцену как дочернюю там где вам необходим функционал IGB.
#Отключение звука при сворачивании, показе interstitial и rewarded происходит автоматически.
#platform
export var game_ready = false #поставте галочу, чтобы отправить сигнал ready в нужной сцене
var vk_only = false #vk games, работает только на платформе vk
var vk_direct_only = false #vk direct only, работает только на мобильной платформе vk direct
var vk_play_only = false #vk play, работает только на vk play
var yandex_only = false #yandex games, работает только на yandex играх
var no_social = false #html5 платформа без интеграции с плагином
#device
var desktop = false #работает только на ПК
var mobile = false #работает только на телефонах
signal app_visible #сигнал при возвращении видимости игры после сворачивания
signal app_hidden #сигнал при сворачивании игры
#advertisement
export var show_banner = false #показать баннер
export var show_interstitial = false #поставьте галочу для показа interstitial, либо вызывайте ее при помощи AnimationPlayer
export var show_rewarded = false #поставьте галочу для показа rewarded, либо вызывайте ее при помощи AnimationPlayer
signal get_reward #используйте сигнал "get_reward" для получения награды
signal ad_open #сигнал при открытии interstitial и rewarded рекламы.
signal ad_close #сигнал при закрытии interstitial и rewarded рекламы.
#social
export var share_app = false #поставте галочу в сцене, где необходимо поделится приложением vk.
export(String) var game_link = "" #ссылка на игру, пример: https://vk.com/app123
export var join_community = false #приглашение в сообщество vk
export(String) var community_id = "" #id вашего сообщества vk, состоит только из цифр, пример: 123
export var vk_donut_check = false #включение проверки подписки на сообщество vk donut через переменную vk_donut_subscriber, так же требуется указать community_id
var vk_donut_subscriber = false #проверка подписки на ваше сообщество через vk donut, true - когда есть подписка и false при ее отсутствии.
export var invite_friends = false #пригласить друга из vk
export var create_post = false #сделать пост на стене vk
export(String) var post_message = "" #текст вашего поста
export(String) var post_attachments = "" #ссылка или номер вложения к посту, например: photo-123 or video-123 etc.
export var add_to_favorites = false #добавить в избранное vk
export var rate = false #оценить приложение в yandex
export var open_catalog = false #открыть каталог игр в yandex
export(String) var catalog_link = "" #ссылка на страницу разработчика, пример: /games/developer?name= Не работает на iOS!
#leaderboard
export var vk_direct_leaderboard = false #доступно только в vk direct, показывает только ваш результат
var vk_direct_result = 0.0 #ваш результат который отобразится в окне vk direct
export var yandex_leaderboard = false #активация доски лидеров yandex
var yandex_result = 0.0 #результат который отобразится на странице игры в yandex играх
export(String) var yandex_leaderboard_name = "" #техническое название лидерборда в который будет осуществляться запись
#storage
export(Array) var data_key #выберете String для создания названия ключа
export(Array) var data_value #выберете любое значение для вашего ключа. ВНИМАНИЕ! Размер массива "data_key", должен совпадать с размером "data_value"
export var save_data = false #сохранение значений
export var load_data = false #загрузка значений
signal data_loaded #проверка загрузки значений
export var delete_data = false #удаление значений

func _ready():
#game ready
	if game_ready:
		Bridge.platform.send_message(Bridge.PlatformMessage.GAME_READY)
#connect states
	Bridge.advertisement.connect("banner_state_changed",self,"_banner_state")
	Bridge.advertisement.connect("interstitial_state_changed",self,"_interstitial_state")
	Bridge.advertisement.connect("rewarded_state_changed",self,"_rewarded_state")
	Bridge.game.connect("visibility_state_changed",self,"_visibility_state")
#get current device
	print("current device: " + str(Bridge.device.type))
#get current platform
	print("current platform: " + str(Bridge.platform.id))
#get current language
	print("current language: " + str(Bridge.platform.language))
#get player authorized
	print("player authorized:" + str(Bridge.player.is_authorized))
#set language
	if OS.get_name() == "HTML5":
		TranslationServer.set_locale(Bridge.platform.language)
#set platform visibility
	if Bridge.platform.id == "vk":
		vk_only = true
	if Bridge.platform.id == "vk" and Bridge.device.type == "mobile":
		vk_direct_only = true
	if Bridge.platform.id == "yandex":
		yandex_only = true
	if Bridge.platform.id == "vk_play":
		vk_play_only = true
	if Bridge.platform.id == "mock":
		no_social = true
#set device visibility
	if Bridge.device.type == "desktop":
		desktop = true
	if Bridge.device.type == "mobile":
		mobile = true
#vk donut check
	if Bridge.platform.id == "vk":
		if vk_donut_check:
			JavaScript.eval("""
			let url = new URL(window.location.href)
			let accessToken = url.searchParams.get('access_token')
			bridge.platform.sdk.send('VKWebAppCallAPIMethod', {
				method: 'donut.isDon',
				params: {
					owner_id: '-"""+str(community_id)+"""',
					v: '5.131',
					access_token: accessToken 
				}})
				.then((data) => { 
					if (data.response) {
						console
						window.vk_donut_subscriber = true
					}
					else {
						window.vk_donut_subscriber = false
					}
				})
				.catch((error) => {
					console.log(error)
				})""")
			yield(get_tree().create_timer(5), "timeout")
			if JavaScript.get_interface("window").vk_donut_subscriber == true:
				vk_donut_subscriber = true
			if JavaScript.get_interface("window").vk_donut_subscriber == false:
				vk_donut_subscriber = false
			if vk_donut_subscriber:
				print("vk donut subscription: true")
			else:
				print("vk donut subscription: false")
		
func _process(_delta):
#advertisement
	if show_banner:
		$anim.play("show_banner")
	if show_interstitial:
		$anim.play("interstitial")
	if show_rewarded:
		$anim.play("rewarded")
#vk social
	if vk_only:
		if share_app:
			$anim.play("share_app")
		if join_community:
			$anim.play("join_community")
		if invite_friends:
			$anim.play("invite_friends")
		if create_post:
			$anim.play("create_post")
		if add_to_favorites:
			$anim.play("add_to_favorites")
#vk direct leaderboard
	if vk_direct_only:
		if vk_direct_leaderboard:
			$anim.play("vk_direct_leaderboard")
#yandex social
	if yandex_only:
		if rate:
			$anim.play("rate")
		if open_catalog:
			$anim.play("open_catalog")
#yandexleaderboard
		if yandex_leaderboard:
			$anim.play("yandex_leaderboard")
#storage
	if load_data:
		$anim.play("load_data")
	if save_data:
		$anim.play("save_data")
	if delete_data:
		$anim.play("delete_data")
	
func _finished(anim_name):
#advertisement
	if anim_name == "show_banner":
		Bridge.advertisement.show_banner()
		show_banner = false
	if anim_name == "interstitial":
		Bridge.advertisement.show_interstitial()
		show_interstitial = false
	if anim_name == "rewarded":
		Bridge.advertisement.show_rewarded()
		show_rewarded = false
#vk social
	if vk_only:
		if anim_name == "share_app":
			Bridge.social.share(Bridge.ShareVkOptions.new(game_link))
			share_app = false
		if anim_name == "join_community":
			Bridge.social.join_community(Bridge.JoinCommunityVkOptions.new(community_id))
			join_community = false
		if anim_name == "invite_friends":
			Bridge.social.invite_friends()
			invite_friends = false
		if anim_name == "create_post":
			Bridge.social.create_post(Bridge.CreatePostVkOptions.new(post_message,post_attachments))
			create_post = false
		if anim_name == "add_to_favorites":
			Bridge.social.add_to_favorites()
			add_to_favorites = false
#vk direct leaderboard
	if vk_direct_only:
		if anim_name == "vk_direct_leaderboard":
			Bridge.leaderboard.show_native_popup(Bridge.ShowNativePopupVkOptions.new(vk_direct_result,true))
			vk_direct_leaderboard = false
#yandex social
	if yandex_only:
		if anim_name == "rate":
			Bridge.social.rate()
			rate = false
		if anim_name == "open_catalog":
			JavaScript.eval("window.open('https://yandex."+str(Bridge.platform.tld)+str(catalog_link)+"')")
			open_catalog = false
#yandex_leaderboard
		if anim_name == "yandex_leaderboard":
			Bridge.leaderboard.set_score(Bridge.SetScoreYandexOptions.new(yandex_result,yandex_leaderboard_name))
			print("leaderboard " + str(yandex_leaderboard_name))
			yandex_leaderboard = false
#storage
	if anim_name == "load_data":
		load_data()
		load_data = false
	if anim_name == "save_data":
		save_data()
		save_data = false
	if anim_name == "delete_data":
		delete_data()
		delete_data = false
#ad state and audio mute in advertisement
func _banner_state(state:String):
	print("banner ",state)
func _interstitial_state(state:String):
	if state == "opened":
		AudioServer.set_bus_mute(0, true)
		emit_signal("ad_open")
		print("interstitial opened")
	if state == "closed":
		emit_signal("ad_close")
		AudioServer.set_bus_mute(0, false)
		print("interstitial closed")
	if state == "failed":
		emit_signal("ad_close")
		AudioServer.set_bus_mute(0, false)
		print("interstitial failed and closed")
func _rewarded_state(state:String):
	if state == "opened":
		emit_signal("ad_open")
		AudioServer.set_bus_mute(0, true)
		print("rewarded opened")
	if state == "rewarded":
		emit_signal("get_reward")
		print("get reward")
	if state == "closed":
		emit_signal("ad_close")
		AudioServer.set_bus_mute(0, false)
		print("rewarded closed")
	if state == "failed":
		emit_signal("ad_close")
		AudioServer.set_bus_mute(0, false)
		print("rewarded failed and closed")
			
#audio mute in minimizing
func _visibility_state(state:String):
	if state == "visible":
		AudioServer.set_bus_volume_db(0,0)
		emit_signal("app_visible")
		print("game visible")
	if state == "hidden":
		AudioServer.set_bus_volume_db(0,-80)
		emit_signal("app_hidden")
		print("game hidden")
#audio mute in mouse focus out
func _notification(what):
	match what:
		MainLoop.NOTIFICATION_WM_MOUSE_ENTER:
			if OS.get_name() == "HTML5":
				AudioServer.set_bus_volume_db(0,0)
			print("mouse in")
		MainLoop.NOTIFICATION_WM_MOUSE_EXIT:
			if OS.get_name() == "HTML5":
				AudioServer.set_bus_volume_db(0,-80)
			print("mouse out")
#storage func and status
func load_data():
	Bridge.storage.get(data_key,funcref(self,"_load_data_completed"))
func save_data():
	Bridge.storage.set(data_key, data_value, funcref(self,"_save_data_completed"))
func delete_data():
	Bridge.storage.delete(data_key)
	
func _load_data_completed(success ,data):
	print("data loaded: " + str(success))
	if success:
		print(data)
		data_value = data
		emit_signal("data_loaded")
	else:
		print("empty")
func _save_data_completed(success):
	print("data saved: " + str(success))
	

and there was this

Can you describe the problem? What is not working for the highscore?

  • Is the highscore not displayed?
  • Do you get a weird text instead of the actual score?
  • Is the loading of the highscore broken?

From the screenshot and code, my first suggestion is to rename the methods load_data(), save_data() and delete_data() to something else in order for the code to distinguish the variables from the methods.

1 Like

Yes, its just doesnt count always highscore:0
and after exporting my game there spawn a script with this errors

I just was talking with plugin creator and he said that its not from plugin so i dont know what this error is

OKay i remove that error but still cant create an highscore

An obvious mistake.
The path used by the function get_node() is incorrect.
Please use relative path.

where ?

get_file_path() receives a null value for the parameter key.
I would troubleshoot where you are calling the method and then go from there.
I believe you need to fix all crashing errors first before we can even think about the highscore.

Once the code is fixed and running, I would check when you are actually calling the Highscore’s _on_player_score_increased() method, which is like the central method responsible for setting the high score label. By script alone, I am unable to determine if the signal is connected properly, I assume it is.

Your code for line2d and the plugin Igbgui is irrelevant for the problem now.
Infact, I would start much smaller and use the Highscore code in a much small scene first in order to test updating the highscore label.

(As in: without all the save/load data overhead that the plugin creates)

1 Like

okay if my label is in the Game scene - control - Highscore
doesnt that mean that i need to do this ?
onready var high_score_label = get_node(“/root/Game/Control/Highscore”)
and about highscore i can test in another scene but i think thats not necessaryI have already used highscore system in 2 games with saving and there was no errors if you want i can show you.

If your game is running, you can open the remote tab and then view the SceneTree of the running game to check where the node is located.

and about highscore i can test in another scene but i think thats not necessaryI have already used highscore system in 2 games with saving and there was no errors if you want i can show you.

If that’s the case then the highscore system should work once it is able to compile? You can print out something as test inside _on_player_score_increased() just to see if it works.
If the print is never displayed, then you need to check your signal connections again.

1 Like

func _on_player_score_increased(new_score: int):
	print("New Score Received: ", new_score)
	if new_score > high_score:
		high_score = new_score
		_update_high_score_label()

— Debugging process started —
Godot Engine v3.5.3.stable.official.6c814135b - https://godotengine.org
OpenGL ES 3.0 Renderer: GeForce GTX 550 Ti/PCIe/SSE2
Async. shader compilation: OFF

current device: desktop
current platform: mock
current language: en
player authorized:False
mouse out
mouse in
mouse out
Animation finished: Explosion
— Debugging process stopped —

I see, so the method is never called, neither in code nor from anywhere else.
Can I ask you to check the other two games of yours where you have successfully used this highscore system?
I would have thought there should be something to connect the signal.

For example this:

func _ready() -> void:
    ???.player_score_increased.connect(_on_player_score_increased)

When do you receive a new player score? When the game is over? Or when you press on a button?

As of now, I believe you maybe copied the code but this somehow broke the signal connection so the highscore label doesnt know who triggers the score update.

yes of course i will check now


Game.gd(main)

extends Node2D

var score = 0
onready var rating_container = $RatingContainer
onready var high_score_label = $HighScoreLabel
onready var score_label = $Timer
onready var area = $deatharea
var is_dead = false
var leaderboard_name = "test"  # Название лидерборда

func _ready():
	var yarn_mouse = $YarnMouse
	yarn_mouse.connect("score_increment", self, "_on_score_increment")
	area.connect("death", self, "_on_death")
	update_labels()
	
	# Загрузка лидерборда при запуске игры
	load_leaderboard()
	
func _on_set_desktop():
	$LeftTouch.queue_free()
	$RightTouch.queue_free()
	
func _on_score_increment():
	if not is_dead:
		score += 1
		score_label.text = str(score)
		print("score is added")
	else:
		print("not scoring bro")

func _on_death():
	is_dead = true
	$AnimationPlayer.play("FadeOut")
	print("you died")
	HighScoreManager.save_high_score(score)
	update_labels()
	yield(get_tree().create_timer(1), "timeout")
	$YarnMouse.queue_free()

	# Сохранение очков в лидерборд после смерти игрока
	save_score_to_leaderboard(score)

func _on_Button_pressed():
	get_tree().change_scene("res://Scenes/Menu.tscn")
	if Admanager.can_show_ad:
		Bridge.advertisement.show_interstitial()

func update_labels():
	score_label.text = str(score)
	var high_score_label = $HighScoreLabel
	if Bridge.platform.language == "ru":
		high_score_label.text = "Рекорд: " + str(HighScoreManager.high_score)
	if Bridge.platform.language == "en":
		high_score_label.text = "Record: " + str(HighScoreManager.high_score)

# Функция для сохранения очков в лидерборд
func save_score_to_leaderboard(score):
	var options
	match Bridge.platform.id:
		"yandex":
			options = {
				"leaderboardName": leaderboard_name,
				"score": score
			}
	Bridge.leaderboard.set_score(options, funcref(self, "_on_set_score_completed"))

# Обработка результата сохранения очков
func _on_set_score_completed(success):
	if success:
		print("Score successfully saved to leaderboard!")
	else:
		print("Failed to save score to leaderboard.")

# Функция для загрузки записей из лидерборда
func load_leaderboard():
	var options
	match Bridge.platform.id:
		"yandex":
			options = {
				"leaderboardName": leaderboard_name,
				"includeUser": true,
				"quantityAround": 10,
				"quantityTop": 10
			}
	Bridge.leaderboard.get_entries(options, funcref(self, "_on_get_entries_completed"))

# Обработка загруженных записей
func _on_get_entries_completed(success, entries):
	if success:
		print("Leaderboard entries retrieved successfully!")
		print("Number of entries: " + str(entries.size()))

		# Пример: обновление UI контейнера с рейтингом
		for i in range(entries.size()):
			rating_container.get_child(i).text = str(entries[i].rank) + ". " + str(entries[i].name) + " - " + str(entries[i].score)
	else:
		print("Failed to retrieve leaderboard entries.")

From this code, I can infer the game progression

func _on_death():
	[...]
	HighScoreManager.save_high_score(score) # <- Saves the highscore in Global Autoload 
	update_labels() # <- Displays whatever was saved in HighScoreManager
	[...]

because everything is done in a single script file game.gd, you did not need signals. But in this case with your new game, I am not so sure.

Assuming in your new game your highscore is shown when you die, can I ask you to show me the code for it?

of course i will show you
Thats my line2d code where i put that

extends Line2D

var drawing = false
var custom_points = []
onready var score_label = get_node("/root/Game/Control/Score")  # Score label
onready var center_point = get_node("/root/Game/Control/Star")   # Center point of the circle
onready var animation_player = get_node("/root/Game/Control/AnimationPlayer")  # Animation player
onready var blackhole = get_node("/root/Game/Control/Blackhole") 
onready var explosion = get_node("/root/Game/Control/Explosion") 

var min_circle_points = 10  # Minimum number of points to consider a circle
var line_thickness = 10  # Initial line thickness
var start_angle = 0.0  # Start angle for circle drawing
var angle_covered = 0.0  # Total angle covered during drawing
var last_angle = 0.0  # Last angle position
var total_sign = 0.0  # Total movement direction
var error_change_direction = false  # Error check state
var is_animation_playing = false  # Track if animation is currently playing

# Path to the Highscore node
onready var highscore_node = get_node("/root/Game/Control/Highscore")  # Replace with correct path

func _ready():
	self.width = line_thickness  # Set the initial line thickness
	self.default_color = Color(1, 1, 1)  # Set the line color to white
	if animation_player:
		animation_player.connect("animation_finished", self, "_on_animation_finished")
	else:
		print("Error: AnimationPlayer node is not assigned")
	
	# Initialize the score label
	if score_label:
		score_label.text = "Score: 0"
	else:
		print("Error: Score label node is not assigned")

func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and event.pressed:
			drawing = true
			error_change_direction = false  # Reset error check
			custom_points = []  # Clear previous points
			start_angle = get_angle()  # Save the start angle
			angle_covered = 0.0  # Reset angle coverage
			total_sign = 0.0  # Reset sign count
			last_angle = start_angle  # Initialize last angle
			if is_animation_playing:
				_reset_animation()  # Reset the animation if it is playing
			if score_label:
				score_label.text = "Score: 0"  # Reset the score label
		elif event.button_index == BUTTON_LEFT and not event.pressed:
			drawing = false
			_on_draw_finished()

	if event is InputEventMouseMotion and drawing:
		custom_points.append(event.position)
		update()
		_on_draw_in_progress()

func _draw():
	if custom_points.size() > 1:
		draw_polyline(custom_points, self.default_color, line_thickness)  # Always draw the line white

func _on_draw_in_progress():
	var perfection_score = calculate_perfection()
	if score_label:
		score_label.text = "%0.1f" % perfection_score  # Update score label with the current score

	var current_angle = get_angle()
	var angle_diff1 = fmod(current_angle + 360.0, 360.0) - fmod(last_angle + 360.0, 360.0)
	var angle_diff2 = fmod(current_angle + 540.0, 360.0) - fmod(last_angle + 540.0, 360.0)
	var sign_diff = 0

	if abs(angle_diff1) <= abs(angle_diff2):
		sign_diff = sign(angle_diff1)
	else:
		sign_diff = sign(angle_diff2)

	total_sign += sign_diff

	if abs(total_sign) < custom_points.size() * 0.75 and custom_points.size() > 3:
		error_change_direction = true
		drawing = false
		_on_draw_finished()

	var angle_diff = min(abs(angle_diff1), abs(angle_diff2))
	angle_covered += sign_diff * angle_diff
	last_angle = current_angle

	if abs(angle_covered) >= 360.0:
		drawing = false
		_on_draw_finished()

func _on_draw_finished():
	if error_change_direction or abs(angle_covered) < 340.0:
		if score_label:
			score_label.text = "It's not a circle"
		custom_points = []
		return

	var perfection_score = calculate_perfection()

	if perfection_score >= 50:
		_play_explosion_animation()  # Play explosion animation when score is 50 or more
		if explosion:
			explosion.visible = true

	if is_near_complete_circle():
		print("Completed a circle!")
		custom_points = []
		# Call the high score update method
		if highscore_node:
			highscore_node._on_player_score_increased(perfection_score)  # Update high score

func is_near_complete_circle():
	if custom_points.size() < min_circle_points:
		return false

	var center = Vector2()
	for point in custom_points:
		center += point
	center /= custom_points.size()

	var total_distance = 0.0
	for point in custom_points:
		total_distance += center.distance_to(point)
	var average_radius = total_distance / custom_points.size()

	var max_deviation = 0.0
	for point in custom_points:
		var distance = center.distance_to(point)
		max_deviation = max(max_deviation, abs(distance - average_radius))

	return max_deviation < 15

func calculate_perfection():
	if custom_points.size() < 3:
		return 0

	var center = Vector2()
	for point in custom_points:
		center += point
	center /= custom_points.size()

	var total_distance = 0.0
	for point in custom_points:
		total_distance += center.distance_to(point)
	var average_distance = total_distance / custom_points.size()

	var deviation = 0.0
	for point in custom_points:
		deviation += abs(center.distance_to(point) - average_distance)
	var average_deviation = deviation / custom_points.size()

	return max(0, min(100, 100 - average_deviation))

func get_angle():
	if not center_point:
		print("Error: center_point is null")
		return 0

	var center_position = center_point.global_position
	return center_position.angle_to_point(get_global_mouse_position()) * 180.0 / PI

func _play_explosion_animation():
	if animation_player:
		animation_player.play("Explosion")
		is_animation_playing = true  # Mark animation as playing
	else:
		print("Error: AnimationPlayer node is not assigned")

func _reset_animation():
	if animation_player:
		center_point.visible = true  # Ensure the center point is visible at the start of the function
		animation_player.stop()  # Stop the current animation
		is_animation_playing = false  # Mark animation as stopped
		if blackhole:
			blackhole.visible = false  # Hide the blackhole
		if explosion:
			explosion.visible = false  # Hide the explosion
		print("Animation reset.")  # Debug print to verify reset
	else:
		print("Error: AnimationPlayer node is not assigned")

func _on_animation_finished(anim_name):
	print("Animation finished: " + anim_name)
	center_point.visible = true
	if anim_name == "Explosion":
		if blackhole:
			blackhole.visible = true
		if explosion:
			explosion.visible = false
		if center_point:
			center_point.visible = false
		if animation_player:
			animation_player.play("Blackhole")
	elif anim_name == "Blackhole":
		is_animation_playing = false  # Reset animation playing state
		if blackhole:
			blackhole.visible = true  # Ensure blackhole is visible after animation ends
		if center_point:
			center_point.visible = false  # Hide the center point
		print("Blackhole animation finished.")

or you mean in my past game ?

No this is perfect

The crux of the problem is this

	if is_near_complete_circle():
		print("Completed a circle!")
		custom_points = []
		# Call the high score update method
		if highscore_node:
			highscore_node._on_player_score_increased(perfection_score)  # Update high score

This and your screenshot gave me the hints I needed.
The script that you described as Highscore, is not actually the script that is attached to the Highscore node, but it’s actually game.gd

Can I ask you to change
onready var highscore_node = get_node("/root/Game/Control/Highscore")
into
onready var highscore_node = get_node("/root/Game")

1 Like

okay but now this


i changed doesnt work highscore_node.text = "High Score: " + str(high_score)

Sorry, there was a misunderstanding.
Let’s do it like this:

  • Go to Line2D.gd
    • change onready var for highscore to get_node("/root/Game")
  • Go to your game.gd
    • leave your highscore_node to get_node("/root/Game/Control/Highscore")

Better yet, let’s make it more readable:

  • go to your game.tscn
  • rightclick on your Highscore Label node in your Scene Tree
  • Access as Unique Name
  • Drag and Drop the node into your game.gd script
    • You will get %Highscore

Exchange

func _update_high_score_label():
	# Update the label text
	high_score_label.text = "High Score: %d" % high_score

to

func _update_high_score_label():
	# Update the label text
	%Highscore.text = "High Score: %d" % high_score

If you do it like this, you can then remove the onready var for high_score_label

okay thats worked and one more question, i need to call function there yes ?

func _on_draw_finished():
	if error_change_direction or abs(angle_covered) < 340.0:
		if score_label:
			score_label.text = "It's not a circle"
		custom_points = []
		return

	var perfection_score = calculate_perfection()

	if perfection_score >= 50:
		_play_explosion_animation()  # Play explosion animation when score is 50 or more
		if explosion:
			explosion.visible = true

	if is_near_complete_circle():
		print("Completed a circle!")
		custom_points = []
		# Call the high score update method

I mean this function func _on_player_score_increased(new_score: int): to wotk or no?