Create Splash screen in cocos 2d-x - cocos2d-x

Hello I am creating an game in cocos2d-x and when I am scheduling an event on splash screen for run game .It shows compilation error (in expansion of macro 'schedule_selector')
Following is my code for this
Splash.h
#ifndef SPLASH_H_
#define SPLASH_H_
#include "cocos2d.h"
class CCSplashLayer : public cocos2d::CCLayer {
private :
void runGame();
public:
static cocos2d::CCScene* createScene();
virtual bool init();
CREATE_FUNC(CCSplashLayer);
};
#endif /* SPLASH_H_ */
And SplashScene.cpp
#include "splash.h"
#include "cocos2d.h"
#include "HelloWorldScene.h"
USING_NS_CC;
bool CCSplashLayer::init() {
if (!Layer::init()) {
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
auto sprite = Sprite::create("splash.png");
sprite->setScale(Director::getInstance()->getContentScaleFactor());
sprite->setPosition(Vec2(visibleSize.width / 2,visibleSize.height/2));
this->addChild(sprite, 0);
//This line cause problem show i symbol on this line in eclipse
this->scheduleOnce(schedule_selector(CCSplashLayer::runGame),4.0f);
return true;
}
Scene* CCSplashLayer::createScene() {
auto scene = CCScene::create();
auto layer = CCSplashLayer::create();
scene->addChild(layer);
return scene;
}
void CCSplashLayer::runGame(){
auto scene = HelloWorld::createScene();
Director::getInstance()->setDepthTest(true);
TransitionScene *transition = TransitionScene::create(0.5f, scene);
Director::getInstance()->pushScene(transition);
}

schedule_selector takes function pointer which needs a float argument for time.
Change method CCSplashLayer::runGame() to CCSplashLayer::runGame(float dt) in defination and declaration.
Also you are pushing a scene over splash scene, which is not recommended way for splash scene. You must replace splash scene with new scene because we never need to display splash again in game unless there is specific design requirement of game.

Try this macro:
#define CCDL_PERFORM_SELECTOR( __OWNER__, __DELAY__, __CALLFUNC_SELECTOR__ ) \
__OWNER__->runAction( cocos2d::Sequence::create( \
cocos2d::DelayTime::create( __DELAY__ ), \
cocos2d::CallFunc::create( CC_CALLBACK_0( __CALLFUNC_SELECTOR__,__OWNER__) ), \
nullptr )); \
(source: https://github.com/duksel/Cocos2dx-DukselLib/blob/master/Cocos2dx-DukselLib/DukselMacros.h#L70-L74)
Allow to use for any CCNode (+subclass) instance.
In your case will be:
bool CCSplashLayer::init()
{
CCDL_PERFORM_SELECTOR( this, 4.f, CCSplashLayer::runGame );
}

try like this...
in init method,
this->runAction(CCSequence::create(CCDelayTime::create(4.0f),
CCCallFuncN::create(this,callfuncN_selector(CCSplashLayer::runGame)),
NULL));
and add this method.
void CCSplashLayer::runGame(){
auto scene = HelloWorld::createScene();
Director::getInstance()->setDepthTest(true);
TransitionScene *transition = TransitionScene::create(0.5f, scene);
Director::getInstance()->pushScene(transition);
}

Related

cocos2d-x 3.6 PhysicsJointFixed error

I am new to cococs2dx and I am working on a code involving PhysicsJointFixed. I am using cocos2d-x-3.6. I am unable to compile the code as I wrote below following the guidelines and the PhysicsTest.cpp.
My GameLayer.h looks like:
class GameLayer : public cocos2d::Layer
{
GameLayer();
virtual ~GameLayer();
virtual bool init();
static Scene* createScene();
void setPhyWorld(PhysicsWorld* world){m_world = world;}
CREATE_FUNC(GameLayer);
private:
PhysicsWorld* m_world;
ShapeSprite* _square; //ShapeSprite extends Sprite
ShapeSprite* _square1;
PhysicsJointFixed* joint;
...
}
The createScene method in GameLayer.cpp:
Scene* GameLayer::createScene()
{
auto scene = Scene::createWithPhysics();
auto layer = GameLayer::create();
layer->setPhyWorld(scene->getPhysicsWorld());
scene->addChild(layer);
return scene;
}
Then inside GameLayer::init()
bool GameLayer::init()
{
if ( !Layer::init() )
{
return false;
}
...
...
_square = ShapeSprite::gameSpriteWithFile("square.png");
auto squareBody = PhysicsBody::createBox(Size(200,200));
_square->setPhysicsBody(squareBody);
_square->setPosition(Vec2(_screenSize.width * 0.5f, _screenSize.height * 0.7f));
_square1 = ShapeSprite::gameSpriteWithFile("square1.png");
auto squareBody1 = PhysicsBody::createBox(Size(100,100));
_square1->setPhysicsBody(squareBody1);
_square1->setPosition(Vec2(_screenSize.width * 0.5f, _screenSize.height * 0.7f));
this->addChild(_square);
this->addChild(_square1);
joint = PhysicsJointFixed::construct(_square->getPhysicsBody(), _square1->getPhysicsBody(),Vec2(100,100));
this->getScene()->getPhysicsWorld()->addJoint(joint);
return true;
}
The code gives EXC_BAD_ACCESS error on the line
this->getScene()->getPhysicsWorld()->addJoint(joint);
because, this->getScene()->getPhysicsWorld() returns NULL.
Please advise, how can I avoid the error. Any suggestion is appreciated. Thanks in advance.
This error occurs because your custom layer is not yet added to scene during init(). One possible solution is to override onEnterTransitionDidFinish() and add the joint there. In GameLayer.h add this:
virtual void onEnterTransitionDidFinish();
And move the joint adding code to GameLayer.cpp like this:
void GameLayer::onEnterTransitionDidFinish() {
joint = PhysicsJointFixed::construct(_square->getPhysicsBody(), _square1->getPhysicsBody(),Vec2(100,100));
this->getScene()->getPhysicsWorld()->addJoint(joint);
}

AdMob Interstitial Cocos2d-x WP8

Can enyone tell me how to call AdMob Interstitial between scenes in my cocos2d-x game?
I have tried this http://robwirving.com/2014/07/21/calling-c-methods-c-winrt-components/ guide, but i don't know how to run it from cocos classes.
Is there any another ways, or some guides?
I've recently made it. You have to do few things. First of all create helper class, which will help you calling native function (I use this for all 3 platforms, but here's just windows phone):
NativeHelper.h:
#ifndef __NATIVE_HELPER_H_
#define __NATIVE_HELPER_H_
#include <string>
#include <functional>
#include "cocos2d.h"
using namespace std;
USING_NS_CC;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
namespace cocos2d
{
public delegate void CSharpShowInterstitialDelegate();
public ref class WP8NativeEventHelper sealed
{
public:
void WP8NativeEventHelper::SetCSharpShowInterstitialDelegate(CSharpShowInterstitialDelegate^ delegate){
m_CSharpShowInterstitialDelegate = delegate;
}
void CallShowInterstitial();
private:
property static CSharpShowInterstitialDelegate^ m_CSharpShowInterstitialDelegate;
};
}
#endif
class NativeHelper
{
public:
static void showInterstitial(string adSdk);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
WP8NativeEventHelper^ wp8helper;
#endif
//instance required only for setting callback
static NativeHelper* getInstance();
~NativeHelper()
{
instanceFlag = false;
}
private:
static bool instanceFlag;
static NativeHelper* instance;
NativeHelper() {};
};
#endif // __NATIVE_HELPER_H_
So. We have special C++/CX class Wp8NativeEventHelper, which can "talk" with C#. Here we store a delegate.
How it works:
C# is calling SetCSharpShowInterstitialDelegate and passes a delegate to it, which will be remembered in static property.
Then C++\CX can call it using CallShowInterstitial.
Now NativeHelperWP.cpp:
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
#ifndef __NATIVE_HELPER_WP_H_
#define __NATIVE_HELPER_WP_H_
#include "NativeHelper.h"
void WP8NativeEventHelper::CallShowInterstitial(){
if (m_CSharpShowInterstitialDelegate)
{
m_CSharpShowInterstitialDelegate->Invoke();
}
}
bool NativeHelper::instanceFlag = false;
NativeHelper* NativeHelper::instance = NULL;
NativeHelper* NativeHelper::getInstance()
{
if(!instanceFlag){
instance = new NativeHelper();
instanceFlag = true;
instance->wp8helper = ref new WP8NativeEventHelper();
}
return instance;
}
void NativeHelper::showInterstitial(){
NativeHelper::getInstance()->wp8helper->CallShowInterstitial();
}
#endif
#endif
Here is just an implementation of CallShowInterstitial. Also in NativeHelper::showInterstitial we're calling C++/CX, which later calls c#.
Now c# code (MainPage.xaml.cs):
outside namespace:
using GoogleAds;
inside class:
private InterstitialAd interstitialAd;
in constructor:
WP8NativeEventHelper helper = new WP8NativeEventHelper();
helper.SetCSharpShowInterstitialDelegate(showInterstitial);
and also create showInterstitial function:
public void showInterstitial() //we recreate interstitial each time, because otherwise it'll show only once, only new requests won't work
{
interstitialAd = new InterstitialAd("MY_AD_UNIT_ID");
AdRequest adRequest = new AdRequest();
#if DEBUG
// Enable test ads.
adRequest.ForceTesting = true;
#endif
interstitialAd.ReceivedAd += OnAdReceived;
interstitialAd.LoadAd(adRequest);
}
and finally OnAdReceived:
private void OnAdReceived(object sender, AdEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Ad received successfully");
interstitialAd.ShowAd();
}
Follow this guide to setup admob: https://developers.google.com/mobile-ads-sdk/docs/admob/wp/quick-start
Now let's use this.
In HelloWorldScene.h add:
#include "NativeHelper.h"
In HelloWorldScene.cpp:
NativeHelper::showInterstitial();
The same way you can show/hide/change position of admob banner for example (however it's buggy so I'm using ad mediation).

cocos2d-x 3.1 EXC_BAD_ACCESS on Touch event + function

I'm cocos2d-x beginner and having trouble with TouchBegan event + function.
I always get EXC_BAD_ACCESS in the [label->setString("Foo Bar");] point when I run this simple code with xCode(5.1.1 + iPhone sim 7.1).
I tried a few ways to solve, but I'm completely stuck up in this problem for 2 or 3 days.
Does anyone have any idea for the wrong point?
HelloWorld.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::LayerGradient
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
cocos2d::Label* label;
CREATE_FUNC(HelloWorld);
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorld.cpp
#include "HelloWorldScene.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
auto scene = Scene::create();
auto layer = HelloWorld::create();
scene->addChild(layer);
return scene;
}
bool HelloWorld::init()
{
if(!LayerGradient::initWithColor(Color4B(0, 0, 0, 255), Color4B(50, 50, 50, 255))){
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
auto label = Label::create("Hello World", "Arial", 112);
label->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - label->getContentSize().height));
this->addChild(label, 1);
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
this->getEventDispatcher()->addEventListenerWithFixedPriority(listener, 100);
return true;
}
bool HelloWorld::onTouchBegan(Touch *touch, Event *event){
label->setString("Foo Bar");
return true;
}
Thank you.
Your problem is in this line :
auto label = Label::create("Hello World", "Arial", 112);
In this line you declare a new variable named label whose scope is only for the init function. You also have a class variable also named label and they're not the same. If you declare a variable in a method with the same name as a class variable, it will shadow it. Consider this example :
class A {
int variable;
void method() {
int variable; // this is not the same thing as the one above
variable = 5; //assignment to local variable
this->variable = 3; //asignment to class variable
}
}
So you actually don't assign anything to your class variable label which you later reference in the touch method. The easiest way to solve this would be to remove the auto keyword at auto label from your init() method.
As noted by #Losiowaty, the use of auto can be dangerous sometimes.
cocos2d::Label* label = cocos2d::Label::create("Hello World", "Arial", 112);
Also, there might be a better constructor to use: http://www.cocos2d-x.org/reference/native-cpp/V3.1rc0/db/de4/classcocos2d_1_1_label.html

pass argv[] from main to other class

Hi I have a question about passing argv[] value to the other class. In my code, I want to pass the argv[1] parameter from cmd to the class mainWindow to trigger spacific event. Here is the code. #include "MainWindow.h"
int main(int argc, char *argv[])
{
#if _DEBUG
// Do not print memory leaks at end of program (QtWebKit causes a large number of them, see Menu class)
_CrtSetDbgFlag(_crtDbgFlag &~ _CRTDBG_LEAK_CHECK_DF);
#endif
QApplication app(argc, argv);
app.setApplicationName("Example_Qt");
MainWindow window;
window.show();
return app.exec();
}
MainWindow.cpp
MainWindow::MainWindow() :
m_pCurrentTutorial(0),
m_pCurrentTutorialAREL(0)
{
setupUi(this);
quitTutorialButton->setVisible(false);
QObject::connect(quitTutorialButton, SIGNAL(clicked()), this, SLOT(onQuitTutorialButtonClicked()));
m_pMenu = new Menu(this, this);
// Init the main view for the scene using OpenGL
QGLWidget *glWidget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
m_pGraphicsView = graphicsView;
m_pGraphicsView->setScene(m_pMenu);
m_pGraphicsView->setViewport(glWidget);
m_pGraphicsView->setFrameShape(QFrame::NoFrame);
// Do not show context menu in web view
m_pGraphicsView->setContextMenuPolicy(Qt::NoContextMenu);
}
MainWindow::~MainWindow()
{
delete m_pMenu;
m_pMenu = 0;
delete m_pGraphicsView;
m_pGraphicsView = 0;
}
Mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <vector>
#include <QVBoxLayout>
#include <QWidget>
#include <QWebView>
class TutorialBase;
class TutorialBaseAREL;
#include "Menu.h"
#include "ui_MainWindow.h"
QT_BEGIN_NAMESPACE
class QGraphicsView;
class QBoxLayout;
QT_END_NAMESPACE
class MainWindow : public QMainWindow, public Ui::MainWindow, public Menu::TutorialSelectionCallback
{
Q_OBJECT
public:
MainWindow();
virtual ~MainWindow();
QBoxLayout* getButtonBar();
protected slots:
void onQuitTutorialButtonClicked();
protected:
void keyPressEvent(QKeyEvent *event);
void quitTutorialIfAny();
void startTutorial(int tutorialNumber);
void startTutorialAREL(int tutorialNumber);
TutorialBase* m_pCurrentTutorial;
TutorialBaseAREL* m_pCurrentTutorialAREL;
QGraphicsView* m_pGraphicsView;
Menu* m_pMenu;
};
#endif
Could anyone help me to pass the parameter from the argv[] to mainwindow.cpp ?
Many thanks
Ying
You should be able to just provide another constructor (or replace the current one) which takes a single char * argument, such as:
MainWindow::MainWindow (char *arg) :
m_pCurrentTutorial(0),
m_pCurrentTutorialAREL(0)
{
// body here, including checking argument, such as:
if (strcmp (arg, "-help") == 0) {
provideHelp();
}
}
and then use that constructor when creating your object:
MainWindow window (argv[1]);
Be aware that this new constructor will need to be listed in the class (in Mainwindow.h), not just added as a function to Mainwindow.cpp:
public:
MainWindow();
MainWindow(char*);
virtual ~MainWindow();

A cocos2d-x code that cause crash on Android but not on iOS

While porting an cocos2d-x project from iOS to Android, I found a problem that will cause crashing on Android but not on iOS, to show this problem, I made a small modification to the HelloWorld sample. To reproduce this problem, just press the close button on the bottom-right corner, on Android it will crash but not on iOS.
The code that cause the crashing is:
void TestNode::test()
{
// This will cause crash on Android, but OK on iOS
CCCallFunc *selector = CCCallFunc::create(this, callfunc_selector(TestNode::destroy));
this->runAction(selector);
// This is ok on both Android and iOS
// CCCallFunc *selector = CCCallFunc::create(scene_, callfunc_selector(HelloWorld::destroyNode));
// scene_->runAction(selector);
// This is ok on both Android and iOS
// destroy();
}
The complete code as the following:
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class TestNode : public cocos2d::CCNode {
public:
TestNode(cocos2d::CCLayer *scene);
~TestNode();
void test();
void destroy();
cocos2d::CCLayer *scene_;
cocos2d::CCSprite *sprite_;
};
class HelloWorld : public cocos2d::CCLayer
{
private:
TestNode *node_;
public:
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::CCScene* scene();
// a selector callback
void menuCloseCallback(CCObject* pSender);
// implement the "static node()" method manually
CREATE_FUNC(HelloWorld);
void destroyNode();
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp:
#include "HelloWorldScene.h"
#include "AppMacros.h"
USING_NS_CC;
TestNode::TestNode(cocos2d::CCLayer *scene):
scene_(scene)
{
sprite_ = CCSprite::create("CloseNormal.png");
sprite_->setPosition(ccp(200, 200));
scene_->addChild(sprite_, 255);
}
TestNode::~TestNode()
{
scene_->removeChild(sprite_, true);
scene_->removeChild(this, true);
CCLog("+++ ~TestNode");
}
void TestNode::test()
{
// This will cause crash on Android, but OK on iOS
CCCallFunc *selector = CCCallFunc::create(this, callfunc_selector(TestNode::destroy));
this->runAction(selector);
// This is ok on both Android and iOS
// CCCallFunc *selector = CCCallFunc::create(scene_, callfunc_selector(HelloWorld::destroyNode));
// scene_->runAction(selector);
// This is ok on both Android and iOS
// destroy();
}
void TestNode::destroy()
{
CCLog("+++ destroy");
delete this;
}
CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
origin.y + pCloseItem->getContentSize().height/2));
// create menu, it's an autorelease object
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1);
/////////////////////////////
// 3. add your codes below...
// add a label shows "Hello World"
// create and initialize a label
CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", TITLE_FONT_SIZE);
// position the label on the center of the screen
pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - pLabel->getContentSize().height));
// add the label as a child to this layer
this->addChild(pLabel, 1);
// add "HelloWorld" splash screen"
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
// position the sprite on the center of the screen
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// add the sprite as a child to this layer
this->addChild(pSprite, 0);
node_ = new TestNode(this);
this->addChild(node_);
return true;
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
// CCDirector::sharedDirector()->end();
if (node_) {
node_->test();
node_ = NULL;
}
//#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
// exit(0);
//#endif
}
void HelloWorld::destroyNode()
{
node_->destroy();
}
I don't know why this works on iOS but you should not do this anyway. When you run the code
CCCallFunc *selector = CCCallFunc::create(this, callfunc_selector(TestNode::destroy));
this->runAction(selector);
which calls the function
void TestNode::destroy()
{
CCLog("+++ destroy");
delete this;
}
you are destroying an object that the CCCallFunc action still keeps a pointer to. Then when the CCCallFunc object is destroyed, it runs the CC_SAFE_RELEASE macro which will call release on your TestNode object. However, by now that TestNode object is already deallocated and that is most likely the reason for your crash.