japanese life

Lambda type Multithreading to process out of scope parameters (Cocos2dx, Android, C++)

Posted on Updated on

Lets pretend you have a vector containing int data, and you also have a class object which you need to pass into a Thread for some heavy duty processing. Lets also pretend that even if this process isn’t heavy at all but the program requires the order for everything to be processed in in exact logical order.

How do we do that? A thread in Cocos2dx with C++ looks like this:

    auto thread = std::thread([](){
        CCLog("start thread");
 
        // code goes here
 
        Director::getInstance()->getScheduler()->performFunctionInCocosThread([](){
            CCLog("finish another thread");
        });
    });
    thread.detach();

The problem:
Great! except our requirement was to pass in some data (a vector containing several int type variables and some class object)

With the above code we can’t do that because a Lambda doesn’t allow you to pass in data from outside of its scope even if it is of the same class. So what can we do about it?

The solution:
The solution is to use std::function. Lets make an example.

Header file:

template                <typename T, typename O>
std::function<T()>      MyThreadClass(T int_vector, O class_object);

I use a template for my variable types for 2 reasons:

1) With templates, You don’t need to worry about what data type goes in, everything is automated for you in the background.

2) I’m lazy (actually, I had a deadline writing this and I couldn’t be bothered to check)

Now in our implementation class we can write something like this:

/**
 * thread class
 */
template <typename T, typename M, typename B>
std::function<T()> MyThreadClass(T int_vector, O class_object) {
    CCLog("start thread");
    auto thread = std::thread([int_vector, class_object](){

        for (std::vector<int>::const_iterator itl = int_vector.begin(); itl != int_vector.end(); ++itl) {
            switch(*itl) {
				case 0: class_object.addNumbers(); 		break;
				case 1: class_object.subtractNumbers(); break;
				case 2: class_object.multiplyNumbers(); break;
				case 4: class_object.divideNumbers(); 	break;      
            }
        }

        Director::getInstance()->getScheduler()->performFunctionInCocosThread([int_vector, class_object);
    });
    thread.detach();
    return 0;
}

Might look a bit intimidating but its actually quite simple to understand.
In our Lambda we have to ‘capture’ data in order to process them. This is where we want to pass data into our thread. But Lambda won’t let us because it cannot see anything outside of its scope. So we pass data into our function which then is captured using something like below:

auto thread = std::thread([int_vector, class_object](){
	// ...
}
	// ...
Director::getInstance()->getScheduler()->performFunctionInCocosThread([int_vector, class_object);
	// ...

If we have no data to pass in from the outside, we can just remove int_vector and class_object.

Happy coding!

Generate array of sprites (Cocos2dx, C++, Android)

Posted on Updated on

alright before i forget i better write this down (being an idiot that i am i’ll forget this later)

i have this image:

which when fired at, a single block explodes gracefully like a new born baby taking its first breath outside of a womans-anyway having 1 massive image like the one above to hold several dozen block images isn’t a good idea.

A better way to do this is to have each block:
block

stored in an array or vector, loop over then before the loop is finished, add each element into our layer.

In code this would look something like this:

Block header file .h

#ifndef __BLOCK_H__
#define __BLOCK_H__
 
#include "cocos2d.h"
 
class Block : public cocos2d::Sprite
{
 
// ....
 
protected:
    Sprite*                 block;
 
public:
    Block();                                                    //  constructor
    Sprite*                 generateBlock(int pos);             //  generate a block
};
 
 
#endif // __BLOCK_H__

Block Implementation file.cpp

// ... 
Sprite* Block::generateBlock(int pos) {
    Block        _block_obj;            // instantiate our block class
// ...
    block      = Sprite::create("block.png");
    block     -> setPosition(Vec2(visibleSize.width/2 + pos, visibleSize.height));
    return block;
}
 
// ...

Now in our game scene we can do something like this:

Game scene header file.h

// ...
std::array<cocos2d::Sprite*, 10> _blockArray;
void    generateBlocksThenAddToArray();                              // generate a block then add into our array
// ...

implementation file .cpp

/**
 *  generate a block then add into our array
 */
void Hoge::generateBlocksThenAddToArray() {
 
    for (int i = 0; i < 10; i++) {
        Sprite* _generatedBlock  = _block_obj.generateBlock((i * 100) / 2);
        _blockArray[i]        = _generatedBlock;
        this                 -> addChild(_generatedBlock);
    }
}

The magic happens in the for loop in Hoge::generateBlocksThenAddToArray() method.
We loop to a suitable range (10 in this case),generate a block from the block class, set its x position by multiplying it by 100 per iteration using i, then add the instantiated block object into our _blockArray with the loop count as its address, then finally add the generated block into our game scene.

There’s probably another (better) way to do this, and I’d love some input from other talented programmers out there so, please give me a shout in the comment section below!

Collision between enemy characters and bullets shot – (Cocos2dx, C++, Android)

Posted on Updated on

Last weekend I got really stuck with something for a game I am building that had to do with collisions. The link is here on Stackoverflow:

http://stackoverflow.com/questions/31352254/collision-between-enemy-characters-and-bullets-shot-cocos2dx-c-android

Would greatly appreciate it if anybody has a few ideas on how I can work around this idea ..

————————-

My problem is the collision detection that i wrote for my enemy character objects and bullet objects.

The symtoms:
When 1 enemy character spawns and i shoot it with my bullets, the enemy character is destroyed as normal. But, if 2 or more enemy characters spawn and i shoot the first enemy that was spawned it does nothing. The last character that was spawned and shot is destroyed without issue.

How i tried to fix it:
I decided to give each enemy character a unique ID by creating an int variable and randomize it each time an enemy is spawned. This ensures me that each enemy character object will definately have a unique identifier so that if i shoot them, I can somehow match that unique ID with my bullet.

However, I dont know how to work around that. The code below just deletes every enemy character associated with any randomized tags

My question:
How can I set my bullet objects to hold every unique ID of my enemy characters, so that when the bullet hits one (doesn’t matter which specific order) it will search then compare the unique IDs it has to the enemy character ID it has shot?

Apologies if my question is unclear or if my coding style is horrible.

GameScene.cpp

/**
 * @param ENEMY_SPAWN_FREQUENCY value is 0.002, set to make them spawn automatically every few seconds
 */
void GameScene::updateScheduler() {
    this -> scheduleUpdate();
    this -> schedule(schedule_selector(GameScene::spawnEnemyCharacter),      ENEMY_SPAWN_FREQUENCY * visibleSize.width);
}

// ...

bool GameScene::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event) {

    // fire button
    auto target = (Sprite*)this -> getChildByTag(FIRE_BUTTON_TAG);
    Rect rect   = target        -> getBoundingBox();
    Point p     = touch         -> getLocation();

    // initialize bullets
    if (rect.containsPoint(p)) {
        GameScene::spawnBullets(PLAYER_TAG, playerCharacter->getPositionX(), playerCharacter->getPositionY()+100, 0, REFERENCE_SIZE_Y);
        return true;
    }

    // ...

    return false;
}

// ... somewhere below my GameScene.cpp class

void GameScene::spawnBullets(int shooter_id, int x, int y, int p_x, int p_y) {

    // load bullet sprites. 
    SpriteFrameCache::getInstance() -> addSpriteFramesWithFile("bullets.plist");

    // ... 

    auto bulletBody   = PhysicsBody::createBox(bullet_sprite -> getContentSize());
    bulletBody       -> setDynamic(true);
    bulletBody       -> setGravityEnable(false);
    bulletBody       -> setCollisionBitmask(BULLET_COLLISION_BITMASK);
    bulletBody       -> setContactTestBitmask(true);

    bullet_sprite    -> setPhysicsBody(bulletBody);
    bullet_sprite    -> setPosition(Point( x, y));
    bullet_sprite    -> setScale(0.2f);
    bullet_sprite    -> setTag(BULLET_TAG);
    this             -> addChild(bullet_sprite);

    // animate bullet object so that it shoots
    bullet_obj.fireBullet(bullet_sprite, p_x, p_y);
}

// ... somewhere further down this class i define my enemy characters to be spawned as enemy objects in the below method

void GameScene::spawnEnemyCharacter(float dt) {
    int random_tag = rand();        // ensure that each enemy character object has a unique random id as its tag
    enemyCharacter_obj.spawnEnemy(this, random_tag);
    enemy_tags.push_back(random_tag);

// ... destroy enemy characters if hit by bullet:

bool GameScene::onContactBegin( cocos2d::PhysicsContact &contact ) {
    PhysicsBody *a = contact.getShapeA() -> getBody();
    PhysicsBody *b = contact.getShapeB() -> getBody();

    if (BULLET_COLLISION_BITMASK == a->getCollisionBitmask() && ENEMY_COLLISION_BITMASK == b-> getCollisionBitmask() ||
        BULLET_COLLISION_BITMASK == b->getCollisionBitmask() && ENEMY_COLLISION_BITMASK == a-> getCollisionBitmask() ) {

        // delete enemys with random tag
        for (std::vector<int>::iterator itl = enemy_tags.begin(); itl != enemy_tags.end(); ++itl) {
            enemyCharacter_obj.destroyEnemyCharacter(this, *itl);
        }    
        this -> removeChild(bullet_sprite);
    }

    return true;
}

Bullet.cpp

void Bullet::fireBullet(Sprite* bullet_sprite, int x, int y) {
    auto bulletAction  = Sequence::create( MoveBy::create(BULLETSPEED, Point(x, y)), CallFuncN::create( CC_CALLBACK_1(Bullet::doRemoveFromParentAndCleanup, this, true)), NULL);
    bullet_sprite     -> runAction(bulletAction);
}

And now my enemy character class:

void EnemyCharacter::spawnEnemy(cocos2d::Layer* layer, int random_tag) {

    // データ読み込み
    SpriteFrameCache::getInstance() -> addSpriteFramesWithFile("enemies.plist");

    // 敵キャラクター
    enemyCharacter   = Sprite::createWithSpriteFrameName("enemy_1.png");
    auto enemyCharacterBody  = PhysicsBody::createBox(enemyCharacter -> getContentSize() / 5);

    // ...

    auto enemyCharacterPosition = (random * visibleSize.height ) + ( enemyCharacter -> getContentSize().height / 2);
    enemyCharacterBody         -> setDynamic(false);
    enemyCharacterBody         -> setCollisionBitmask(ENEMY_COLLISION_BITMASK);
    enemyCharacterBody         -> setContactTestBitmask(true);
    enemyCharacter             -> setScale(0.3f);
    enemyCharacter             -> setTag(random_tag);
    enemyCharacter             -> setPhysicsBody(enemyCharacterBody);
    enemyCharacter             -> setPosition( Point( ((random * visibleSize.width) + (enemyCharacter->getContentSize().width / 2)), visibleSize.height ) );
    layer                 -> addChild(enemyCharacter);

    // ...
}

// .. further down this class 

void EnemyCharacter::destroyEnemyCharacter(cocos2d::Layer* layer, int randomized_tag) {
    layer-> removeChild(layer -> getChildByTag(randomized_tag));
}

Fatal signal 6 (SIGABRT) at … (Cocos2dx 3.x on Android with C++) + Eclipse

Posted on Updated on

While it makes sense to use if statements its also blimin’ messy once you have so many conditions and editing the code later becomes messy, which eventually leads to bugs and hours of headaches.

I had an array like so:

MyClass::Constructor()
: MyArray({"C++", "C#", "Objective-C", "C"})
{
    // コンストラクター
}

Then I had to loop through this and tried to optimize my code so that instead of having something like this:

if (strcmp(MyArray,"C++") == 0){
    CCLog("array has C++");
} 
else if (strcmp(MyArray,"C#") == 0){
    CCLog("array has C#");
} 
if (strcmp(MyArray,"Objective-C") == 0){
    CCLog("array has Objective-C");
} 
if (strcmp(MyArray,"C") == 0){
    CCLog("array has C");
} 

I could turn it into something like this:

for (int i = 0; i < sizeof(MyArray); i++) {
    switch(i) {
        case 0: CCLog ("array has C++"); break;
        case 1: CCLog ("array has C#"); break;
        case 2: CCLog ("array has Objective-C"); break;
        case 3: CCLog ("array has C"); break;
    }

But the problem occurs when I get this error message:
Fatal signal 6 (SIGABRT) at …

I tried to print all the values of my array and commented out the switch statement and it seems that my loop will go through the array, but then read it from start to finish again and output (null)

The solution
I ended up not using sizeof, but just changed the above code to this:

for (int i = 0; i < MyArray.size(); i++) {
    switch(i) {
        case 0: CCLog ("array has C++"); break;
        case 1: CCLog ("array has C#"); break;
        case 2: CCLog ("array has Objective-C"); break;
        case 3: CCLog ("array has C"); break;
    }

Then recompiled and finally I was able to get my loop to work properly without issue.

Not really sure what sizeof really means, but i had assumed it worked the same as .size() and guessed wrong.

Programming – the important of design patterns

Posted on

It’s common sense to have some concrete design in your software not just for other people to understand your code, but also later when you have to modify your own project it will save you time.

You could be debugging in spaghetti code and try to “fix” 1 bug and cause 32 more defects to appear.

That’s my situation right now. Except before I allow any bugs to appear I have to consider putting everything into a new design that makes more sense. My approach would be the MVC approach (Model View Controller)

Model: the template
View: the GUI
controller: the code that does all the work

The view would talk to the controller for some data to be calculated.
The controller would look at the model while processing the requested data.
The model is .. just there like a confused bf passing stuff to his woman when she needs something.

Ok I’m done talking, lets start revamping this mess.

Cocos2dx (C++, Java & XML) – How to retrieve Android ID & IMEI/Device ID

Posted on Updated on

Problem: I’m currently building an app using Eclipse with Cocos2dx library using C++. A few days ago I was asked whether it is possible to retrieve the IMEI of someones Android device and load it into our app. So I investigated.

Later this thread ( http://discuss.cocos2d-x.org/t/get-device-id-in-cocos2dx-3-3/18960 ) and read that there is (apparently) no function built in this engine to retrieve the device ID for Android and this baffled me for a good day and a half. I also didn’t want to directly modify the cocos2dx library so that was also an issue.

But then I discovered JniHelper library under the JNI folder in my project.
From what I understand, JNI links Cocos2dx with Java for Android. So I investigated some more and found the solution to my problem. Without further ado, let the hacking begin!

First we need to prepare our C++ source file.

Solution:

.h Header file:

std::string getDeviceID();

.cpp implementation file:

// load jni libraries
#include "platform/android/jni/JniHelper.h"
#include <jni.h>

// ... somewhere further down our code

// 
std::string HogeHoge::getDeviceID() {
    std::string str;
    cocos2d::JniMethodInfo methodInfo;

    cocos2d::JniHelper::getStaticMethodInfo( methodInfo, "org/cocos2dx/cpp/AppActivity",  "findDeviceID", "()Ljava/lang/String;" ); // find our Java method
    jstring jpath  = (jstring)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID);      // For now we use a static method to retrieve a string value using CallStaticObjectMethod
    const char* npath = methodInfo.env->GetStringUTFChars(jpath, NULL);											    
    str = npath;

    // release objects/methods/anything we no longer need
    methodInfo.env->ReleaseStringUTFChars(jpath, npath);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
    return str.c_str();
}

From the C++ side, you declare where your Java class is located in your project and which class you want to load. In this example this is defined here:

std::string str;
cocos2d::JniMethodInfo methodInfo;
cocos2d::JniHelper::getStaticMethodInfo( methodInfo, "org/cocos2dx/cpp/AppActivity",  "findDeviceID", "()Ljava/lang/String;" );
// etc etc ..

Our method has now been implemented. But we need a way to print out our string value. Since my emulator is broken/slow as a donkey I’ve had to build my app as a .apk and load it straight into my device. Which means no error log will appear. Luckily however we can use Labels from the Cocos2dx Library to print out the value for us:

auto deviceIDLabel = Label::create(this->getDeviceID(), "Arial",100);
deviceIDLabel->setPosition(Point(winSize.width/2, winSize.height/2));
this->addChild(deviceIDLabel);

Our C++ implementation is now ready. Now lets head over to our Java file and write some more code:

.java Java implementation:

package org.cocos2dx.cpp;

import java.util.Locale;

import org.cocos2dx.lib.Cocos2dxActivity;
import com.example.etc.R;
//import android.R;  // <- dont need this
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;


public class AppActivity extends Cocos2dxActivity {
	
	private static String fetchID;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		fetchID = this.getIMEI();
	}
	
	/**
	 *  From the C++ side, we are calling for a static method. 
         *  Since we cannot use something like "this.etc etc" we need to compromise a bit and declare
         *  a private static string variable, set its value to call the return value of our static string
         *  method upon initialization.
	 * */
	public static String findDeviceID() {
		return fetchID;
	}
	
	/**
	 * Get Android ID
	 * */
	public String getDeviceID() {
		return Secure.getString(this.getContentResolver(), Secure.ANDROID_ID);	
	}
	
	/**
	 * retrieve IMEI
	 * */
	public String getIMEI() {
		TelephonyManager manager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
		return manager.getDeviceId();
	}
}

As stated in my comment:

From the C++ side, we are calling for a static method. Since we cannot use something like “this.etc etc” we need to compromise a bit and declare a private static string variable, set its value to call the return value of our static string method upon initialization.

one last thing – VERY IMPORTANT!!

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

you must add the following in your AndroidManifest.xml or your application will crash.

Now if we run this, our app should show our IMEI/device ID as a simple Label from our Cocos2dx library.

Was this article helpful/did it make sense? Please let me know because I’m terrible at explaining and I’d like to get better at it. Thanks!

Happy coding!

References:
http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId()
http://qiita.com/hmuronaka/items/9e62acb8ca7425102632
http://discuss.cocos2d-x.org/t/get-device-id-in-cocos2dx-3-3/18960

Cocos2dx (C++) – EditBox – How to retrieve multiple text data from EditBox

Posted on Updated on

It’s been a while since I posted any coding stuff here. But today after hours of debugging I have finally figured out how to solve my problem.

Objective; Using the editBoxReturn method, retrieve seperate from multiple parameters for user login.

In my .h header file I first have two private string variables as placeholders


class HogeHoge: public cocos2d::Layer, public cocos2d::ui::EditBoxDelegate
{

 private:
    std::string user_id_str;
    std::string password_str;
// etc etc
{;

In my .cpp implementation:

// etc etc
// username
 auto userID= cocos2d::ui::EditBox::create(Size(642, 146), "userid_background.png");
 userID->setPlaceHolder("Enter username");
 userID->setPosition(Point(winSize.width/2, winSize.height/2+300));
 userID->setFontSize(40);
 userID->setDelegate(this);
 userID->setReturnType(cocos2d::ui::EditBox::KeyboardReturnType::DONE);
 addChild(userID);

//password
 auto passwordText= cocos2d::ui::EditBox::create(Size(642, 146),"password_background.png");
 passwordText->setPlaceHolder("Enter password");
 passwordText->setPosition(Point(winSize.width/2, winSize.height/2+100));
 passwordText->setFontSize(40);
 passwordText->setDelegate(this);
 passwordText->setInputFlag(cocos2d::ui::EditBox::InputFlag::PASSWORD);
 addChild(passwordText);
// etc etc

and further down the code …

void HogeHoge::editBoxReturn(cocos2d::ui::EditBox* editbox) {
	this->user_id_str= editbox->getText(); break;
}

The problem: There is no distinction between userID and passwordText.
The solution: using getTag() and then pass an integer value with some kind of true false statement. Our code then looks like this:

.cpp implementation:

// etc etc
// username
 auto userID= cocos2d::ui::EditBox::create(Size(642, 146), "userid_background.png");
 userID->setPlaceHolder("Enter username");
 userID->setPosition(Point(winSize.width/2, winSize.height/2+300));
 userID->setFontSize(40);
 userID->setDelegate(this);
 userID->setTag(100);  // <- this is important
 userID->setReturnType(cocos2d::ui::EditBox::KeyboardReturnType::DONE);
 addChild(userID);

//password
 auto passwordText= cocos2d::ui::EditBox::create(Size(642, 146),"password_background.png");
 passwordText->setPlaceHolder("Enter password");
 passwordText->setPosition(Point(winSize.width/2, winSize.height/2+100));
 passwordText->setFontSize(40);
 passwordText->setDelegate(this);
 passwordText->setTag(200);  // <- this is important
 passwordText->setInputFlag(cocos2d::ui::EditBox::InputFlag::PASSWORD);
 addChild(passwordText);
// etc etc

and further down the code …

void HogeHoge::editBoxReturn(cocos2d::ui::EditBox* editbox) {
	switch(editbox->getTag()) {  // <- see what we did here?
		case 100: this->user_id_str= editbox->getText(); break;
		case 200: this->password_str = editbox->getText(); break;
	}
}

To test if this works, just use CCLog to print out the values of user_id_str or print them out as labels in your app. I tested mine on my phone rather than the emulator …because of a lot of problems and windows hates me. So I print out the values in the app like this:

auto copiedString = Label::create(this->user_id_str.c_str(), "Arial",100);
copiedString->setPosition(Point(winSize.width/2, winSize.height/2+550));
this->addChild(copiedString);

auto copiedPasswordString = Label::create(this->password_str.c_str(), "Arial",100);
copiedPasswordString->setPosition(Point(winSize.width/2, winSize.height/2+250));
this->addChild(copiedPasswordString);

Compile and run this and there we go!

Happy coding!

References:
http://toro.2ch.sc/test/read.cgi/gamedev/1390136237/756n-
http://xb.dachuw.com/cocosapi/df/d16/classcocos2d_1_1extension_1_1_edit_box_delegate.html

Wanderlust

Posted on Updated on

One of my ex girlfriends has this syndrome called Wanderlust, which according to dictionary.reference.com means this:

[won-der-luhst]
a strong, innate desire to rove or travel about.

So why does this matter? well lately I’ve been thinking about traveling to other countries. But first, I want to stay in Japan for another few years just to see if I will change my mind. Who knows, but I am thinking about New Zealand because my brother told me all about his amazing crazy adventures when he went. Next on my list is Canada because I love to snowboard, but I want to see more of the country besides Toronto which is where my family lives.

My weakness becomes my weapon and pain my pleasure

Posted on Updated on

Me and my friend Daniel are bodybuilding right now. The main difference between us is that I have a much higher metabolism than his, this means I burn fat much faster and with less effort.

The problem is my diet. So during the next 4 weeks I have to cut beer, chocolate, rice and bread out of my life completely and eat as much protein and less carbs as I can. The only carbs I should take in are from fruits or vegetables.

weight training is also a thing that has become possible thanks to my good friend Kim. He set up a training room above his shop so I go there as much as I can with 1 day rest in between.

I’m making a commitment to improve my shape.

Fun with Perl

Posted on Updated on

I’ve been wanting to learn Perl for a long time but never had the chance. So today after finishing my assignment and a bit of time to spare I decided to have a little fun with it and see just what kind of cool things I can do with it.

This is just a simple for loop inside another for loop to print a 10 by 10 grid. Useful for later if I want to iterate then print out a 2D array.

#!/usr/local/bin/perl
my $count;
 
$count;
$new_count;
 
for ($count = 0; $count &lt; 10; $count++) {
        print $count;
    for ($new_count = 0; $new_count; 10; $new_count++) {
        print $new_count;
    }
    print "\n";
}