Godot v4.5.1.stable.steam [f62fdbde1]
I have just finished the demo for my upcoming metroidvania game; Lost Facade, and everything works great in the editor and I am really happy with the finished demo.
After exporting the game however I noticed I couldn’t start the game past the title screen, which I deduced was because the save files weren’t being created through my global script functions
I also noticed sounds were not playing when I hovered over the title screen UI elements (which each contain a mouse_entered signal that calls a global function that creates an audiostream player and plays it)
I believe my global script autoload isnt running at all in the exported build and I have no idea why this would be happening. I checked the debug console and the script itself (global.gd) is loaded into the game along with the rest of the assets needed, but it is not running the script at all.
here is my global script (global.gd)
extends Node
@onready var AfterImage = preload("res://Data/Entities/Effects/Effect_AfterImage.tscn")
@onready var ACHIEVEMENTINSTANCE = preload("res://data/ui/AchievementBubble.tscn")
var savefilelocation = "user://Save.json"
#DEBUG
var lowperformancemode = false
var indebugscene = false
var InFractal = false
var debugmode = false
var squishy
var gui
var storedposition
var storedareaid
var storedsectionid
var perspectivebuffer = 3
#DEBUG
#VARIABLES THAT ARE TO BE SAVED
var StoredCameraLimits = [0,0,0,0]
var StoredCameraOffset = Vector2(0,0)
var CurrentSectionID = 0
var CurrentSection
var lastcheckpointposition
var CurrentAreaStringName: String = ""
var fractalscollected = 0
var collectedfractalindexes = [null]
var UnlockedAttacking = false
var PersistentBossVariables = [
[[]],
[],
[],
[],
[],
]
var BossesDefeated = [
""
]
var CompletedDemo: bool = false
var SilenceMusicZones: bool = false
var QueueOneTimeTriggerSave: bool = false
var QueuedOneTimeTriggers = []
#VARIABLES THAT ARE TO BE SAVED
var CurrentSubSection
var StoredSection
var CurrentSubSectionID = 0
var StoredSectionID = 0
var InSubSection = false
var DialogueActive = false
var globalpause = false
var indangerousarea = false
var DestroyingProjectiles = false
var loaded = false
var AwaitSpecificLoad = false
var TestingModeActive = false
var CanSaveThroughTestingMode: bool = false
var InPauseMenu = false
var SquishyFocus
var OneTimeTriggers = []
var BreakableWallsBroken = []
var MusicZoneEnabledStates = []
var MusicZoneNames = []
var SceneSpecificVariables = [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
]
var SceneSpecificVariableNames = [
"GeneratorsActivated"
]
var CurrentOccupiedFractal
var OldPlayerMovementState: String = ""
var CurrentBoss = []
var OnEnd = false
@onready var SceneBase = get_tree().get_current_scene()
func _ready():
print("Global.gd is running!")
# for i in controlnamelist.size():
# InputMap.action_erase_events(controlnamelist[i - 1])
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
if lowperformancemode == true:
Engine.max_fps = 30
Engine.max_physics_steps_per_frame = 30
process_mode = Node.PROCESS_MODE_ALWAYS
func _process(delta: float) -> void:
if CompletedDemo == true and OnEnd == false:
get_tree().change_scene_to_packed(load("res://EndOfDemoScreen.tscn"))
globalpause = false
OnEnd = true
if CompletedDemo == true:
if Input.is_anything_pressed():
CompletedDemo = false
Save()
BossesDefeated = [""]
if Input.is_action_just_pressed("move_jump"):
get_tree().quit()
#gyu
if gui != null and gui.lastfractalscollected != fractalscollected:
gui.lastfractalscollected = fractalscollected
#Preset Screen Movement Patterns
if loaded == false:
var dir = DirAccess.open("user://")
if dir == null:
DirAccess.make_dir_absolute(OS.get_user_data_dir())
if not FileAccess.file_exists("user://Save.save"):
Save()
print ("GameSave was Called")
else:
LoadSave()
loaded = true
if AwaitSpecificLoad == true and CurrentAreaStringName != "":
LoadSpecificSave()
if not FileAccess.file_exists(str("user://",CurrentAreaStringName,".save")) and CurrentAreaStringName != "" and CompletedDemo == false:
var AreaSpecificSave = ConfigFile.new()
AreaSpecificSave.set_value("Fractals", "collectedfractalindexes", [null])
#if not FileAccess.file_exists(str("user://",get_tree().get_current_scene().name,".save")):
AreaSpecificSave.save(str("user://",CurrentAreaStringName,".save"))
AwaitSpecificLoad = true
#if TestingModeActive == true:
#Global.UnlockedAttacking = true
#DEBUG
if DestroyingProjectiles == true:
DestroyingProjectiles = false
if Input.is_action_just_pressed("Breakpoint"):
breakpoint
if Input.is_action_just_pressed("Debug_Mode") and debugmode == false and TestingModeActive == true:
debugmode = true
var dbins = load("res://Data/ui/Menus/debugmenu.tscn").instantiate()
add_child(dbins)
if Input.is_action_just_pressed("Exit_Debug"):
debugmode = false
#if debugmode == true and Input.is_action_pressed("Flight"):
#get_tree().debug_collisions_hint = true
#get_tree().debug_navigation_hint = true
#pass
#
#else:
#get_tree().debug_collisions_hint = false
#get_tree().debug_navigation_hint = false
#DEBUG
if Input.is_action_just_pressed("Reload") and TestingModeActive == true:
ResetVariables()
get_tree().reload_current_scene()
SceneBase = get_tree().get_current_scene()
func GetImportantRefs(player,ui):
squishy = player
gui = ui
func Save():
if TestingModeActive == false or CanSaveThroughTestingMode:
if not FileAccess.file_exists("user://Save.save"):
#Create nonspecific area save variables at their default values if no save file exists
var Save = ConfigFile.new()
Save.set_value("Area Information","lastcheckpointposition", Vector2(-5555,0))
Save.set_value("Area Information", "CurrentSectionID", 0)
Save.set_value("Area Information","CurrentAreaStringName", "TheTwilightSpace_FirstExpedition")
Save.set_value("Collectibles","fractalscollected", 0)
Save.set_value("Collectibles","timelinecount", 0)
Save.set_value("Squishy","UnlockedAttacking", false)
Save.set_value("Squishy","SquishyFocus", "Basic")
Save.set_value("Squishy","BossesDefeated", [""])
Save.set_value("Squishy","CompletedDemo", false)
Save.save("user://Save.save")
print ("File should be there")
#Create nonspecific area save variables at their default values if no save file exists
#if gui != null:
#gui.CreateDebugLabel(str("The game was saved successfully and the save file looks like:", Save.encode_to_text()))
LoadSave()
else:
#Save Nonspecific Area Information
var Save = ConfigFile.new()
Save.set_value("Area Information","lastcheckpointposition", lastcheckpointposition,)
Save.set_value("Area Information", "CurrentSectionID", CurrentSectionID)
Save.set_value("Area Information","CurrentAreaStringName", CurrentAreaStringName)
Save.set_value("Collectibles","fractalscollected", fractalscollected)
Save.set_value("Squishy","UnlockedAttacking", UnlockedAttacking)
Save.set_value("Squishy","SquishyFocus", SquishyFocus)
Save.set_value("Squishy","BossesDefeated", BossesDefeated)
Save.set_value("Squishy","CompletedDemo", CompletedDemo)
Save.save("user://Save.save")
#Save Nonspecific Area Information
SaveSpecific()
#if gui != null:
#gui.CreateDebugLabel(str("The game was saved successfully and the save file looks like:", Save.encode_to_text()))
func SaveSpecific():
if not FileAccess.file_exists(str("user://",CurrentAreaStringName,".save")) and CurrentAreaStringName != "" and "_" in CurrentAreaStringName:
var AreaSpecificSave = ConfigFile.new()
AreaSpecificSave.set_value("Fractals", "collectedfractalindexes", [null])
AreaSpecificSave.set_value("Objects", "OneTimeTriggers", [])
AreaSpecificSave.set_value("Objects", "MusicZoneNames", [])
AreaSpecificSave.set_value("Objects", "MusicZoneEnabledStates", [])
AreaSpecificSave.set_value("Objects", "BreakableWallsBroken", [])
#if not FileAccess.file_exists(str("user://",get_tree().get_current_scene().name,".save")):
AreaSpecificSave.save(str("user://",CurrentAreaStringName,".save"))
AwaitSpecificLoad = true
elif FileAccess.file_exists(str("user://",CurrentAreaStringName,".save")) and "_" in CurrentAreaStringName:
var AreaSpecificSave = ConfigFile.new()
AreaSpecificSave.set_value("Fractals", "collectedfractalindexes", collectedfractalindexes)
AreaSpecificSave.set_value("Objects", "OneTimeTriggers", OneTimeTriggers)
AreaSpecificSave.set_value("Objects", "MusicZoneNames", MusicZoneNames)
AreaSpecificSave.set_value("Objects", "MusicZoneEnabledStates", MusicZoneEnabledStates)
AreaSpecificSave.set_value("Objects", "BreakableWallsBroken", BreakableWallsBroken)
#if not FileAccess.file_exists(str("user://",get_tree().get_current_scene().name,".save")):
AreaSpecificSave.save(str("user://",CurrentAreaStringName,".save"))
AwaitSpecificLoad = true
func LoadSave():
#Load nonspecific save
var config = ConfigFile.new()
var err = config.load("user://Save.save")
var sections = ["Area Information",
"Collectibles",
"Squishy"]
var index = 0
for i in config.get_sections().size():
for x in config.get_section_keys(sections[i]).size():
set(config.get_section_keys(sections[i])[x], config.get_value(sections[i],config.get_section_keys(sections[i])[x]))
print(config.get_value(sections[0],config.get_section_keys(sections[0])[2]).get_slice("/",4) )
#CurrentAreaStringName = config.get_value(sections[0],config.get_section_keys(sections[0])[2]).get_slice("/",4)
#Load nonspecific save
AwaitSpecificLoad = true
func LoadSpecificSave():
if FileAccess.file_exists(str("user://",CurrentAreaStringName,".save")):
var Sconfig = ConfigFile.new()
var Serr = Sconfig.load(str("user://",CurrentAreaStringName,".save"))
var Ssections = ["Fractals",
"Objects"
]
var Sindex = 0
for i in Sconfig.get_sections().size():
for x in Sconfig.get_section_keys(Ssections[i]).size():
set(Sconfig.get_section_keys(Ssections[i])[x], Sconfig.get_value(Ssections[i],Sconfig.get_section_keys(Ssections[i])[x]))
pass
AwaitSpecificLoad = false
func PlayUISound(soundid):
var sounds = [
"res://sounds/UI/TitleScreen_CrystalHover.ogg",
"res://sounds/Entities/Projectiles/Ally_Gun.wav",
"res://sounds/UI/TitleScreen_SquishyHover.ogg",
"res://sounds/BreakableWallBreak.ogg"
]
var soundeffect = AudioStreamPlayer.new()
for i in get_children():
if i is AudioStreamPlayer:
i.queue_free()
add_child(soundeffect)
soundeffect.stream = load(sounds[soundid])
soundeffect.play()
await get_tree().create_timer(2).timeout
if self.has_node(str(soundeffect)):
soundeffect.queue_free()
func ImpactDelay(time):
#globalpause = true
#
#await get_tree().create_timer(time).timeout
#
#globalpause = false
pass
func GrantAchievement(achievementid):
var achievementslist = ["Base", #id 0
"Test",#id 1
"TestWithAdvancements",#id 2
]
if not ResourceLoader.exists(str("user://Achievements/Achievement_",achievementslist[achievementid],".tres")) or ResourceLoader.exists(str("user://Achievements/Achievement_",achievementslist[achievementid],".tres")) and load(str("user://Achievements/Achievement_",achievementslist[achievementid],".tres")).unlocked == false:
var achievements_basedir = "res://Data/Resources/Achievements/Achievement_"
#this list of achievements is purely for keeping track of all that exist and is not used
var achievement = load(str(achievements_basedir,achievementslist[achievementid],".tres"))
print(DirAccess.dir_exists_absolute(str("user://Achievements/Achievement_",achievementslist[achievementid],".tres")), "and the path is checked was: ", str("user://Achievements/Achievement_",achievementslist[achievementid],".tres"))
if not ResourceLoader.exists(str("user://Achievements/Achievement_",achievementslist[achievementid],".tres")):
if achievement.currentrequirementsuccesscount >= achievement.UnlockRequirementSuccessCount and achievement.unlocked == false:
var ach = ACHIEVEMENTINSTANCE.instantiate()
add_child(ach)
ach.title = achievement.UnlockedName
ach.icon = achievement.UnlockedIcon
achievement.unlocked = true
ach.type = "Achievement"
var dupedach = achievement.duplicate()
if not DirAccess.dir_exists_absolute("user://Achievements"):
DirAccess.make_dir_absolute("user://Achievements")
ResourceSaver.save(dupedach,str("user://Achievements/","Achievement_",achievementslist[achievementid],".tres"))
else:
achievement.currentrequirementsuccesscount += 1
var ach = ACHIEVEMENTINSTANCE.instantiate()
add_child(ach)
ach.title = achievement.LockedName
ach.icon = achievement.LockedIcon
ach.type = "Advancement"
ach.advancementcompletionnumber = achievement.currentrequirementsuccesscount
ach.advancementtotalnumber = achievement.UnlockRequirementSuccessCount
var dupedach = achievement.duplicate()
if not DirAccess.dir_exists_absolute("user://Achievements"):
DirAccess.make_dir_absolute("user://Achievements")
ResourceSaver.save(dupedach,str("user://Achievements/","Achievement_",achievementslist[achievementid],".tres"))
Save()
else:
achievement = load(str("user://Achievements/Achievement_",achievementslist[achievementid],".tres"))
if achievement.currentrequirementsuccesscount < achievement.UnlockRequirementSuccessCount and achievement.unlocked == false:
achievement.currentrequirementsuccesscount += 1
var ach = ACHIEVEMENTINSTANCE.instantiate()
add_child(ach)
ach.title = achievement.LockedName
ach.icon = achievement.LockedIcon
ach.type = "Advancement"
ach.advancementcompletionnumber = achievement.currentrequirementsuccesscount
ach.advancementtotalnumber = achievement.UnlockRequirementSuccessCount
var dupedach = achievement.duplicate()
if not DirAccess.dir_exists_absolute("user://Achievements"):
DirAccess.make_dir_absolute("user://Achievements")
ResourceSaver.save(dupedach,str("user://Achievements/","Achievement_",achievementslist[achievementid],".tres"))
elif achievement.currentrequirementsuccesscount >= achievement.UnlockRequirementSuccessCount and achievement.unlocked == false:
var ach = ACHIEVEMENTINSTANCE.instantiate()
add_child(ach)
ach.title = achievement.UnlockedName
ach.icon = achievement.UnlockedIcon
achievement.unlocked = true
ach.type = "Achievement"
var dupedach = achievement.duplicate()
if not DirAccess.dir_exists_absolute("user://Achievements"):
DirAccess.make_dir_absolute("user://Achievements")
ResourceSaver.save(dupedach,str("user://Achievements/","Achievement_",achievementslist[achievementid],".tres"))
func ChangeSection(Section):
if CurrentSection != null and StoredSection == null or CurrentSection != null and Section != CurrentSectionID:
CurrentSection.queue_free()
if Section != 0:
CurrentSectionID = Section
CurrentBoss = []
var SectionInstance
if StoredSection == null or StoredSection != null and CurrentSectionID != StoredSectionID:
SectionInstance = load(str("res://Data/Areas/",CurrentAreaStringName,"/Section_",CurrentSectionID,".tscn")).instantiate()
get_tree().get_current_scene().add_child(SectionInstance)
SectionInstance.global_position = Vector2(0,0) - (SectionInstance.get_node("SectionOrigin").global_position)
CurrentSection = SectionInstance
if squishy == null:
var s = SceneBase.PlayerInstance.instantiate()
CurrentSection.add_child(s)
squishy = s
if gui == null:
var g = SceneBase.UIInstance.instantiate()
CurrentSection.add_child(g)
gui = g
squishy.global_position = SectionInstance.get_node(str("Spawnpoints/Spawnpoint",SceneBase.CurrentSectionSpawnpoint)).global_position
if SceneBase.respawned == true and SceneBase.animplr.current_animation != "WakeUp":
SceneBase.animplr.play("SectionTransitionOut")
elif StoredSection != null and CurrentSectionID == StoredSectionID:
StoredSection.global_position = Vector2(0,0)
StoredSection.visible = true
squishy.global_position = StoredSection.get_node(str("Spawnpoints/Spawnpoint",SceneBase.CurrentSectionSpawnpoint)).global_position
if CurrentSubSection != null:
CurrentSubSection.queue_free()
if StoredCameraLimits[0] != 0 and StoredCameraLimits[0] != null:
SceneBase.get_node("Camera3D").limit_left = StoredCameraLimits[0]
SceneBase.get_node("Camera3D").limit_right = StoredCameraLimits[1]
SceneBase.get_node("Camera3D").limit_top = StoredCameraLimits[2]
SceneBase.get_node("Camera3D").limit_bottom = StoredCameraLimits[3]
SceneBase.CamOffset = StoredCameraOffset
StoredCameraOffset = Vector2(0,0)
StoredCameraLimits[0] = 0
StoredCameraLimits[1] = 0
StoredCameraLimits[2] = 0
StoredCameraLimits[3] = 0
if CurrentSectionID != StoredSectionID:
StoredSectionID = CurrentSectionID
StoredSection = null
#Global.squishy.global_position = get_node(Spawnpoint).global_position
func ChangeToSubSection(Section):
Global.InFractal = true
CurrentBoss = []
StoredCameraLimits[0] = SceneBase.get_node("Camera3D").limit_left
StoredCameraLimits[1] = SceneBase.get_node("Camera3D").limit_right
StoredCameraLimits[2] = SceneBase.get_node("Camera3D").limit_top
StoredCameraLimits[3] = SceneBase.get_node("Camera3D").limit_bottom
StoredCameraOffset = SceneBase.CamOffset
if CurrentSection != null:
StoredSection = CurrentSection
CurrentSection.visible = false
CurrentSection.global_position = Vector2(100000,100000)
CurrentSubSectionID = Section
var SubSectionInstance = load(str("res://Data/Areas/",CurrentAreaStringName,"/Fractal_SubSections/Section_",CurrentSubSectionID,".tscn")).instantiate()
get_tree().get_current_scene().add_child(SubSectionInstance)
CurrentSubSection = SubSectionInstance
var origin = SubSectionInstance.get_node("SectionOrigin").global_position
if not origin.is_finite():
push_error("SectionOrigin position is invalid: " + str(origin))
origin = Vector2.ZERO
breakpoint
SubSectionInstance.global_position = -origin
squishy.global_position = SubSectionInstance.get_node(str("Spawnpoints/Spawnpoint0")).global_position
#Global.squishy.global_position = get_node(Spawnpoint).global_position
func CreateAfterImage(Sprite: CompressedTexture2D, Position: Vector2, Rotation: float, FadeTime: float, Parent: NodePath, OffsetVelocity: Vector2):
var a = AfterImage.instantiate()
get_tree().get_current_scene().get_node(Parent).add_child(a)
a.global_position = Position
a.TweenTime = FadeTime
a.global_rotation = Rotation
a.texture = Sprite
a.OffsetVelocity = OffsetVelocity
func CreateEffect(Parent: NodePath, Effect):
var e = Effect.instantiate()
get_tree().get_current_scene().add_child(e)
e.global_position = CurrentSection.get_node(Parent).global_position
func CreateSoundEffect(Parent:NodePath, AudioID, Directional):
var s
if Directional == false:
s = load("res://Data/Entities/Misc/OneTimeSFX.tscn").instantiate()
else:
s = load("res://Data/Entities/Misc/OneTimeDirectionalSFX.tscn").instantiate()
SceneBase.add_child(s)
s.stream = load(AudioID)
if Directional == true:
s.global_position = CurrentSection.get_node(Parent).global_position
s.play()
func DestroyAllProjectiles():
DestroyingProjectiles = true
func CloseGame():
get_tree().quit()
func UnlockFocus(Focus: String):
if UnlockedAttacking == false:
UnlockedAttacking = true
SquishyFocus = Focus
squishy.Focus = Focus
SceneBase.InFocusCutscene = true
SceneBase.BaseAnimationPlayer.play(str("UnlockFocus_",Focus))
Save()
func ResetVariables():
InFractal = false
CurrentOccupiedFractal = null
StoredCameraLimits = [0,0,0,0]
StoredCameraOffset = Vector2(0,0)
QueuedOneTimeTriggers = []
QueueOneTimeTriggerSave = false
Please let me know if there is more information I did not provide or steps I can take to debug / troubleshoot this, and thank you to anybody who can help me on this!