手势识别器的用法

本文详细介绍了在游戏开发中使用libGDX框架的手势识别功能,具体讲解了手势监听器类及其功能方法,如翻页、长按、划屏、捏、缩放等,并以章节选择界面为例,展示了如何利用这些手势识别功能实现用户交互。通过自动获取屏幕分辨率,确保游戏适配不同设备。此外,还介绍了章节图片的处理方法和章节回滚机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

33.手势识别

  (2013-07-31 22:07:33)
标签: 

android开发

 

it

分类: libGDX开发教程

1.GestureListener 类

我们做章节选择这个界面的时候,第一个难点就是要解决就是屏幕的
  手势识别 
,那么如何解决这个问题呢?其实libgdx已经给我们提供了很好的方法,这就是
  GestureDetector.GestureListener ,这个其实就是libgdx自做的 手势识别器 ,他可以检测出你当前对屏幕做的操作类型,包括6种操作: 翻页 、拖拽、长按、捏、zoom(手指放大)、按下、快速点击 下面我们就来详细的讲解下,手势识别器是如何使用的。

API定义:这个类是GestureDetector的一个监听,他负责监听  触屏手势 如: 翻页 、拖拽、长按、捏、zoom(手指放大)、按下 、快速点击。每个方法返回一个布尔类型,不同的手势识别还会伴随其他几个状态的响应。

功能方法:

(1)fling(float velocityX, float velocityY, int button) 翻页动作。
        第一个参数:X 轴方向滑动的速度。
        第二个参数:Y 轴方向滑动的速度。
    第三个参数是:鼠标按键的编码,鼠标左键是 0 ,鼠标右键是 1 。 

(2)longPress(float x, float y) :长按。

     参数解释:这里面的X Y 代表 按下的手指的坐标是多少。

(3) pan(float x, float y, float deltaX, float deltaY)   划屏动作。
        第一个参数:X 轴方向滑动, 手指抬起后的X坐标
        第二个参数:Y 轴方向滑动 手指抬起后的Y坐标
        第三个参数:X 轴方向滑动的速度,矢量。
        第四个参数:Y 轴方向滑动的速度,矢量。
 
(4) pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2)   手指捏的动作。

我们在捏的动作中需要2个手指来做这个动作,我们定义其中一个手指为“起始手指”,另外一个手指为“第二手指”,来进行区分。

        第一个参数: 起始手指在滑动过程中的起始滑动的向量。
        第二个参数: 第二手指在滑动过程中的起始滑动的向量。
        第三个参数: 起始手指在进行滑动过程后,当前滑动的向量。
        第四个参数: 第二手指在进行滑动过程后,当前滑动的向量

(5) tap(float x, float y, int count, int button)  快速点击动作,即手指或鼠标,按下后迅速抬起。
        第一个参数:手指按下后的 X坐标
        第二个参数: 手指按下后的 Y坐标
        第三个参数:点击次数。
     第四个参数:进行点击操作的是鼠标左键还是右键,左键返回button为0,右键返回button为1.

(6) touchDown (float x, float y, int count, int button)     手指按下动作,不论是否手指抬起,只要手指货鼠标按下就立刻响应,tap动作执行前,它都是先执行的。
        第一个参数:手指按下后的 X坐标
        第二个参数: 手指按下后的 Y坐标
        第三个参数:点击次数。
     第四个参数:进行点击操作的是鼠标左键还是右键,左键返回button为0,右键返回button为1.

(7) zoom(float initialDistance, float distance)    手指向外分开的动作。

PS:zoom是通过计算手指放到屏幕上的 初始距离 和 当前距离 来计算要进行缩放操作的缩放比例。

        第一个参数:两手指放到屏幕时,手指之间的 初始距离
        第二个参数:两手指不进行缩放操作屏幕时,手指之间的 当前 距离


2.图文详解

(1)fling:“翻页”动作,即在滑动过程中,手指既有按下,也有抬起,事件响应效果是在手指抬起后响应

如图:

33.手势识别
(2)longPressed:“长按”动作。

如图:

33.手势识别
(3)pan:“划屏”动作。
如图:

33.手势识别
(4)pinch:“捏”的动作。

如图:

33.手势识别

(5)tap:“快速点击”的动作。

如图:

33.手势识别
(6)touchDown:“按下”的动作。

如图:

33.手势识别
(7)zoom:“放大”的动作。

如图:

33.手势识别

3.SelectScreen 类

上一篇博文,我们讲解了“保卫萝卜”的游戏入口、开始界面、加载界面的内容那么今天我们接着讲解SelectctScreen类---- 章节选择界面。本博文之前的讲解的手势识别器,也是为了这个界面做的只是铺垫,为了方便大家理解,这里就给大家先讲解了。

(1)游戏中固定常量设置。

在游戏中,我们要适应不同的分辨率的手机,那么我们就不能像以前的那样,将坐标写死,那么我们要使用什么办法来实现这个功能呢?我们可以通过让系统自动获取长宽,然后在游戏中凡事要使用坐标的地方都用自动获取的游戏宽高的比例来实现,这样就可以使用不同的设备。

如图:

33.手势识别
(2)游戏中基本成员的声明。

如图:

33.手势识别

(3)游戏中基本成员的初始化。

如图:

33.手势识别
(4)章节图片处理,这里我采用了一个技巧,我将所需的5张图片,分别命名为“1.png”“2.png”“3.png”“4.png”“5.png”,这样就可以再使用TextureAltas寻找的时候建立循环。

如图:

33.手势识别
(5)建立一个循环,将我们初始化的Region数组 赋给Image数组,同时设置下图片大小,以及章节图片坐标,同时将图片加入舞台。这里要注意的就是偏移量是要变化的,变化是有固定距离的。

如图:

33.手势识别

(6)将一个三维向量,赋值为我们游戏舞台相机的位置向量。

如图:

33.手势识别
(7)游戏内容绘制。

如图:

33.手势识别

(8)游戏章节图片回滚。这个内容我们在“保卫萝卜(三)”中详细学习,其中有很多原理,比较复杂,这里由于篇幅的关系,暂时不讲。


4.完整代码

(1)SelectScreen类中代码。

package  com. potato;

import  com.badlogic.gdx.Gdx;
import  com.badlogic.gdx.InputProcessor;
import  com.badlogic.gdx.Screen;
import  com.badlogic.gdx.audio.Sound;
import  com.badlogic.gdx.graphics.GL10;
import  com.badlogic.gdx.graphics.OrthographicCamera;
import  com.badlogic.gdx.graphics.Texture;
import  com.badlogic.gdx.graphics.g2d.SpriteBatch;
import  com.badlogic.gdx.graphics.g2d.TextureAtlas;
import  com.badlogic.gdx.graphics.g2d.TextureRegion;
import  com.badlogic.gdx.input.GestureDetector;
import  com.badlogic.gdx.input.GestureDetector.GestureListener;
import  com.badlogic.gdx.math.Vector2;
import  com.badlogic.gdx.math.Vector3;
import  com.badlogic.gdx.scenes.scene2d.Actor;
import  com.badlogic.gdx.scenes.scene2d.InputEvent;
import  com.badlogic.gdx.scenes.scene2d.InputListener;
import  com.badlogic.gdx.scenes.scene2d.Stage;
import  com.badlogic.gdx.scenes.scene2d.ui.Image;

;

public  class  selectScreen  implements  Screen,  GestureListener  {
     //游戏舞台的基本宽高
     public  static  float  GAMESTAGE_WIDTH;
     public  static  float  GAMESTAGE_HEIGHT;
    
     //游戏中选择游戏章节中,章节图标的基本宽高和摆放间隔,以及每张图片回滚速度、相机的X坐标的变化间隔
     public  static  float  CHAPTER_WIDTH;
     public  static  float  CHAPTER_HEIGHT;
    
     public  static  float  CHAPTER_INTERVAL;
     public  static  float  CHAPTER_ROLLBACKSPEED;
    
     float  disRollBack;

     float  touch_X;
     float  touch_Y;
     float  touchBaseX;
     float  touchBaseY;
     float  baseOffset;

     float  SELECT_STATE  ;
     float  SELECT_CHAPTER_FIRST  ;
     float  SELECT_CHAPTER_SECOND;
     float  SELECT_CHAPTER_THIRD;
     float  SELECT_CHAPTER_FOURTH;
     float  SELECT_CHAPTER_FIFTH;

     boolean  isRollbackIng;
     boolean  isTouching;

     SpriteBatch  batch;
     //处理使用图片打包工具打包的图片所需变量。
     TextureAtlas  pager;
     TextureRegion[]  pages;
    
     Texture  texture;
     Image[]  images;

     Stage  stage;
     MyGame  game;

     Sound  sound;
     Sound  soundSelect;

     Vector3  beforCameraPos;

     public  selectScreen(MyGame  game)  {
           this. game  game;
     }

     @Override
     public  void  show()  {

           GAMESTAGE_WIDTH  Gdx. graphics. getWidth();
           GAMESTAGE_HEIGHT  Gdx. graphics. getHeight();

           CHAPTER_WIDTH  GAMESTAGE_WIDTH  0.625f;
           CHAPTER_HEIGHT  GAMESTAGE_HEIGHT  0.7f;
           CHAPTER_INTERVAL  GAMESTAGE_WIDTH  0.375f;
           CHAPTER_ROLLBACKSPEED  GAMESTAGE_WIDTH  50;

           batch  new  SpriteBatch();
           texture  new  Texture(Gdx. files. internal( "data/bg.png"));
           sound  Gdx. audio. newSound(Gdx. files. internal( "data/MenuSelect.ogg"));
           soundSelect  Gdx. audio. newSound(Gdx. files. internal( "data/Select.ogg"));

           stage  new  Stage(GAMESTAGE_WIDTH,  GAMESTAGE_HEIGHT,  false);
          
           Gdx. input. setInputProcessor( new  GestureDetector( this));

           pages  new  TextureRegion[ 5];
           images  new  Image[ 5];
           pager  new  TextureAtlas(Gdx. files. internal( "data/potato.pack"));
           //设置基准偏移量
           baseOffset  (GAMESTAGE_WIDTH  CHAPTER_WIDTH)  2;
           float  offset  baseOffset;

           for  ( int  0pages. lengthi++)  {
                 //通过名字,找到用texturePacker处理的图片
                 pages[i]  pager. findRegion((i  1 "");
                 //将对应名字的图片赋给images数组中对象的成员
                 images[i]  new  Image(pages[i]);
                 //设置image的大小和位置。
                 images[i]. setSize(GAMESTAGE_WIDTH,  GAMESTAGE_HEIGHT);
                 images[i]. setPosition(offset,-(GAMESTAGE_HEIGHT  CHAPTER_HEIGHT)  2);
                 //这个offset是每次都加一个“章节间隔距离,出去章节图片的宽度游戏剩下的距离 ”
                 offset  +=  CHAPTER_INTERVAL  GAMESTAGE_WIDTH  CHAPTER_WIDTH;
                 //将image加入舞台。
                 stage. addActor(images[i]);
           }
           beforCameraPos  new  Vector3(stage. getCamera(). position);
          
     }

     public  void  update()  {
           // justTouched 是开始按下手指的第一个点。
           if  (Gdx. input. justTouched()  &&  isTouching  ==  false{
                 isTouching  true;
                 touchBaseX  Gdx. input. getX( 0);
                 touchBaseY  Gdx. input. getY( 0);

                 touchBaseX  +=  stage. getCamera(). position. x  GAMESTAGE_WIDTH  2;

                 // isTouched 是结束时,手指按下的点。
           else  if  (Gdx. input. isTouched( 0&&  isTouching  ==  true{
                 touch_X  Gdx. input. getX( 0);
                 touch_Y  Gdx. input. getY( 0);
                 // 滑动相机,相机的移动是和手指移动相反的,手指右滑,是为了看左面。
                 stage. getCamera(). position. set(touchBaseX  touch_X
                             beforCameraPos. xbeforCameraPos. ybeforCameraPos. z);

           else  {
                 isTouching  false;
                 if  (isRollbackIng  ==  false{
                       rollBackPre();
                 else  {
                       rollBack();
                 }
           }
     }

     private  void  rollBackPre()  {
           float  camX  stage. getCamera(). position. x;
           disRollBack  camX  (images[ 0]. getX()  CHAPTER_WIDTH  2);

           // 计算距离手指结束位置最近的章节图片是哪个
           for  ( int  1images. lengthi++)  {
                 float  temp  camX  (images[i]. getX()  CHAPTER_WIDTH  2);
                 if  (Math. abs(temp)  Math. abs(disRollBack))  {
                       disRollBack  temp;
                 }
           }
           isRollbackIng  true;

     }


     private  void  rollBack()  {
           float  temDis  disRollBack  Gdx. graphics. getDeltaTime()
                       CHAPTER_ROLLBACKSPEED;
           stage. getCamera(). position. x  -=  temDis;
           disRollBack  -=  temDis;
           if  (Math. abs(disRollBack)  0.1{
                 stage. getCamera(). position. x  -=  disRollBack;
                 isRollbackIng  false;

           }
     }

     @Override
     public  void  render( float  delta)  {
           Gdx. gl. glClear(GL10. GL_COLOR_BUFFER_BIT);
           update();

           batch. begin();
           batch. draw(texture,  0 0GAMESTAGE_WIDTH,  GAMESTAGE_HEIGHT);
           batch. end();
           stage. act();
           stage. draw(); 

     }

     @Override
     public  void  resize( int  width,  int  height)  {
           // TODO Auto-generated method stub

     }

     @Override
     public  void  hide()  {
           // TODO Auto-generated method stub

     }

     @Override
     public  void  pause()  {
           // TODO Auto-generated method stub

     }

     @Override
     public  void  resume()  {
           // TODO Auto-generated method stub

     }

     @Override
     public  void  dispose()  {
           // TODO Auto-generated method stub

     }

     @Override
     public  boolean  touchDown( float  x,  float  y,  int  pointer,  int  button)  {
           // TODO Auto-generated method stub
           return  true;
     }

     @Override
     public  boolean  tap( float  x,  float  y,  int  count,  int  button)  {
          
           soundSelect. play( 15f);
          
           //相机位置 ,以及选择状态的判定。
           SELECT_STATE  stage. getCamera(). position. x;
           SELECT_CHAPTER_FIRST  GAMESTAGE_WIDTH  0.5f;
           SELECT_CHAPTER_SECOND  GAMESTAGE_WIDTH  1.25f;
           SELECT_CHAPTER_THIRD  GAMESTAGE_WIDTH  2.0f;
           SELECT_CHAPTER_FOURTH  GAMESTAGE_WIDTH  2.75f;
           SELECT_CHAPTER_FIFTH  GAMESTAGE_WIDTH  3.5f;
                      
           if(SELECT_STATE  ==  SELECT_CHAPTER_FIRST)  {
                 gameScreen. CHAPTER_COUNT  1;
                 game. setScreen(game. gamescreen);
           } else  if  (SELECT_STATE  ==  SELECT_CHAPTER_SECOND)  {
                 gameScreen. CHAPTER_COUNT  2;
                 game. setScreen(game. gamescreen);
           } else  if  (SELECT_STATE  ==  SELECT_CHAPTER_THIRD)  {
                 gameScreen. CHAPTER_COUNT  3;
                 game. setScreen(game. gamescreen);
           } else  if  (SELECT_STATE  ==  SELECT_CHAPTER_FOURTH)  {
                 gameScreen. CHAPTER_COUNT  4;
                 game. setScreen(game. gamescreen);
           } else  if  (SELECT_STATE  ==  SELECT_CHAPTER_FIFTH)  {
                 gameScreen. CHAPTER_COUNT  5;
                 game. setScreen(game. gamescreen);
           }
           return  false;
     }

     @Override
     public  boolean  longPress( float  x,  float  y)  {
           // TODO Auto-generated method stub
           return  false;
     }

     @Override
     public  boolean  fling( float  velocityX,  float  velocityY,  int  button)  {
           // TODO Auto-generated method stub

           sound. play( 15f);
           return  false;
     }

     @Override
     public  boolean  pan( float  x,  float  y,  float  deltaX,  float  deltaY)  {
           // TODO Auto-generated method stub
           return  false;
     }

     @Override
     public  boolean  zoom( float  initialDistance,  float  distance)  {
           // TODO Auto-generated method stub
           return  false;
     }

     @Override
     public  boolean  pinch(Vector2  initialPointer1,  Vector2  initialPointer2,
                 Vector2  pointer1,  Vector2  pointer2)  {
           // TODO Auto-generated method stub
           return  false;
     }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值