I am programming an android game with Godot 3.2.2. Of course I want to save the game data, therefore I created a new scene called SaveGame.tscn with SaveGame.gd. I exported the project to my windows pc and everything worked fine, all datas were saved. After that I also exported it to my android phone, but this time no data was saved. Instead it showed me that it could not find the save path. Maybe anybody of you can help me with this problem so that data is also saved on android.
SaveGame.gd:
extends Control
const FILE_NAME = "user://save_game_data_one.json"
var save_game_data
func _ready() -> void:
Signals.connect("load_data", self, "load")
Signals.connect("game_quit", self, "save")
save_game_data = {
"highscore": Globals.highscore,
"coins": Globals.coins,
"music_volume": Globals.music_volume,
"sound_volume": Globals.sound_volume,
"button_gameplay": Globals.button_gameplay,
"button_gameplay_side": Globals.button_gameplay_side,
}
func save():
update_data()
var file = File.new()
file.open(FILE_NAME, File.WRITE)
file.store_string(to_json(save_game_data))
file.close()
func load():
var file = File.new()
if file.file_exists(FILE_NAME):
file.open(FILE_NAME, File.READ)
var data = parse_json(file.get_as_text())
file.close()
if typeof(data) == TYPE_DICTIONARY:
save_game_data = data
else:
printerr("Corrupted data")
else:
self.show() <---- Here it shows me the hidden scene (white rectangle), this means it could not find FILE_NAME
export_data()
func export_data():
Globals.highscore = save_game_data["highscore"]
Globals.coins = save_game_data["coins"]
Globals.music_volume = save_game_data["music_volume"]
Globals.sound_volume = save_game_data["sound_volume"]
Globals.button_gameplay = save_game_data["button_gameplay"]
Globals.button_gameplay_side = save_game_data["button_gameplay_side"]
func update_data():
if Globals.score_round >= Globals.highscore:
save_game_data["highscore"] = Globals.score_round
save_game_data["coins"] += Globals.coins_round
I also would like to know the answer. I am trying to figure a way to have "persistent time" in my android game where "time passes" in game even when closed. Best solution I figure so far is getting the unix time on the games first start and check against it when reopening the app. My problem is finding a way to save that original unix time to call upon for checks.
Related
I am testing how to store game data using Godot 3.2.2 (I also tested Godot 3.2.3-rc4). When I exported the project (basicly you press a button and 1 is added to the score, which is displayed by a label) on Windows everything worked fine, the score was saved. But when I exported it to my Android phone the data was not saved. In the export setting I have enabled all permissions and in the settings of my phone I enabled the storage permission to my app. Maybe anybody of you can explain this to me and tell me how to solve this problem, so that data is also stored on android.
Code:
extends Node2D
var score = 0
var path = "user://save_file.json"
var save_game_data
func _ready() -> void:
load_data()
set_label_text()
func _on_Button_pressed() -> void:
score += 1
set_label_text()
func set_label_text():
$Label.text = str(score)
func _notification(what: int) -> void:
if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
save_game_data = {
"score": score
}
save_data()
func save_data():
var save_game = File.new()
save_game.open(path, File.WRITE)
save_game.store_line(to_json(save_game_data))
save_game.close()
func load_data():
var save_game = File.new()
if not save_game.file_exists(path):
print("No save file found")
save_data()
return
save_game.open(path, File.READ)
save_game_data = parse_json(save_game.get_line())
score = save_game_data["score"]
print("Saved game loaded", save_game_data)
According to the docs on NOTIFICATION_WM_QUIT_REQUEST:
Implemented on desktop platforms.
NOTIFICATION_WM_QUIT_REQUEST is mainly so you can implement an "Are you sure you want to quit?" dialog, or similar. Mobile platforms generally don't have this option--when you press the home button, the window closes whether it wants to or not.
You could solve this by autosaving whenever the score changes (or at the end of a round, etc).
I am trying to watch the folder of my "Camera" on my phone. This is an android phone and connected to my PC with WebDAV server which allows to map the phone as a driver; it works fine. (The mounted folder is the "Camera" in DCIM.) When I take a picture it should trigger a sub in my program. Half year ago it was working fine, now I've continued to develop my program and it's not working. (I've just reinstalled my PC, I guess this is the only thing I've changed.)
I read about a lot of trouble with filesystemwatcher over network drives.
I've already tried it with one another phone and PC too, but I had no luck.
It's working when I'm trying it with path "C:\"
The program can see the mapped drive/ folder, it doesn't stop at the checking code.
Also tried with copy and paste files to the given path instead of taking pictures...
Is there anything should I add or modify?
Here is my example code to illustrate...:
Imports System.IO
Public Class Form1
Public watchfolder As FileSystemWatcher
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim path As String
path = "Z:\"
watchfolder = New System.IO.FileSystemWatcher()
watchfolder.Path = path
If (Not System.IO.Directory.Exists(path)) Then MsgBox("Wrong path.")
watchfolder.NotifyFilter = IO.NotifyFilters.DirectoryName
watchfolder.NotifyFilter = watchfolder.NotifyFilter Or IO.NotifyFilters.FileName
watchfolder.NotifyFilter = watchfolder.NotifyFilter Or IO.NotifyFilters.Attributes
AddHandler watchfolder.Changed, AddressOf logchange
AddHandler watchfolder.Created, AddressOf logchange
AddHandler watchfolder.Deleted, AddressOf logchange
AddHandler watchfolder.Error, AddressOf erroreventhandler 'I'm trying to read the error with this...
watchfolder.EnableRaisingEvents = True
End Sub
Private Sub logchange(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)
MsgBox("This is the place where I'll call one sub in case of modification.")
End Sub
Sub erroreventhandler(sender As Object, e As ErrorEventArgs)
'this is to stop the program in case of error...
''it stops when I run the program on a mapped drive. (not on "C:\")
'''I could provide the error texts, I don't really familiar with them...
Stop
End Sub
End Class
For some reason, when I restart my PhoneGap app - it looses the localStorage vales that were stored before! I'm saving them in the normal way:
localStorage.setItem("foo","value");
This stores it just fine. However, when you restart the app (or leave the device off for a random amount of time), it seems to randomly loose the data. I've found a heck of a lot of posts about this - but no definative answer on how to get it to be persistent in a PhoneGap Build WebView app,
Any suggestions are much welcomed!
This seems to be quite a common problem with WebView apps:
Android 2.3.6 + Phonegap + localStorage
Android - Making Webview DomStorage persistant after app closed
I can't find a solution that works with PhoneGap Build apps though
An actual example I'm using, is:
var current_id = parseInt(currentId) + 1;
localStorage.setItem("entry_"+current_id,save_string);
localStorage.setItem("entryId",current_id);
..and then to extract it (not that this is important, as the problem is with the data going missing, and not with accessing it)
for (var i = 0; i < localStorage.length; i++){
if (localStorage.key(i).match("entry_")) {
outputString += "\n" + localStorage.getItem(localStorage.key(i));
}
}
I'm wondering if maybe upgrading from PhoneGap Build cli-5.2.0 to cli-6.0.0 may help. I will do this, and give it a whirl.
I guess another option, would be to use a SQL database to locally store the device (its just a bit trickier to setup, and means re-writing my code)
UPDATE: Not the ideal solution - but I have now moved the app over to use WebSQL for the app. It was a bit tricky to get the hang of (never used it before) - but seems to do the job, and shouldn't loose the data :)
EDIT
i tried it like this and it worked:
var current_id = parseInt(currentId) + 1;
localStorage.setItem("entry_"+current_id,save_string);
localStorage.setItem("entryId",current_id);
/*
//this is for checking, what is stored in localStorage
console.log("length: " + localStorage.length);
for(var i = 0; i < localStorage.length; i++) {
console.log(localStorage.key(i));
}
*/
var myEntryIdFromStorage = localStorage.getItem("entryId");
var myItem = localStorage.getItem("entry_" + myEntryIdFromStorage);
Old answer for clarification
How do you get your localstorage?
normally you should store items like you did:
var permanentStorage = window.localstorage;
permanentStorage.setItem("foo", "bar");
and get them back by initializing the permanentStorage the same way and:
//assuming you have permanentStorage in the same script file
//or else you have to initialize it again:
//var permanentStorage = window.localstorage;
var myItem = permanentStorage.getItem("foo");
console.log("myItem: " + myItem);
The method store item uses two parameters: the identifier and the data itself. Please check, that the identifier with which you store your data is the same as the one, with which you get it back.
Do you get any errors? Is the return (stored in my example in myItem) null or undefined or just an empty string? Does this fail in the browser or on the device?
You could clarify your question by providing more code or error messages!
I want to save some user credentials in my qt application that runs on Android.
I use QSettings for this like so:
QString appPath = QCoreApplication::applicationDirPath()+QLatin1Char('/');
set = new QSettings(appPath+"test",
QSettings::NativeFormat);
set->setValue ( "user/username", "NameOfTheUser" );
set->setValue ( "user/password", "UserPassword" );
set->sync();
I restart the app and inside an initialize() method I have:
QString username(set->value("user/username",
( QVariant ) tr ( "defaultUser" ) ).toString());
QString password(set->value("user/password",
( QVariant ) tr ( "defaultPass" ) ).toString());
The username and password vars are not read from the QSettings.
The same code is working on Windows.
Thank you
I also ran into similar problem and found out that 2 things should be done:
path to settings file should be specified
QSettings::sync() should be explicitly called after every settings change.
So on Windows I had this working:
QSettings settings("settings.ini", QSettings::IniFormat);
settings.setValue(GRID_ENABLED, enabled);
On Android I have to use the following code:
QSettings settings("/sdcard/settings.ini", QSettings::NativeFormat); //can be IniFormat, no difference
settings.setValue(GRID_ENABLED, enabled);
settings.sync();
Probably using "sdcard" is not good enough and you should use other directory.
You can try to specify the location of the setting file to a writable location which exists even if the application is removed :
#include <QSettings>
#include <QStandardPaths>
QString path ;
QString filename;
path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) ;
filename = “config.ini” ;
QSettings settings(path + “/”+ filename,QSettings::IniFormat) ;
Here QStandardPaths::GenericDataLocation returns a directory location where persistent data shared across applications can be stored and it is never empty.
Also you can set the application and organization name in the main of your application once :
qApp->setOrganizationName("Company");
qApp->setApplicationName("App");
As noted, a re-deploy of the application from Qt Creator wipes the settings.
This is still true in Qt Creator 3.3.2 with the following caveat. When you deploy the app on Android and look at the Application Output window, there is a tool bar with a "stop" button (red square) and a "Re-run this run configuration" button (green triangle).
The initial deploy from Qt starts the app. The QSettings object is cleared or empty. Any changes to the QSettings object will be saved in the object.
If you stop the app with the red button, then immediately restart the app with the green Re-run button, the app will restart and all changes to the QSettings object in the previous run will still be there.
I assume this emulates the start, exit, restart of the app on a device.
Hi I've found the solution, tested on 3 different Android device. You can set the following path for your settings.
mPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
QString filename = "se.ini";
mPath = mPath + "/" + filename;
By following code you save your info under above location.
void ProfileManager::saveToRegistery()
{
QSettings settings(mPath , QSettings::NativeFormat);
settings.setValue("SE/Mail" , mMail);
settings.setValue("SE/Pass" , mPass);
settings.sync();
}
If you have any trouble with saving that place, you ask user permission for accessing any file with:
bool QAndroidPermissions::requestPermissions()
{
QtAndroid::PermissionResult r =
QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE");
if(r == QtAndroid::PermissionResult::Denied) {
QtAndroid::requestPermissionsSync( QStringList() <<
"android.permission.WRITE_EXTERNAL_STORAGE" );
r =QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE");
if(r == QtAndroid::PermissionResult::Denied) {
return false;
}
}
return true;
}
Hope this helps,
I had a problem similar to the above, and it turned out that everything worked just fine. That is it did work with a simple QSettings object without any arguments.
HOWEVER, every time I re-deployed the application from Qt Creator, the settings file was destroyed, leading me to the conclusion that QSettings did not work.
The problem should, according to Bogdan himself, have been fixed in Qt Creator 3.2
The only problem with your code is that for Android you have to use QStandartPaths to get path and not the QCoreApplication::applicationDirPath().
QCoreApplication::applicationDirPath() will give you the windows application path to your Android Application, which won't work on Android.
I am working on a prototype Air for Android application that loads some remote swf files (all created and controlled by me) and I need to be able to pass a variable along to the remote SWF.
Here is a quick break down of how the process currently works:
The Android app, called Loader, is installed on the device.
Loader points to my server and finds Player.swf, which it loads into the main stage. Player.swf show a login screen.
When a user logs in correctly, Player.swf receives an XML response from an API with a list of remote SWF videos to display for the user. Player.swf loops through the XML list and plays each remote SWF, one after the other.
Now, so far, so good. The remote SWF videos load up and play perfectly. But I need to start picking up variables from Player.swf (pulled from the XML response) to use in the remote SWF (things like text strings, user ID's etc)
From all the searching I have done, I believe it is down to the Sandbox environment, as Loader is a compiled application and Player.swf + the remote SWF's are all coming off a server. However, now I am wondering, as Player.swf is the one that has the AS3 code to deal with the XML response, and that is located on the same server as the remote SWF's that are played (and therefore should be the same sandbox?)
I was able to pass a variable along using a URL parameter, but it only works locally and not when I use the Android application.
I found an old blog pot about Sandbox Bridges, but the example file download doesn't work anymore.
Can anyone point me in the right direction in using the parentSandboxBridge function/class to pass along a variable (all examples I have seen deal with passing functions and/or are coded for Flex)
I cannot post any code, as I simply have nothing to show for what I want to achieve (I'm totally stumped on this bit!)
EDIT: I managed to get parameters to pass along (even though it worked locally before, it didnt work with the Loader app > Remote Player > Remote SWF animation combo)
I had to set the application domain context inside Player.swf (seeing as it is on the same server as the remote swf animations, not sure why I needed to do this)
But oddly, I cannot use parent or root to pickup variables?
I've tested this on HTC Desire running android 2.2.2 and it works what I've put in comment thus the answer is as follows:)
your host needs to define similar:
var params:URLVariables = new URLVariables();
params["string"] = "ala ma kota";
params["number"] = 1979;
var request:URLRequest = new URLRequest();
request.data = params;
request.url = "urlVarsReader.swf";
var loader:Loader = new Loader();
loader.load(request);
addChild(loader);
then loaded content (here urlVarsReader.swf) can read them as follows:
var output:TextField = new TextField();
addChild(output);
output.border = true;
output.width = 320;
output.height = 240;
output.wordWrap = true;
output.multiline = true;
var p:Object = getParams(this.loaderInfo);
for (var name:String in p)
{
output.appendText(name + " = " + p[name] + "\n");
}
I have a wrapper method for reading params:
public function getParams(li:LoaderInfo):Object
{
try
{
var params:Object = li.parameters;
var pairs:Object = {};
var key:String;
for(key in params)
{
pairs[key] = String(params[key]);
}
}
catch(e:Error)
{
return {error:e.getStackTrace()};
}
return pairs;
}
best regards
EDIT:
This works only with local content fails with SecurytyError e.g. SecurityError: Error #2070: Security sandbox violation: caller http://example.com/urlVarsReader.swf?string=ala%20ma%20kota&number=1979 cannot access Stage owned by app:/loadwithparams.swf