HttpRequest* request = new HttpRequest();
request->setUrl("http://just-make-this-request-failed.com");
request->setRequestType(HttpRequest::Type::GET);
request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted));
This code is from the NetworkTest of cocos2d-x 3.0. I don't understand why I should pass Layer* to setResponseCallback? What if I want to send/get request/response without creating a single layer? Why shouldn't I be able to do that?
Selector in obj-c is just the name of the method so in order to call it you need a reference to the object as well. The code calls it "httpresponse_selector" and cocos2d-x is reportedly modelled after obj-c so might be it.
Related
I'm trying to implement biometric authentication on iOS from a C++ codebase. Here is one example.
In order to achieve this, I need to use the LAContext obj-c APIs. However, when I try to initialize the class from C++ I get a pointer/reference error:
// Cannot initialize a variable of type 'LAContext *__strong' with an rvalue of type 'LAContext'
LAContext* authContext = LAContext();
Is there any way to achieve this? Or is this struct available from Obj-c only?
Edit 1:
My file is in Obj-C++, so in theory I should be able to mix C++ and Obj-C code, however when I try to write a Obj-C function to alloc the LAContext object I get a missing symbols error:
-(bool)biometricsAvailable {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
return true;
}
On the compilation step this error is thrown:
Undefined symbol: _OBJC_CLASS_$_LAContext
XCode itself does not show any error while editing the file, only happens when I try to build/compile the app.
As it turns out, the problem was not with mixing C++ and Obj-C code, but rather with my library being linked via cocoapods and the LocalAuthentication framework being missing.
I needed to add:
s.frameworks = "LocalAuthentication"
to the podspec and creating a LAContext instance works just fine.
I am developing a mobile game using Cocos2D-x engine for android platform and i want to integrate GPGS on it.
I achieved to show leaderboards, but there is a little annoying problem. When leaderboard is visible, if i go background and then come back to app, the gamescene goes to black. I think opengl context being released and doesnt restore again. In my opinion running leaderboard on same activity causes this, the game engine cant understand whats happening there. Whatever, because of this I want to run leaderboard (and also all GPGS things) on a new activity using intent.
Google likes "Providing"
In the reference documents of Google Play Game Services C++ SDK, there is a few unclear/fuzzy explanation about using SetOptionalIntentHandlerForUI method.
"Provide a function that can start a provided UI intent at any point, using startActivityForResult."
What is the mean of "Providing"? What is a provided Intent? How will I use startActivityForResult method? Unfortunately, "using" and "providing methods" are not clear expressions for coding. There is no sample about
using this method in the documents of GPGS for C++. Eventually,
Google's document is so poor and
there is no useful information on the internet. If someone from Google helps me, I will be so happy.
As i understand, I wrote the code like this. But it gives error when starting.
AppActivity.java
public void runGPGSActivity(Intent i) {
startActivityForResult(i,100);
}
AndroidPlatformConfiguration.h (From C++ gpg lib)
typedef std::function<void(jobject)> IntentHandler;
AndroidPlatformConfiguration &SetOptionalIntentHandlerForUI(
IntentHandler intent_handler);
main.cpp (JNI binding, the working code, GPGS runs on same activity )
gpg::AndroidPlatformConfiguration platform_configuration;
platform_configuration.SetActivity(activity);
StateManager::InitServices( ...
main.cpp (JNI binding, GPGS must be run on new activity )
gpg::AndroidPlatformConfiguration platform_configuration;
jclass activityClass = env->FindClass("org/cocos2dx/cpp/AppActivity");
jmethodID jIntentHandlerMethodID = env->GetMethodID(activityClass,"runGPGSActivity","(Landorid/content/Intent;)V");
jobject jIntentHandler = env->NewObject(activityClass, jIntentHandlerMethodID);
gpg::AndroidPlatformConfiguration::IntentHandler mIntentHandler; /*= [](jobject mjIntentHandler){};*/
std::function<void(jobject)> intentHandler = std::bind(mIntentHandler,jIntentHandler);
platform_configuration.SetOptionalIntentHandlerForUI(intentHandler);
platform_configuration.SetActivity(activity);
StateManager::InitServices(
There is no build error, but the application crashes when launching.
03-24 14:12:24.301: A/libc(21352): Fatal signal 6 (SIGABRT) at
0x00005368 (code=-6), thread 21352 (main)
And some links about this issue:
IntentHandler reference
StartActivityForResult reference
/// Thank you in advance. ///
...Yeah I solved the problem, but didn't use IntentHandler method.
I was using this code in my app, to show weekly leaderboard data.
gameServices->Leaderboards().ShowUIBlocking(leaderboardId,gpg::LeaderboardTimeSpan::WEEKLY);
But return value is not void, it is UIStatus (whatever it is)
I've reverted back to this code, app is not going to black screen now. This method returns void, I think I have to catch some callbacks when using ShowUIBlocking method, with that UIStatus thing.
gameServices->Leaderboards().ShowUI(leaderboardId);
But now, I can't benefit from timespan feature of leaderboards.
I am going to research how it can be used. There is no problem for now. But, documentation of SetOptionalIntentHandlerForUI must be written more explicit, for programmers who want to use it.
I'm currently working on a "save" mechanism, which allows a user to save the project his working on on hard disc. The output will be a XML file containing all kinds of data.
Now our project structure is about to change and we need to write a new xml file (create a new save method).
So now here comes the challenge: When saving I want the user to be able to choose which file format he will be creating (version1 (old) or version2 (new)).
Does anyone now how to achieve that? Is there a suitable design pattern around?
Remarks:
- The data we are saving can be seen as unrelated blocks, so it would actually be easy to exchange an old block with a new one.
- The whole goal of the thing is, it should be readable again when loading an old project. (I assume this can be done by tags, and just react on tags when loading?)
This sounds like a good application for the Strategy pattern.
You would create an abstract base class FileFormat (the Strategy interface) with two virtual functions, projectToXml and xmlToProject, which are supposed to turn your internal project representation into XML or vice versa.
Then you create two implementing subclasses FileFormatNew and FileFormatLegacy (these are the concrete strategies).
Your save functions would then additionally require an instance of FileFormat, and call the corresponding method of that object to do the data conversion. Your load function could choose the strategy to use by examining the XML tree for something which tells it which version it is.
And when you ever need to support another file format, you just have to create a new class which is a subclass of FileFormat.
Addendum after the exchange in the comments
When you are going to have a lot of versions with very small differences and you still want to use the Strategy pattern, you could make the FileFormat a composite of multiple strategies: A CircleStragegy, a RectangleStrategy, a LineStrategy etc.. In that case I wouldn't use different classes for different versions of the FileFormat. I would create a static factory function for each version which returns a FileFormat with the Strategy objects used in that version.
FileFormat FileFormat::createVersion1_0() {
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_1() {
// the 1.1 version introduced the new way to save lines
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_2() {
// 1.2 uses the new format to save circles
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyNew(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_3() {
// 1.3 uses a new format to save rectangles, but we realized that
// the new way to save lines wasn't that good after all, so we
// returned to the old way.
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyNew(),
new RectangleStragegyNew()
);
}
Note: In real code you would of course use more descriptive suffixes than "Old" and "New" for your strategy class names.
So, I'm experimenting with Webkit GTK DOM functions. It's pretty straightforward, except for one thing: there's a useful part of the API called the WebKitDOMTreeWalker which, I assume, lets you walk over each node in the DOM, just like the TreeWalker object in Javascript.
Now, in Javascript a TreeWalker is created by calling:
document.createTreeWalker(root, nodesToShow, filter, entityExpandBol)
So, in WebKit GTK, there is an obvious counterpart in the API - a function called webkit_dom_document_create_tree_walker. The function signature is:
WebKitDOMTreeWalker* webkit_dom_document_create_tree_walker(WebKitDOMDocument* self, WebKitDOMNode* root, gulong what_to_show, WebKitDOMNodeFilter* filter, gboolean expand_entity_references, GError **error);
So creating a TreeWalker with WebKit GTK seems pretty straightforward - except for one big problem: the fourth argument in the webkit_dom_document_create_tree_walker expects a filter object, that is, it wants an instance of WebKitDOMNodeFilter. Well, the Javascript function also takes a filter, but you can pass null if you don't want to use a filter. With the Webkit API, passing NULL doesn't work. If you call:
WebKitDOMTreeWalker* walker = webkit_dom_document_create_tree_walker(doc, root, SHOW_ALL, NULL, false, err)
You get the error message:
** (webkit:3367): CRITICAL : WebKitDOMTreeWalker* webkit_dom_document_create_tree_walker(WebKitDOMDocument*,
WebKitDOMNode*, gulong, WebKitDOMNodeFilter*, gboolean, GError):
assertion `filter' failed
So, the WebKit API won't accept a NULL pointer for the filter argument. Evidently you need to pass an instance of a WebKitDOMNodeFilter. Okay, again - this wouldn't be a problem either, except I've searched far and wide through the WebKit API, as well as Google, and I can't find anyway to create a WebKitDOMNodeFilter object! The header file for WebKitDOMNodeFilter.h doesn't expose any constructor for WebKitDOMNodeFilter. It seems like the API doesn't ever expose anyway to actually construct a WebKitDOMNodeFilter object at all.
Yet... the API exposes many functions (like webkit_dom_document_create_tree_walker, and webkit_dom_document_create_node_iterator) which require a WebKitDOMNodeFilter. So... is the API just incomplete right now? Or, is there some way to create a Filter object which I'm just not seeing?
Can you try casting your null to the WebKitDOMNodeFilter type by calling
WEBKIT_DOM_NODE_FILTER(null)?
I have a game with a mainloop - on each loop i call for every NPC in the game ->ProcessAI() to execute any actions.
This is a server so the call to ProcessAI is not executed on every frame like on a client game! Its also singlethreaded.
Now i wanted to extend the C++ codebase with lua using luabind (maybe, even with boost overhead). So i expose some functions of my NPC class to LUA.
I wanted to create actor scripts for example - boss battles which have more sophisticated behaviour - whenever in my c++ ProcessAI function an event happens - i would delegate this to the corresponding lua script for the specific NPC.
i imagined in my boss.lua script i would have something like this
function OnEngageCombat(NPC)
NPC:say ("Some taunts...")
ScheduleEvent(CastEvilSpell,/*time*/2000,/*numExecutions*/1,)
end
function CastEvilSpell(NPC)
NPC:CastSpell("someSpell")
end
However - i have no idea how to do this - i gather ScheduleEvent should be some C++ function exported to Lua - but what would be the best approach to keep the object reference of the NPC (boss) with this and call a function in that script about 2 seconds later ?
Furthmore along with this delayed execution - i want that NPCs can interact with each other - my current idea is to have an actor behavior script for each special NPC.
Now what i imagined is to initiate a conversation between two NPCs e.g.
function DoGossip(NPC)
// check if NPC1 is close to NPC2
if NPC:DistanceToNpc("SomeGuy") < 10 then
StartConversation1()
end
function StartConversation1(NPC)
NPC:Say("Hello ...")
// wait a moment now trigger NPC2 to reply
????
end
Basically - how do i call a function from lua scriptA which exists in lua scriptB which is the behavior script for NPC2.
What would be a good design?
Thanks
If you use LuaBind, you can set a global scriptable object that refers to a wrapper class around your game engine that you expose to your script.
So, whenever you set up your lua engine, you can register a global you want all scripts to have access to, like this in your C++ code:
luabind::globals(m_pLuaState)["Game"] = m_pGameWrapperClass;
Then, in your script, you could simply refer to the Game object to get at game specific functionality, like this:
Game:ScheduleEvent(...)
Your C++ game wrapper class would just implement a ScheduleEvent function that you'd bind with LuaBind. You could add/register as many game-y specific functions as you'd need on that object.
To lead into your question 2, you could simply register a function on your Game class called FindNPC(), that takes a string argument or id or something that would look up an npc in your engine, and return a reference to it. You'd probably want to write a wrapper class around the npc object that exposes npc-y functionality just like you would do with your Game class, and FindNPC() would return userdata that represents an NPC, and exposes whatever functionality that is necessary to use it, or to make it do stuff in the Game itself.