Cocos2dx 3.1 learning from scratch (3) -- Touch event (callback, reverse value transfer)

Source: Internet
Author: User

Lecture 3 Touch

The first two articles we learned are enough for us to make a simple game. We can also say that we are getting started and can walk around.

This article describes the important touch callback mechanism in cocos2dx. You must remember that the first chapter uses the CC_CALLBACK_1 macro to define the timer time. It calls back a function with only one form parameter to perform the scheduled operation.


Implementation of callback functions (Lambda expressions)

Before learning this article, please carefully learn the features of C ++ 11, std: function and lambda expressions. C ++ 11 also introduces a lot of excellent code for the boost library, so that we do not need to add boost: when using it, such as std: bind to be used;

The Learning address is as follows:

Use C ++ 11function

Lua closure, iosblock, C ++ lambda Function

 

Briefly describe the use of functions. Unified function Definition Format: function <int (int, float)>. It is equivalent to a data type. Int defines an integer, while function defines a function.

Function <int (int, float)> func = [] (int a, float B) {return a + B ;}; // defines a function named func, the first parameter is int, the second parameter is float, and the return value is int. Int ret = func (3, 1.2f );

 

First, let's take a look at the definition of macro CC_CALLBACK _.

// new callbacksbased on C++11#defineCC_CALLBACK_0(__selector__,__target__, ...)std::bind(&__selector__,__target__, ##__VA_ARGS__)#defineCC_CALLBACK_1(__selector__,__target__, ...)std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)#defineCC_CALLBACK_2(__selector__,__target__, ...)std::bind(&__selector__,__target__, std::placeholders::_1,std::placeholders::_2, ##__VA_ARGS__)#defineCC_CALLBACK_3(__selector__,__target__, ...)std::bind(&__selector__,__target__, std::placeholders::_1,std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)

In fact, they only encapsulate the usage of bind. We can see several parameters, followed by several _*.

To use bind and function, you need to introduce the header file # include <functional>. For the bind parameter type, you need to introduce the namespace using namespace std: placeholders;

 

#include"stdafx.h"#include<iostream>#include<string>#include<functional>using namespace std;using namespacestd::placeholders; struct Foo {    Foo(int num) : num_(num) {}    void print_add(int i) const { std::cout<< num_ + i << '\n'; }    int num_;};int _tmain(int argc,_TCHAR* argv[]){    const Foo foo(123);   function<void(int)> f_add_display =bind(&Foo::print_add, foo, _1);return0;}

Note: When bind is bound to a class function, the second parameter must be a class object.

 

Therefore, when we bind the callback function to the menu item, we do not use CC_CALLBACK_1:

        auto item =MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt",itemName->getCString()));       item->setCallback(CC_CALLBACK_1(KT0618::change, this));
Equivalent

        auto item =MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt",itemName->getCString()));       item->setCallback(std::bind(&KT0618::change, this,std::placeholders::_1));

It is also equivalent

Auto item = MenuItemLabel: create (Label: createWithBMFont ("fonts/futura-48.fnt", itemName-> getCString ())); item-> setCallback ([=] (Ref * ref)-> void {// lambd expression ...... });

 

How to correctly define and declare callback functions:

When we create an genie, we often cannot remember the parameters and types of callback functions of this type. The important method here is to read the api. Let's track the source code of the create method. In the create method, check the type of the callback function returned value and the type of the parameter. Copy the parameter.


During the exercise, we should try not to use CC_CALLBACK _ *, but write the bind function or lambda expression on our own.


**************************************** **************************************** *******************************

Reverse value transfer

A simple application scenario: the highest score is displayed on the main game page. After switching to the game scenario, you need to return the score to the main scene to determine whether to refresh the record. If yes, the highest score on the main interface is updated.

We have learned how to pass forward values in the previous section. You can use the member functions in the subscenario to transfer values to the subscenario. The so-called reverse value transfer can be understood as the sub-scenario to transfer the value back to the main scenario.

 

Based on the functions we learned above, we should store the function pointers in the main scenario using the member functions in the sub-scenario to the sub-scenario, then, in a subscenario, you can call its member variables to call functions in the main scenario. In this way, we can only use pushScene when switching scenarios, and use popScene in subscenarios. Otherwise, the objects in the main scenario do not exist. How can we implement callback ?!

New users may want to instantiate a class object in the main scenario in the subscenario so that they can pass the value, and then use replace to switch the scenario, instead of passing a function pointer in this way. In this case, the home scene and sub-scenario should reference the header file to instantiate the other party, in violation of the low coupling principle.

 

This is defined in the header file of the sub-scenario:

 

Public:    std::function<void(int)> func;

We can register the callback function as follows when switching from the main scenario to the sub-scenario:

Auto scene = HomeWorkSnowFight: createScene (); HomeWorkSnowFight * layer = (HomeWorkSnowFight *) scene-> getChildren (). at (0); layer-> func = std: bind (& HomeWorkSnow: callback1, this, std: placeholders: _ 1 ); // bind the callback function to the subscenario ctor: getInstance ()-> pushScene (TransitionCrossFade: create (1, scene ));

In this way, calling func (99) in a subscenario is equivalent to calling callback1 (99) in the main scenario.


Trigger event

Gyroscope

    Device::setAccelerometerEnabled(true);   // auto ac =EventListenerAcceleration::create(CC_CALLBACK_2(KT0618::accelerationc, this));    auto ac =EventListenerAcceleration::create([&](Acceleration* acc, Event* e){       sp->setPositionX(acc->x+sp->getPositionX());    });   _eventDispatcher->addEventListenerWithSceneGraphPriority(ac, this);

When writing a function, check the api carefully and check that create has several parameters.

For example, the form parameter format of the create function of the gyroscope is as follows:

Const std: function <void (Acceleration *, Event *)> & callback

This indicates that the parameter to be passed in should be a void function object with two parameters.

The gyroscope code can only be tested on a real machine.


Keyboard Events

It cannot be simulated in xcode and can only be tested in. The following code must be kept in mind. You can understand it after implementation!

    auto keyboardLs =EventListenerKeyboard::create();    keyboardLs->onKeyPressed =[=](EventKeyboard::KeyCode code, Event*event){        if(code==EventKeyboard::KeyCode::KEY_A)        {            CCLOG("AAA");        }    };    keyboardLs->onKeyReleased =[](EventKeyboard::KeyCode code, Event*event){        CCLOG("BBB");    };   _eventDispatcher->addEventListenerWithSceneGraphPriority(keyboardLs,this);

Mouse event single touch

    auto listen =EventListenerTouchOneByOne::create();    listen->onTouchBegan =CC_CALLBACK_2(KT0618::onTouchBegan, this);    listen->onTouchMoved =CC_CALLBACK_2(KT0618::onTouchMoved, this);    listen->onTouchEnded =CC_CALLBACK_2(KT0618::onTouchEnded, this);     listen->setSwallowTouches(true);   Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listen,this);

You can drag an object to another object. You only need to drag the object to the edge of the target and release the mouse. The object is automatically placed in the center.

 

B

oolKT0618::onTouchBegan(Touch *t, Event*e){    Point p = t->getLocation();    Rect rect = spMove->getBoundingBox();    if (rect.containsPoint(p))    {        return true;    }    else    {        return false;    }    return true;}voidKT0618::onTouchMoved(Touch *t, Event*e){    Point p = t->getLocation();    Rect rect = spMove->getBoundingBox();    if (rect.containsPoint(p))    {        spMove->setPosition(p);    }} voidKT0618::onTouchEnded(Touch *t, Event*e){    Point p = t->getLocation();    Rect rect = spBase->getBoundingBox();     if (rect.containsPoint(p))    {       spMove->setPosition(spBase->getPosition());    }}

 

Multi-touch

AppController. mm in ios adds [eaglView setMultipleTouchEnabled: YES]; you can debug multiple points by pressing alt in the simulator.

You don't need to think about windows, except for surface.

    auto touchMore =EventListenerTouchAllAtOnce::create();    touchMore->onTouchesBegan =CC_CALLBACK_2(KT0618::onTouchesBegan, this);    touchMore->onTouchesMoved =CC_CALLBACK_2(KT0618::onTouchesMoved, this);    touchMore->onTouchesEnded =CC_CALLBACK_2(KT0618::onTouchesEnded, this);   _eventDispatcher->addEventListenerWithSceneGraphPriority(touchMore,this);

OnTouchesBegan has different values for single-touch operations. Please write them according to the api.

void  KT0618::onTouchesBegan(conststd::vector<Touch*>& touches, Event* events){    for (auto v : touches )    {        v->getLocation();    }}voidKT0618::onTouchesMoved(const std::vector<Touch*>& touches, Event*unused_event){}void  KT0618::onTouchesEnded(conststd::vector<Touch*>& touches, Event *unused_event){}

Add custom message response EventListenerCustom

Add the following code in init (), so this layer will respond to the shutdown message of the flag.

   auto listenCustom =EventListenerCustom::create("shutdown",CC_CALLBACK_1(KT0618::popupLayerCustom, this));   Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listenCustom,1);

 

This can be added in the place where the shutdown message needs to be sent. The second parameter is the custom parameter of the message.

_ EventDispatcher-> dispatchCustomEvent ("shutdown", (void *) "Go! DongGuan! ");
 

In this way, a message named shutdown is distributed out.

This message can be received in different layers, and the second parameter can be used for data transmission. It can be any type of data, which is more convenient than callback.

The init of other layers is also added as shown above, and corresponding response functions are added.

voidPopupLayer::shutdown(EventCustom * event){    char * str =(char *)event->getUserData();    CCLOG("Do not toucheme,bullshit!");    CCLOG(str);}


Add sound effects

# Include <SimpleAudioEngine. h>

Usingnamespace CocosDenshion;

CocosDenshion: SimpleAudioEngine: sharedEngine ()-> playBackgroundMusic (MUSIC_BG, true );

CocosDenshion:

: SimpleAudioEngine: sharedEngine ()-> playEffect (MUSIC_ENEMY1 );

 

Sound effects are pre-loaded when init is used, but you must release the pre-loaded sound effects when switching the scenario.

CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic(MUSIC_BG);CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect(MUSIC_BULLET);



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.