Irrlicht Sur Anndroid - Partie 2 - Multitouch Event

Proposé par nabouill

le 07 January 2014 à 17h 42mn 53s

10308 visualisations


Suite à la partie1 et à l’intégration des event sur la gui, nous allons maintenant passer au multitouch.

Effectivement, à la base dans Irrlicht, il nous renvoi si on cliqué sur un bouton avec le clic gauche par exemple. Cependant, nos dernier test nous dit si par exemple nous avons cliqué sur le bouton « quittez » mais si nous restons appuyé sur ce bouton et essayons d’appuyé en même temps sur un autre, cela ne fonctionne pas, il reste bloqué sur l’event précédant temps que celui-ci n’est pas terminée, ce qui va vite nous poser problème.

Imaginons que nous avons un bouton pour avancer et un autre pour reculer, vous poser votre doigt sur « avancer » puis vous le faite glissé sur « reculer ». Et bien, vous n’allez pas reculer mais continuer d’avancé tant que votre doigt touchera l’écran.

Nous allons donc pour remédier à ce problème utilisé les event multitouch.





Pour cela nous allons récupérer la position de chaque touche renvoyé par :
event.MultiTouchInput.X[i];
event.MultiTouchInput.Y[i];

Soit par exemple une function MyEventReciver:

Code c++ :


class MyEventReceiver : public IEventReceiver
{

    public:
    MyEventReceiver(SAppContext & context) : Context(context) { }
    int posX[2];
    int posY[2];

    virtual bool OnEvent(const SEvent& event)
    {
        if(event.EventType == EET_MULTI_TOUCH_EVENT)
        {

            for( int i = 0; i < 2; i++)
            {

                if(event.MultiTouchInput.Touched[i])
                {
                    posX[i] = event.MultiTouchInput.X[i];
                    posY[i]= event.MultiTouchInput.Y[i];
                    __android_log_print(ANDROID_LOG_ERROR, "*******MOUSE***** ", "X = %i, Y = %i,\n", posX[i], posY[i]);

                }
                else
                {
                    posX[i] = -1; // on reset la position si on n’y touche plus
                    posY[i] = -1; // on reset la position si on n’y touche plus
                }

            }
        }

        return false;
    }

    private:
    SAppContext & Context;
};


Puis dans notre code, on n’a plus qu’à vérifier les positions touchées pour en faire ce qu’on veut, imaginons un bouton en position rect<s32>(10,10,50,50) :

Code c++ :


MyEventReceiver receiver(context);
device->setEventReceiver(&receiver);
env->addButton(rect<s32>(10,10,50,50),0) ;

/*

*/


// on parcourt les positions que l’on touche
for(int i = 0; i < 2; i++)
{
    If(receiver.posX[i] > 10 && receiver.posX[i] < 50
    && receiver.posY[i] > 10 && receiver.posY[i] < 50)
    {
                     //on touche à notre bouton
              }
}


Dans cette exemple on se limite à récupère la position de 2 touches simultané, cependant vous avez la possibilité d’en récupérer jusqu’à 10 dans l’état actuel d’Irrlicht (même plus si vous modifiez la valeur de NUMBER_OF_MULTI_TOUCHES dans IEventReceiver.h)

#1 

07-01-2014 17:49:37

nabouill
Abonné
Date d'inscription: 17-09-2009
Messages: 242
Corrections: 1

Donc maintenant voici un petit code exemple basé sur le l’exemple 02.Quake3Map inclus avec Irrlicht mais intégrant un pavé de touche directionnel + 1 Joystick pour contrôler la camera :

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480

/** Example 002 Quake3Map

This Tutorial shows how to load a Quake 3 map into the engine, create a
SceneNode for optimizing the speed of rendering, and how to create a user
controlled camera.

Please note that you should know the basics of the engine before starting this
tutorial. Just take a short look at the first tutorial, if you haven't done
this yet: http://irrlicht.sourceforge.net/tut001.html

Lets start like the HelloWorld example: We include the irrlicht header files
and an additional file to be able to ask the user for a driver type using the
console.
*/




#include <irrlicht.h>

#include <android_native_app_glue.h>
#include <android/log.h>
#include <android/native_window.h>


using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;



struct SAppContext
{
    IrrlichtDevice *device;
};

// Define some values that we'll use to identify individual gui controls.
enum
{
    GUI_ID_QUIT_BUTTON = 101,
    GUI_ID_AVANCE,
    GUI_ID_RECULE,
    GUI_ID_GAUCHE,
    GUI_ID_DROITE,
    MJOY_UP,
    MJOY_DOWN,
    MJOY_LEFT,
    MJOY_RIGHT,
};



class MyEventReceiver : public IEventReceiver
{

    public:
    MyEventReceiver(SAppContext & context) : Context(context) { }
    int posX[2];
    int posY[2];

    virtual bool OnEvent(const SEvent& event)
    {
        if (event.EventType == EET_USER_EVENT)
        {
            __android_log_print(ANDROID_LOG_ERROR, "Reset", "Reset Event");
            //Context.device->getGUIEnvironment()->addImage(Context.device->getVideoDriver()->getTexture("media/irrlichtlogo2.png"), position2d<int>(10,10));
        }
        else if (event.EventType == EET_GUI_EVENT)
        {
            s32 id = event.GUIEvent.Caller->getID();
            IGUIEnvironment* env = Context.device->getGUIEnvironment();

            switch(event.GUIEvent.EventType)
            {

                case EGET_BUTTON_CLICKED:
                    switch(id)
                    {
                        case GUI_ID_QUIT_BUTTON:
                            Context.device->closeDevice();
                            return true;


                        default:
                            return false;
                    }
                    break;


                default:
                    break;
            }
        }
        else if(event.EventType == EET_MULTI_TOUCH_EVENT)
        {

            for( int i = 0; i < 2; i++)
            {

                if(event.MultiTouchInput.Touched[i])
                {
                    posX[i] = event.MultiTouchInput.X[i];
                    posY[i]= event.MultiTouchInput.Y[i];
                    __android_log_print(ANDROID_LOG_ERROR, "*******MOUSE***** ", "X = %i, Y = %i,\n", posX[i], posY[i]);

                }
                else
                {
                    posX[i] = -1;
                    posY[i] = -1;
                }

            }
        }

        return false;
    }

    private:
    SAppContext & Context;
};




void getAndroidScreenSize(int& lEcran, int& hEcran, JNIEnv* jnienv, android_app* app)
{
    jclass CActivity = jnienv->FindClass("android/app/Activity");
    jmethodID MgetWindowManager = jnienv->GetMethodID(CActivity, "getWindowManager", "()Landroid/view/WindowManager;");
    jclass CWindowManager = jnienv->FindClass("android/view/WindowManager");
    jmethodID MgetDefaultDisplay = jnienv->GetMethodID(CWindowManager, "getDefaultDisplay", "()Landroid/view/Display;");
    jclass CDisplay = jnienv->FindClass("android/view/Display");
    jmethodID MgetSize = jnienv->GetMethodID(CDisplay, "getSize", "(Landroid/graphics/Point;)V");
    jclass CPoint = jnienv->FindClass("android/graphics/Point");
    jmethodID MPointNew = jnienv->GetMethodID(CPoint, "<init>", "()V");
    jfieldID FPointX = jnienv->GetFieldID(CPoint, "x", "I");
    jfieldID FPointY = jnienv->GetFieldID(CPoint, "y", "I");
    jobject display = jnienv->CallObjectMethod(jnienv->CallObjectMethod(app->activity->clazz, MgetWindowManager), MgetDefaultDisplay);
    jobject point = jnienv->NewObject(CPoint, MPointNew);
    jnienv->CallVoidMethod(display, MgetSize, point);
    lEcran = (int)(jnienv->GetIntField(point, FPointX));
    hEcran = (int)(jnienv->GetIntField(point, FPointY));
}


bool touchInBoutton(IGUIButton *boutton, int x, int y)
{
    if(x > boutton->getAbsolutePosition().UpperLeftCorner.X
        && x < boutton->getAbsolutePosition().LowerRightCorner.X
        && y > boutton->getAbsolutePosition().UpperLeftCorner.Y
        && y < boutton->getAbsolutePosition().LowerRightCorner.Y)
        {
            return true;
        }
    else
    {
        return false;
    }

}

int stateJoystick(IGUIButton *boutton, int x, int y)
{
    if(x < (boutton->getAbsolutePosition().UpperLeftCorner.X + boutton->getAbsolutePosition().getWidth() * 0.30))
    {
        return MJOY_LEFT;
    }
    else if(x > (boutton->getAbsolutePosition().UpperLeftCorner.X + boutton->getAbsolutePosition().getWidth() * 0.70))
    {
        return MJOY_RIGHT;
    }
    else if(y < (boutton->getAbsolutePosition().UpperLeftCorner.Y + boutton->getAbsolutePosition().getWidth() * 0.30))
    {
        return MJOY_UP;
    }
    else if(y > (boutton->getAbsolutePosition().UpperLeftCorner.Y + boutton->getAbsolutePosition().getWidth() * 0.70))
    {
        return MJOY_DOWN;
    }


}


void move(ISceneNode *node, vector3df vel)
{
    matrix4 m;
    m.setRotationDegrees(node->getRotation());
    m.transformVect(vel);
    node->setPosition(node->getPosition() + vel);
    node->updateAbsolutePosition();
}

void targetCamera(ICameraSceneNode* camera)
{
    vector3df rotCam = camera->getRotation();
    vector3df pos(0.0f,0.0f,1000.0f);//1000 en Z pour regarder a 1000 unité devant nous
    matrix4 mat;
    mat.setRotationDegrees(rotCam);
    mat.transformVect(pos);
    camera->setTarget(camera->getAbsolutePosition() + pos);
}


void android_main(android_app* app)
{


    JNIEnv *jnienv = NULL;
    JavaVM *jvm = app->activity->vm;
    JavaVMAttachArgs lJavaVMAttachArgs;
    lJavaVMAttachArgs.version = JNI_VERSION_1_6;
    lJavaVMAttachArgs.name = "NativeThread";
    lJavaVMAttachArgs.group = NULL;
    jvm->AttachCurrentThread(&jnienv, &lJavaVMAttachArgs);
    jobject activity = app->activity->clazz;
    app_dummy();

    int lEcran;
    int hEcran;
    //recupere la taille de l ecran stocker dans nos variable lEcran et hEcran
    getAndroidScreenSize(lEcran, hEcran, jnienv, app);
    __android_log_print(ANDROID_LOG_ERROR, "Screen Width, Height: ", "%i, %i\n", lEcran, hEcran);


    SIrrlichtCreationParameters param;
    param.DriverType = EDT_OGLES2;
    param.PrivateData = app;
    param.WindowSize = dimension2d<u32>(0,0);//lEcran>hEcran?lEcran:hEcran, lEcran>hEcran?hEcran:lEcran);
    param.Bits = 24;
    param.ZBufferBits = 16;
    param.AntiAlias  = 0;

    IrrlichtDevice* device = createDeviceEx(param);

    if (device == 0) // could not create selected driver.
        return;

    device->setResizable(true);

    video::IVideoDriver* driver = device->getVideoDriver();


    dimension2d<u32> size = driver->getScreenSize();
    __android_log_print(ANDROID_LOG_ERROR, "Render Window Width, Height: ", "%i, %i\n", size.Width, size.Height);


    IGUIEnvironment* env = device->getGUIEnvironment();
    ISceneManager* smgr = device->getSceneManager();

    IGUISkin* skin = env->getSkin();
    IGUIFont* font = env->getFont("media/fonthaettenschweiler.bmp");
    if (font)
        skin->setFont(font);

    skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP);



    //calcule de la position des bouton par rapport à la taille de l'écran
    s32 largeurBoutton = lEcran*0.10;
    s32 hauteurBouton = (hEcran * 0.15);
    s32 p1 = lEcran * 0.10;
    s32 p2 = hEcran - (hEcran * 0.4);
    s32 p3 = p1 + largeurBoutton;
    s32 p4 = p2 + hauteurBouton;

    // BOUTTON AVANCE
    ITexture* imageAvance(driver->getTexture("media/arrow-up.png"));
    IGUIButton *buttonAvance = env->addButton(rect<s32>(p1,
                                                        p2,
                                                        p3,
                                                        p4),
                                                        0, GUI_ID_AVANCE);
    buttonAvance->setImage(imageAvance);
    buttonAvance->setScaleImage(true);
    buttonAvance->setUseAlphaChannel(true);
    buttonAvance->setDrawBorder(false);

    // BOUTON RECULE
    ITexture* imageRecule(driver->getTexture("media/arrow-down.png"));
    IGUIButton *buttonRecule = env->addButton(rect<s32>(p1,
                                                        p4 + (hEcran*0.06) ,
                                                        p3,
                                                        p4 + (hEcran*0.06) + hauteurBouton),
                                                        0, GUI_ID_RECULE);
    buttonRecule->setImage(imageRecule);
    buttonRecule->setScaleImage(true);
    buttonRecule->setUseAlphaChannel(true);
    buttonRecule->setDrawBorder(false);

    // BOUTTON GAUCHE
    ITexture* imageGauche(driver->getTexture("media/arrow-left.png"));
    IGUIButton *buttonGauche = env->addButton(rect<s32>(p1 - hauteurBouton - (lEcran * 0.01),
                                                        p4 - (largeurBoutton/2) + (hEcran*0.03),
                                                        p1 - (lEcran * 0.01) ,
                                                        p4 + (largeurBoutton/2) + (hEcran*0.03)),
                                                        0, GUI_ID_GAUCHE);
    buttonGauche->setImage(imageGauche);
    buttonGauche->setScaleImage(true);
    buttonGauche->setUseAlphaChannel(true);
    buttonGauche->setDrawBorder(false);

    // BOUTON DROITE
    ITexture* imageDroite(driver->getTexture("media/arrow-right.png"));
    IGUIButton *buttonDroite = env->addButton(rect<s32>(p1 + largeurBoutton + (lEcran * 0.01),
                                                        p4 - (largeurBoutton/2) + (hEcran*0.03),
                                                        p1 + largeurBoutton + (lEcran * 0.01) + hauteurBouton,
                                                        p4 + (largeurBoutton/2) + (hEcran*0.03)),
                                                        0, GUI_ID_DROITE);

    buttonDroite->setImage(imageDroite);
    buttonDroite->setScaleImage(true);
    buttonDroite->setUseAlphaChannel(true);
    buttonDroite->setDrawBorder(false);

    // JOYSTICK
    p1 = lEcran - (lEcran * 0.25);
    p2 = hEcran - (hEcran * 0.35);
    p3 = lEcran - (lEcran * 0.05);
    p4 = hEcran - (hEcran * 0.05);
    //la base
    ITexture* imageControlBase(driver->getTexture("media/control-base.png"));
    IGUIButton *buttonControlBase = env->addButton(rect<s32>(p1,p2,p3,p4),0, GUI_ID_DROITE);
    buttonControlBase->setImage(imageControlBase);
    buttonControlBase->setScaleImage(true);
    buttonControlBase->setUseAlphaChannel(true);
    buttonControlBase->setDrawBorder(false);
    // la boule du joystick
    ITexture* imageBall(driver->getTexture("media/control-ball.png"));
    IGUIButton *buttonBall = env->addButton(rect<s32>(p1 + (buttonControlBase->getAbsolutePosition().getWidth() *0.25),
                                                      p2 + (buttonControlBase->getAbsolutePosition().getHeight() *0.25),
                                                      p3 - (buttonControlBase->getAbsolutePosition().getWidth() *0.25),
                                                      p4 - (buttonControlBase->getAbsolutePosition().getHeight() *0.25)),
                                                      0, GUI_ID_DROITE);
    buttonBall->setImage(imageBall);
    buttonBall->setScaleImage(true);
    buttonBall->setUseAlphaChannel(true);
    buttonBall->setDrawBorder(false);
    int tailleBall = buttonBall->getAbsolutePosition().getWidth();
    int buttonBallTouchInEvent = -1;






    // boutton pour quitter
    env->addButton(rect<s32>(lEcran - (lEcran * 0.11),
                             hEcran - (hEcran * 0.99),
                             lEcran - (lEcran * 0.01),
                             hEcran - (hEcran * 0.89)),
                             0, GUI_ID_QUIT_BUTTON, L"Quit", L"Exits Program");



    env->addImage(driver->getTexture("media/irrlichtlogo3.png"), position2d<int>(10,10));


        device->getFileSystem()->addFileArchive("media/map-20kdm2.pk3");

        scene::IAnimatedMesh* mesh = smgr->getMesh("20kdm2.bsp");
        scene::ISceneNode* node = 0;

        if (mesh)
        node = smgr->addOctreeSceneNode(mesh->getMesh(0), 0, -1, 1024);

        if (node)
        node->setPosition(core::vector3df(-1300,-144,-1249));


    ICameraSceneNode * myCamera = smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));


    SAppContext context;
    context.device = device;
    MyEventReceiver receiver(context);
    device->setEventReceiver(&receiver);



    ANativeWindow* oldwin = app->window;

    while(device->run() && driver)
    if (device->isWindowActive())
    {

        if(oldwin!=app->window){
            __android_log_print(ANDROID_LOG_ERROR, "Win", "window changed");
            oldwin = app->window;
        }

        // on boucle pour checker le multitouch
        for(int i = 0; i < 2; i++)
        {
            // button event
            if(touchInBoutton(buttonAvance,receiver.posX[i],receiver.posY[i]))
            {
                move(myCamera, vector3df(0,0,1));
            }
            if(touchInBoutton(buttonRecule,receiver.posX[i],receiver.posY[i]))
            {
                move(myCamera, vector3df(0,0,-1));
            }
            if(touchInBoutton(buttonGauche,receiver.posX[i],receiver.posY[i]))
            {
                move(myCamera, vector3df(-1,0,0));
            }
            if(touchInBoutton(buttonDroite,receiver.posX[i],receiver.posY[i]))
            {
                move(myCamera, vector3df(1,0,0));
            }
            //JOYSTICH EVENT
            if(touchInBoutton(buttonControlBase,receiver.posX[i],receiver.posY[i]))
            {
                buttonBall->setRelativePosition(position2d<s32>(receiver.posX[i] - tailleBall/2,
                                                                receiver.posY[i]- tailleBall/2));
                buttonBallTouchInEvent = i;

                // appel de joystate qui nous renvoi son etat
                int joystate = stateJoystick(buttonControlBase,receiver.posX[i],receiver.posY[i]);

                switch(joystate)
                {
                    case MJOY_LEFT:
                    {
                        myCamera->setRotation(vector3df(myCamera->getRotation().,myCamera->getRotation().Y - 1,myCamera->getRotation().Z));
                    }
                    break;
                    case MJOY_RIGHT:
                    {
                        myCamera->setRotation(vector3df(myCamera->getRotation().,myCamera->getRotation().Y + 1,myCamera->getRotation().Z));
                    }
                    break;
                    case MJOY_UP:
                    {
                        myCamera->setRotation(vector3df(myCamera->getRotation().X - 1  ,myCamera->getRotation().Y,myCamera->getRotation().Z));
                    }
                    break;
                    case MJOY_DOWN:
                    {
                        myCamera->setRotation(vector3df(myCamera->getRotation().X + 1,myCamera->getRotation().Y,myCamera->getRotation().Z));
                    }
                    break;
                    default:
                    break;

                }

            }
            if(i == buttonBallTouchInEvent && !touchInBoutton(buttonControlBase,receiver.posX[i],receiver.posY[i])) //reset event ball
            {
                buttonBall->setRelativePosition(position2d<s32>(p1 + (buttonControlBase->getAbsolutePosition().getWidth() *0.25),
                                                                            p2 + (buttonControlBase->getAbsolutePosition().getHeight() *0.25)));

            }
            //FIN EVENT JOYSTICK

        }

        targetCamera(myCamera);

        driver->beginScene(true, true, SColor(0,200,200,200));
        smgr->drawAll();
        env->drawAll();

        driver->endScene();
    }

    device->drop();

    jvm->DetachCurrentThread();
    return;

}





Vous avez la possibilité de télécharger ce code exemple compilé avec le fichier .apk pour tester sur ce lien :

http://www.mediafire.com/download/vif90 … s-4620.zip


mes sites: www.manga-vf.fr et www.series-vf.fr

Hors ligne


#2 

25-05-2014 12:58:51

Magun
SleekThink Producer
Lieu: Punakha
Date d'inscription: 18-11-2007
Messages: 910
Corrections: 2
Site web

merci pour ce tuto wink

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
883 membres
1429 sujets
11121 messages
Dernier membre inscrit: Saidov17
64 invités en ligne
Aucun membre connecté
RSS Feed