How to store data as a database in cocos2dx (c++) ios game - cocos2d-x

I am totally new to cocos2d-x ios game development and really learning a lot from stackoverflow.Just want to thank all the software coders.Now my question is I am making a game with levels and high score.But still couldn't find a way to store the high score and the levels cleared.When the game restarts all the values are set to initial values as there is no database to fetch.I have heard about userdefault in cocos2d-x but really couldn't find a way to execute. Can anyone help me with a sample. I will be thankful to you

CCUserDefault acts as a key value pair and stores a value corresponding to the keys.Suppose you want to store a high score of your game so that when the user restarts the game after exiting,the changes should persist
For this,in your .cpp file take a const key value at the top after header inclusion
const char *HIGH_SCORE="key1";
key1 is a key and this key must be different for every const char * which you declare
Delete the lines in init function after these lines upto return true statement.
if(!CCLayer::init())
{
return false;
}
Don’t delete return true.Then in your init function write the following code
CCUserDefault *def=CCUserDefault::sharedUserDefault();
def->setIntegerForKey(HIGH_SCORE, 2000);
def->flush();
Here def is a pointer to CCUserDefault and it will help to access all the methods in that class.
SetIntegerForKey is the method which sets the corresponding integer value to the constant char *.
There are many more functions to store string, float, bool and double values.
def->flush() is a function which flushes the contents to the xml file. It basically saves the data to the xml file
To retrieve values from the key,suppose we want to retrieve the high score and display on a label
int high_score=def->getIntegerForKey(HIGH_SCORE);
Here we are converting the integer into a string so that we can display on a label
char s[4];
sprintf(s,"%d", high);
Adding the score to a label
CCLabelTTF *high_label=CCLabelTTF::create(s, "Arial.fnt", 20);
high_label->setPosition(ccp(200,200));
this->addChild(high_label);
Now run your project and you will see 2000 on the screen
Now stop the run and comment the following lines
//def->setIntegerForKey(HIGH_SCORE, 2000);
//def->flush();
Again re run the project and still the value is 2000 on the screen.It means that now HIGH_SCORE is stored in the xml file and the value is retrieved from it.Therefore the changes persist even after application is closed

If you want to store basic information like High Score, Current Level etc then you can use CCUserDefault and if you want to store complex data then either you can use SQLite or CCDictionary
Here is pseudo code to store and retrieve High Score in Cocos2dx-3.0:
const char* KEY_HIGH_SCORE = "high_score";
// Store High Score
UserDefault::getInstance()->setIntegerForKey(KEY_HIGH_SCORE, 100);
// Retrieve High Score.
int high_score = UserDefault::getInstance()->getIntegerForKey(KEY_HIGH_SCORE);

Related

How do I extract a timestamp from the heap dump

Unfortunately, I forgot to record the time that I took the heap dump. I hope that somewhere in the heap, the standard library caches something like System.currentTimeMillis(). Unfortunately, I do not have any business objects that cache it.
One difficult option I have it to browse all the threads, and see if their local variables stored a timestamp somewhere. However, this is not technique I can apply to all heap dumps.
I looked at java.lang.System in openJDK and it doesn't look like we cache a value. We go to native code to get the current time, but we don't store the result from native code anywhere. https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/4d891c8db5c1/src/share/classes/java/lang/System.java
The heap dump file contains a timestamp right in its header. But there is a zero-terminated string at the beginning, which would make the exact position of the timestamp dynamic, if the string wouldn’t be always the same.
So for a short, ad-hoc lookup in your actual files, you might simply assume the usual position and extract the timestamp as
try(RandomAccessFile raf = new RandomAccessFile(hprofFileLocation, "r")) {
raf.seek(23);
System.out.println(hprofFileLocation+" created "+Instant.ofEpochMilli(raf.readLong()));
}
whereas a clean solution would read the zero terminated string, skip the subsequent int value and read the timestamp from the resulting position, e.g.
try(FileChannel fch = FileChannel.open(
Paths.get(hprofFileLocation), StandardOpenOption.READ)) {
ByteBuffer bb = fch.map(
FileChannel.MapMode.READ_ONLY, 0, Math.min(Integer.MAX_VALUE, fch.size()));
do {} while(bb.get() != 0); // zero terminate string, usually "JAVA PROFILE 1.0.[12]"
int pointerSize = bb.getInt();
long timeStamp = bb.getLong();
System.out.println(hprofFileLocation+" created "+Instant.ofEpochMilli(timeStamp));
}

How do I keep a variable consistant even after seperate play sessions?

I have a variable area which stores a number.
When the app is restarted, it is reset back to it's original value. How can I keep area persistent after being closed?
I'm using Flash CS6 for Android
You'll have to save the variable. There's multiple ways to do this but using a SharedObject is the easiest IMO.
First thing is you don't actually create a new instance of the SharedObject class, you instead call the static function getLocal and this sets your variable. So somewhere near the start of your program you'll want something like this:
var gameSave:SharedObject = SharedObject.getLocal("gameSave");
This either creates a new locally persistent shared object if one does not exist or it grabs the one with the same initialized name ("gameSave") on your computer. This way you can access the saved variables across multiple playthroughs.
Now to save a variable you simply use the dataObject on the shared object and write values to it, then you call the function flush when you're done writing values to immediately save the shared object to your computer.
So saving your area value would look something like this:
gameSave.data.area = Main.area;
gameSave.flush();
After that you'll want to set the area value to whatever the saved value is when your game launches:
if (gameSave.data.area !== undefined) Main.area = gameSave.data.area;
We check if the value is undefined because it might not exist yet if you're playing the game for the first time and the area hasn't been saved yet.
Last thing in case you want to expand the scope of this and save more values: you can only write specific values to the shared object. The way I understand it is you can only write certain class types and primitives. If you try to write anything that's not a primitive or the exception classes, it'll automatically convert that item to an Object and it more or less becomes useless. The classes that it can accept that you'll probably use the most are: int, uint, Number, String, Boolean, Object, and Array. It has a few others like ByteArray and XML, but you'll either not use those at all or not use them very frequently. If you want to save any other class type you'll have to add that functionality yourself.

what is the standard procedure for Generating keys for each document in java..?

I want to insert documents into Couchbase as a bulk in Java. So what is the standard procedure for Generating keys for each document in java..?
You could use a Couchbase "counter" document as a form of sequence. Using the reactive approach with the Java SDK, this would go something like this, assuming your batch is a List<JsonObject> with each content to save to Couchbase:
//start with a sequence of contents to save
Observable.from(listOfDocumentContent)
//for each content, asynchronously generate something...
.flatMap(content -> bucket.async() //assuming bucket is a `Bucket`
//atomically generate an increasing value, starting from 0
.counter("DOCUMENT_KEY_GENERATOR", 1, 0) //use a more relevant document key
//this gives a `JsonLongDocument`, so extract the number and turn that + the original content into a `JsonDocument` to be saved
.map(cDoc -> JsonDocument.create(KEY_PREFIX + cDoc.content(), content))
)
//next up, asynchronously saving each document we generated in the previous step... You could also use insert since you don't expect the keys to already exist in Couchbase
.flatMap(docToSave -> bucket.async().upsert(docToSave))
//this will perform the above asynchronously but wait for the last doc in the batch to finish saving:
.toBlocking().last();
Notice we use a KEY_PREFIX when generating the document to be saved, so that there is less risk of collision (otherwise, other documents in the bucket could be named "1" if you do that for multiple types of documents inside the same bucket).
Also tune the saving method used to your needs (here upsert vs create vs update, TTL, durability requirements, etc...)

Append string to a Flash AS3 shared object: For science

So I have a little flash app I made for an experiment where users interact with the app in a lab, and the lab logs the interactions.
The app currently traces a timestamp and a string when the user interacts, it's a useful little data log in the console:
trace(Object(root).my_date + ": User selected the cupcake.");
But I need to move away from using traces that show up in the debug console, because it won't work outside of the developer environment of Flash CS6.
I want to make a log, instead, in a SO ("Shared Object", the little locally saved Flash cookies.) Ya' know, one of these deals:
submit.addEventListener("mouseDown", sendData)
function sendData(evt:Event){
{
so = SharedObject.getLocal("experimentalflashcookieWOWCOOL")
so.data.Title = Title.text
so.data.Comments = Comments.text
so.data.Image = Image.text
so.flush()
}
I don't want to create any kind of architecture or server interaction, just append my timestamps and strings to an SO. Screw complexity! I intend to use all 100kb of the SO allocation with pride!
But I have absolutely no clue how to append data to the shared object. (Cough)
Any ideas how I could create a log file out of a shared object? I'll be logging about 200 lines per so it'd be awkward to generate new variable names for each line then save the variable after 4 hours of use. Appending to a single variable would be awesome.
You could just replace your so.data.Title line with this:
so.data.Title = (so.data.Title is String) ? so.data.Title + Title.text : Title.text; //check whether so.data.Title is a String, if it is append to it, if not, overwrite it/set it
Please consider not using capitalized first letter for instance names (as in Title). In Actionscript (and most C based languages) instance names / variables are usually written with lowercase first letter.

Is LINQ lazy-evaluated?

Greetings, I have the following question. I did not find the exact answer for it, and it's really interesting to me. Suppose I have the following code that retrieves the records from database (in order to export it to XML file, for example).
var result = from emps in dc.Employees
where emps.age > 21
select emps;
foreach (var emp in result) {
// Append this record in suitable format to the end of XML file
}
Suppose there is a million of records that satisfy the where condition in the code. What will happen? All this data will be retrieved from SQL Server immediately to the runtime memory when it reaches the foreach construct, or it will be retrieved then necessary, the first record, second. In other words, does LINQ really handle the situation with iterating through large collections (see my post here for details)?
If not, how to overcome the memory issues in that case? If I really need to traverse the large collection, what should I do? Calculate the actual amount of elements in collection with help of Count function, and after that read the data from the database by small portions. Is there an easy way to implement paging with LINQ framework?
All the data will be retrieved from SQL Server, at one time, and put into memory. The only way around this that I can think of is to process data in smaller chunks (like page using Skip() and Take()). But, of course, this requires more hits to SQL Server.
Here is a Linq paging extension method I wrote to do this:
public static IEnumerable<TSource> Page<TSource>(this IEnumerable<TSource> source, int pageNumber, int pageSize)
{
return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
}
Yes, LINQ uses lazy evaluation. The database would be queried when the foreach starts to execute, but it would fetch all the data in one go (it would be much less efficient to do millions of queries for just one result at a time).
If you're worried about bringing in too many results in one go, you could use Skip and Top to only get a limited number of results at a time (thus paginating your result).
It'll be retrieved when you invoke ToList or similar methods. LINQ has deferred execution:
http://weblogs.asp.net/psteele/archive/2008/04/18/linq-deferred-execution.aspx
The way - even having deferred execution and loading the entire collection from a data source in the case of an OR/M or any other LINQ provider - will be determined by the implementer of the LINQ object source.
That's, for example, some OR/M may provide lazy-loading, and that means your "entire list of customers" would be something like a cursor, and accessing one of items (an employee), and also one property, will load the employee itself or the accessed property only.
But, anyway, these are the basics.
EDIT: Now I see it's a LINQ-to-SQL thing... Or I don't know if question's author misunderstood LINQ and he doesn't know LINQ isn't LINQ-to-SQL, but it's more a pattern and a language feature.
OK, now thanks to this answer I have an idea - how about mixing the function of taking a page with yield return possibilities? Here is the sample of code:
// This is the original function that takes the page
public static IEnumerable<TSource> Page<TSource>(this IEnumerable<TSource> source, int pageNumber, int pageSize) {
return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
}
// And here is the function with yield implementation
public static IEnumerable<TSource> Lazy<TSource>(this IEnumerable<TSource> source, int pageSize) {
int pageNumber = 1;
int count = 0;
do {
IEnumerable<TSource> coll = Page(source, pageNumber, pageSize);
count = coll.Count();
pageNumber++;
yield return coll;
} while (count > 0);
}
// And here goes our code for traversing collection with paging and foreach
var result = from emps in dc.Employees
where emps.age > 21
select emps;
// Let's use the 1000 page size
foreach (var emp in Lazy(result, 1000)) {
// Append this record in suitable format to the end of XML file
}
I think this way we can overcome the memory issue, yet leaving the syntaxis of foreach not so complicated.