Things I didn’t know about Cocos2d-x, but I probably could have read in the docs somewhere #4

If you have the same Scene on the Director’s Scene stack, either by runWithScene or with pushScene, if you pop one off, it’ll call release on it, and effectively destroy it, making any further operations on the Scene impossible.

To resolve this, you need to call retain() on the scene, to tell cocos that somewhere else is using the scene.

Things I didn’t know about Cocos2d-x, but I probably could have read in the docs somewhere #1

If you run an Effect, by creating a NodeGrid, and then adding a sprite or something to it, and then each frame, you keep calling runAction on it with a new Effect, it’ll never start, because each action is constantly getting replaced.

To solve this, I added a boolean flag on the object to see if an effect was running or not, and then only ran the effect if the flag was false.

How to add vibration to any cocos2dx 3.3 Android app

I had originally avoided using vibration in my game, because I had found several different posts trying to figure out exactly what you needed to do, and I wasn’t able to find any tutorials that really broke down the process, so I chugged some coffee and dug into the code that was linked on the official forums. forum post. I can’t overstate how helpful it was to have a sub 10 second turn around time, between using Visual Studio to write the code, cocos to compile it (cocos compile -p android) and then to push it to my android phone with adb (adb install -r debug.apk), and then monitoring what was happening with logcat (adb logcat *:w), filtering only for warnings, errors and anything higher). Before we jump into it though, here’s a rough summary:

  1. You need to add a header in your Classes/ folder where you just have the vibrate function declared but not defined.
  2. Add a vibration function definition in the proj.android/jni, in a .cpp file. I used proj.android/jni/hellocpp/main.cpp , which I believe is the default for a starter cocos2dxv3 project. In this method you call the method you’ve defined in your java, in this case it was defined as a static method on your Activity. The default was named AppActivity .
  3. make sure you’ve got the vibration permission on your proj.android/AndroidManifest.xml , <uses-permission android:name= android.permission.VIBRATE>”

So, in one of your standard C++ headers in the Classes/ folder, add

    //Classes/any_header.h
    void vibrate(int milliseconds);

and in the associated <tt>.cpp</tt> file, call it: 

    //Classes/any_header.cpp
    void get_hit()
    {
      vibrate(200);
    }

In your
proj.android/AndroidManifest.xml , you’ll want to add that line

    <manifest>
      ...
      <uses-permission android:name="android.permission.VIBRATE"/>
    </manifest>

In a cpp file the jni will deal with, say proj.android/jni/hellocpp/main.cpp , you’ll need to define the connection between the Java and C++ by calling the Java method:

    //proj.android/jni/hellocpp/main.cpp
    /* this function should already exist though */
    void cocos_android_app_init (JNIEnv* env, jobject thiz) {
        LOGD("cocos_android_app_init");
        AppDelegate *pAppDelegate = new AppDelegate();
    }

    /* this is the new one you're adding, where org/cocos2dx/cpp/AppActivity
       is the java file where your Activity with the vibrate static method is defined
    */
    void vibrate(int milliseconds)
    {
        JniMethodInfo minfo;
        CCAssert(JniHelper::getStaticMethodInfo(minfo, "org/cocos2dx/cpp/AppActivity", "vibrate", "(I)V"), "Function doesn't exist");
        minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, (jint)milliseconds);
        minfo.env->DeleteLocalRef(minfo.classID);
    }

Finally, here’s the .java file where the android call to vibrate is made. Mine was proj.android/src/org/cocos2dx/cpp/AppActivity.java

    /* default imports */
    package org.cocos2dx.cpp;

    import org.cocos2dx.lib.Cocos2dxActivity;

    /* imports needed for vibration stuff */
    import android.os.Vibrator;
    import android.content.Context;
    import android.app.ActivityManager;
    import android.util.Log;
    import android.os.Bundle;

    public class AppActivity extends Cocos2dxActivity {

        private static volatile Cocos2dxActivity mainActivity;
        public static void setMainActivity(Cocos2dxActivity activity)
        {
            mainActivity = activity;
        }

        public static Cocos2dxActivity getMainActivity()
        {
            if(mainActivity == null)
            {
                Log.w("MY_APP_NAME_GOES_HERE", "Warning : null main Activity");
            }
            return mainActivity;
        }

    	@Override
    	protected void onCreate(Bundle savedInstanceState)
    	{
    		super.onCreate(savedInstanceState);
        	AppActivity.setMainActivity(this);
    	}

        public static void vibrate(int milliseconds)
        {
            Vibrator v = (Vibrator) getMainActivity().getSystemService(Context.VIBRATOR_SERVICE);
            if (getMainActivity().getSystemService(Context.VIBRATOR_SERVICE) != null)
            {
                v.vibrate(milliseconds);
            }
        }
    }

Hope this helped you!