【ANDROID游戏开发十七】让玩家自定义手势玩转ANDROID游戏!—ANDROID GESTURE之【输入法手势技术】

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 
转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/340.html

———————————————————————

多童鞋说我的代码运行后,点击home或者back后会程序异常,如果你也这样遇到过,那么你肯定没有仔细读完Himi的博文,第十九篇Himi专门写了关于这些错误的原因和解决方法,这里我在博客都补充说明下,省的童鞋们总疑惑这一块;请点击下面联系进入阅读:

【Android游戏开发十九】(必看篇)SurfaceView运行机制详解—剖析Back与Home按键及切入后台等异常处理! 』

——————————————————————-

有童鞋问我为什么不用SDK2.1 ,2.2来进行游戏开发,那我这里稍微说两句:

1.Android SDK 属于向下兼容!那么低版本可以运行的,高版本基本上更是没问题!(当然每次SDK的更新也会带来新功能,或者修改了一些原来的BUG等等,那么其实对于游戏开发来说,如果你的游戏中不需要更高的SDK版本的支持情况下,完全不必去追求最新的SDK!)

2.使用低版本进行游戏开发这样能兼顾更多的机型,获取更多的用户!

3.大家都知道Android SDK 每次版本的更新,底层代码也会更健壮和优化了!比如我们公司的网游Android版在G2(SDK1.5)上跑起来稍微有些卡,而在我的手机上(SDK2.2)运行起来流畅的没说的~各种舒坦~~但是这样也会带来一些弊端,比如我们自己游戏如果上来就用高版本SDK进行开发,那么对于性能、内存上到底如何,我们都不会很容易的看出其效果,如果我们用低版本的SDK则会让我们明显的感受到性能到底如何~你想想如果你的游戏在1.5 ,1.6上跑起来很流畅,那放在更高版本的SDK机器上更是没说的啦~

总结:游戏开发中,如果你游戏不需要更高的API的支持,那么推荐基于SDK 1.5和1.6来开发!

在上一篇中我给大家介绍了触摸屏手势操作,但是这种触屏手势的操作比较有局限性;比如我们都知道Android可以利用手势来解锁,比如九宫格形式的,通过自定义的一个单笔画手势可以解开屏幕锁,还可以自定义笔画手势来启动一个应用等,那么这种所谓的笔画手势其实就是今天我要给大家讲解的输入法手势识别技术!这种手势是我们可以自己来自定义,而不像之前的触屏手势操作只是利用Android 对一些触屏动作的封装罢了。下面上几张手机自定义笔划手势解锁的的截图:

OK,那么既然利用手势既然能进行解锁等操作,那么我们游戏开发中,更是可以加入这一亮点了,比如在游戏中我画个圆形执行换背景操作,画个X表示退出游戏等等,等等、哈哈 是不是感觉很有意思了?好的,下面就开始进入讲解!

首先本篇主要学习两点:

     1. 如何创建输入法手势、删除输入法手势、从SD卡中读取出手势文件!

     2.当输入法手势创建后,如何来匹配出我们的自定义手势!

下面我们来熟习两个类和几个概念:

1. 什么是 GestureOverlayView ?  简单点说其实就是一个手写绘图区;

2. 什么是 GestureLibrary ?   这个类是对手势进行保存、删除等操作的,一个存放手势的小仓库!

3. 笔划是什么,字体笔画?  是的,其实就是跟我们写字的笔划一个概念!

4.什么是笔类型?   输入法手势操作中,笔划类型有两种;一种是:单一笔划,另外一种是:多笔划

    所谓单一笔划笔划就是一笔划画出一个手势,从你手指接触屏幕开始到你离开屏幕笔画就会立刻形成一个手势!一气呵成!

    而多笔划则是可以在一定紧凑时间内随意几笔划都可!然后超过这个紧凑时间后便会形成一个手势!

先出项目截图,简单说下其功能和操作:

图1界面中分为3块,从上到下依次是:TextView ,EditText,SurfaceView;然后在SurfaceView后面还有一个覆盖全屏的GestureOverlayView!

图2界面是在创建好的手势中匹配手势的界面,这里很清晰看出来,找的很对 ~嘿嘿~

先看下main.xml:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical" android:layout_width="fill_parent"

    android:layout_height="fill_parent">

    <TextView android:id="@+id/himi_tv" android:layout_width="fill_parent"

        android:layout_height="wrap_content" android:text="@string/hello"

        android:textSize="15sp" android:textColor="#FFFFFF00" />

    <EditText android:id="@+id/himi_edit" android:layout_width="fill_parent"

        android:layout_height="wrap_content" />

    <RelativeLayout android:layout_width="fill_parent"

        android:layout_height="wrap_content" android:layout_weight="1">

        <com.himi.MySurfaceView android:id="@+id/view3d"

            android:layout_width="fill_parent" android:layout_height="fill_parent" />

        <android.gesture.GestureOverlayView

            android:id="@+id/himi_gesture" android:layout_width="fill_parent"

            android:layout_height="fill_parent" android:layout_weight="1.0"/>

    </RelativeLayout>

</LinearLayout>

xml中注册的有我们自定义的surfaceview,对此不太熟悉可以去看下【Android2D开发之六】,不多解释了。关于GestureOverlayView这里也只是简单的定义了宽高,还有一些重要的属性设置在代码中设置了,当然xml也可以设置的;

下面看MainActivity.java

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

**

*@author Himi

*@输入法手势识别

*@注意: android.gesture这个类在api-4(SDK1.6)才开始支持的!

*@提醒:默认存到SD卡中,所以别忘记在AndroidMainfest.xml加上SD卡读写权限!

*/

public class MainActivity extends Activity {

    private GestureOverlayView gov;// 创建一个手写绘图区

    private Gesture gesture;// 手写实例

    private GestureLibrary gestureLib;//创建一个手势仓库

    private TextView tv;

    private EditText et;

    private String path;//手势文件路径

    private File file;//

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        this.requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.main);

        tv = (TextView) findViewById(R.id.himi_tv);

        et = (EditText) findViewById(R.id.himi_edit);

        gov = (GestureOverlayView) findViewById(R.id.himi_gesture);

        gov.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);//设置笔划类型

        // GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE 设置支持多笔划

        // GestureOverlayView.GESTURE_STROKE_TYPE_SINGLE 仅支持单一笔划

        path = new File(Environment.getExternalStorageDirectory(), "gestures").getAbsolutePath();

        //得到默认路径和文件名/sdcard/gestures

        file = new File(path);//实例gestures的文件对象

        gestureLib = GestureLibraries.fromFile(path);//实例手势仓库

        gov.addOnGestureListener(new OnGestureListener() { // 这里是绑定手写绘图区

                    @Override

                    // 以下方法是你刚开始画手势的时候触发

                    public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {

                        tv.setText("请您在紧凑的时间内用两笔划来完成一个手势!西西~");

                    }

                    @Override

                    // 以下方法是当手势完整形成的时候触发

                    public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {

                        gesture = overlay.getGesture();// 从绘图区取出形成的手势

                        if (gesture.getStrokesCount() == 2) {//我判定当用户用了两笔划

                            //(强调:如果一开始设置手势笔画类型是单一笔画,那你这里始终得到的只是1!)

                            if (event.getAction() == MotionEvent.ACTION_UP) {//判定第两笔划离开屏幕

                                //if(gesture.getLength()==100){}//这里是判定长度达到100像素

                                if (et.getText().toString().equals("")) {

                                    tv.setText("由于您没有输入手势名称,so~保存失败啦~");

                                } else {

                                    tv.setText("正在保存手势...");

                                    addGesture(et.getText().toString(), gesture);//我自己写的添加手势函数

                                }

                            }

                        } else {

                            tv.setText("请您在紧凑的时间内用两笔划来完成一个手势!西西~");

                        }

                    }

                    @Override

                    public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {

                    }

                    @Override

                    public void onGesture(GestureOverlayView overlay, MotionEvent event) {

                    }

                });

        //----这里是在程序启动的时候进行遍历所有手势!------

        if (!gestureLib.load()) {

            tv.setText("Himi提示:手势超过9个我做了删除所有手势的操作,为了界面整洁一些!"

                    + " 输入法手势练习~(*^__^*)~ 嘻嘻!/n操作介绍:(画手势我设置必须画两笔划才行哦~)/n1." +

                            "添加手势:先EditText中输入名称,然后在屏幕上画出手势!/n2.匹配手势:"

                    + "在EditText输入/"himi/",然后输入手势即可! ");

        } else {

            Set<String> set = gestureLib.getGestureEntries();//取出所有手势

            Object ob[] = set.toArray();

            loadAllGesture(set, ob);

        }

    }

}

这个就是MainActivity主要代码了,其中添加手势、匹配手势、遍历手势、将手势转成图片这些我都单独写成了函数,这样让各位童鞋更清晰思路一些。

从以上代码中我们看出在创建手势之前,手写绘图区(GestureOverlayView)肯定先被创建出来,然后我们就可以在其区域中进行笔划绘画手势了,当然绘画手势前,我们也需要设置了笔划类型,也就是我一开始给大家介绍的~其后最重要的就是手写绘图区的手势监听器绑定,增加OnGestureListener这个监听器重写了四个函数,这里最重要的就两个函数:

onGestureStarted   和  onGestureEnded  ; 手势开始和手势结束的监听函数!

尤其是手势结束监听这个函数尤为重要,在其中我设置好几个条件语句,这么几个条件一方面是让大家了解Gesture中一些比较重要常用的方法,另一方面我要提醒各位童鞋:

如果你设置笔划类型是多笔划类型的,那么理想状态下,应该是在一段紧凑时间内,不管你使用了几笔划来绘制手势,系统都应该在判定你在一定短暂时间内没有再进行笔划的时候才应该创建手势,并且系统响应此函数;

其实错了,一开始我也这么想,但是发现,不管你设置的笔划类型是单一的还是多笔划当你手指离开屏幕,不管你当前是第几笔,Android都会去响应这个完成函数,so~ 我在这里调用手势Gesture类中的getStrokesCount()函数,这个函数会记录在紧凑时间内你绘制手势的笔划数,那么根据这个函数我们就可以解决手指离开屏幕总被响应的问题了,因为单一笔划类型永远这个值不会大于1!

而 if (event.getAction() == MotionEvent.ACTION_UP) {}写这个只是给大家演示第二个参数按键动作该怎么用;

那么我们下面就来看如何创建一个手势:

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

public void addMyGesture(String name, Gesture gesture) {

        try {

            if (name.equals("himi")) {

                findGesture(gesture);

            } else {

                // 关于两种方式创建模拟器的SDcard在【Android2D游戏开发之十】有详解

                if (Environment.getExternalStorageState() != null) {// 这个方法在试探终端是否有sdcard!

                    if (!file.exists()) {// 判定是否已经存在手势文件

                        // 不存在文件的时候我们去直接把我们的手势文件存入

                        gestureLib.addGesture(name, gesture);

                        if (gestureLib.save()) {////保存到文件中

                            gov.clear(true);//清除笔画

                            // 注意保存的路径默认是/sdcard/gesture ,so~别忘记AndroidMainfest.xml加上读写权限!

                            // 这里抱怨一下,咳咳、其实昨天就应该出这篇博文的,就是因为这里总是异常,今天仔细看了

                            // 才发现不是没写权限,而是我虽然在AndroidMainfest.xml中写了权限,但是写错了位置..哭死!

                            tv.setText("保存手势成功!因为不存在手势文件," + "所以第一次保存手势成功会默认先创" +

                                    "建了一个手势文件!然后将手势保存到文件中.");

                            et.setText("");

                            gestureToImage(gesture);

                        } else {

                            tv.setText("保存手势失败!");

                        }

                    } else {//当存在此文件的时候我们需要先删除此手势然后把新的手势放上

                        //读取已经存在的文件,得到文件中的所有手势

                        if (!gestureLib.load()) {//如果读取失败

                            tv.setText("手势文件读取失败!");

                        } else {//读取成功

                            Set<String> set = gestureLib.getGestureEntries();//取出所有手势

                            Object ob[] = set.toArray();

                            boolean isHavedGesture = false;

                            for (int i = 0; i < ob.length; i++) {//这里是遍历所有手势的name

                                if (((String) ob[i]).equals(name)) {//和我们新添的手势name做对比

                                    isHavedGesture = true;

                                }

                            }

                            if (isHavedGesture) {//如果此变量为true说明有相同name的手势

//----备注1-------------------//gestureLib.removeGesture(name, gesture);//删除与当前名字相同的手势

/*----备注2-----------------*/gestureLib.removeEntry(name);

                                gestureLib.addGesture(name, gesture);

                            } else {

                                gestureLib.addGesture(name, gesture);

                            }

                            if (gestureLib.save()) {

                                gov.clear(true);//清除笔画

                                gestureToImage(gesture);

                                tv.setText("保存手势成功!当前所有手势一共有:" + ob.length + "个");

                                et.setText("");

                            } else {

                                tv.setText("保存手势失败!");

                            }

                            ////------- --以下代码是当手势超过9个就全部清空 操作--------

                            if (ob.length > 9) {

                                for (int i = 0; i < ob.length; i++) {//这里是遍历删除手势

                                    gestureLib.removeEntry((String) ob[i]);

                                }

                                gestureLib.save();

                                if (MySurfaceView.vec_bmp != null) {

                                    MySurfaceView.vec_bmp.removeAllElements();//删除放置手势图的容器

                                }

                                tv.setText("手势超过9个,已全部清空!");

                                et.setText("");

                            }

                            ob = null;

                            set = null;

                        }

                    }

                } else {

                    tv.setText("当前模拟器没有SD卡 - -。");

                }

            }

        } catch (Exception e) {

            tv.setText("操作异常!");

        }

    }

这里也都很好理解,套路类似之前File文件存储的套路,先判断SD是否存在,然后是文件是否存在:

如果文件不存在就先直接添加到手势到手势仓库中,然后手势仓调用gestureLib.save()才算把手势存到SD卡的手势文件中。

文件存在的话还要去判定是否文件中包含了相同名字的手势;当然这里可以不判定是否有相同手势名存在,然后进行删除操作!其实也可不删除,直接添加进去当前新建的手势;原因看了下面的备注解释就明白了;

备注 1:因为gestureLib保存的手势是个HashMap, key=手势的名字,value=手势,所以gestureLib.removeGesture(name, gesture);这种删除方式只是删除了手势,该手势名字依旧保存在hashmap中,下次还有相同的name手势存入的时候Hashmap就直接覆盖本条目了。所以根据Hashmap的特征,我们可以不进行删除操作,可以直接gestureLib.addGesture(name, gesture);因为如果出现相同的手势名字的手势,Hashmap就会根据key(手势的名字)直接覆盖其条目的value(手势)滴~

备注2 :这里也是一种删除手势的方式,但是这种方式跟备注1的不同,这里是将Hashmap中的条目删除,也就是说key和value都被删去!

下面看下如何把手势转成bitmap!

1

2

3

4

5

6

public void gestureToImage(Gesture ges) {//将手势转换成Bitmap

        //把手势转成图片,存到我们SurfaceView中定义的Image容器中,然后都画出来~

        if (MySurfaceView.vec_bmp != null) {

            MySurfaceView.vec_bmp.addElement(ges.toBitmap(100, 100, 12, Color.GREEN));

        }

    }

下面是如何遍历手势!

1

2

3

4

5

6

7

8

9

10

11

12

public void loadAllGesture(Set<String> set, Object ob[]) { //遍历所有的手势

        if (gestureLib.load()) {//读取最新的手势文件

            set = gestureLib.getGestureEntries();//取出所有手势

            ob = set.toArray();

            for (int i = 0; i < ob.length; i++) {

                //把手势转成Bitmap

                gestureToImage(gestureLib.getGestures((String) ob[i]).get(0));

                //这里是把我们每个手势的名字也保存下来

                MySurfaceView.vec_string.addElement((String) ob[i]);

            }

        }

    }

下面最后来看看手势的匹配!

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

public void findGesture(Gesture gesture) {

    try {

        // 关于两种方式创建模拟器的SDcard在【Android2D游戏开发之十】有详解

        if (Environment.getExternalStorageState() != null) {// 这个方法在试探终端是否有sdcard!

            if (!file.exists()) {// 判定是否已经存在手势文件

                tv.setText("匹配手势失败,因为手势文件不存在!!");

            } else {//当存在此文件的时候我们需要先删除此手势然后把新的手势放上

                //读取已经存在的文件,得到文件中的所有手势

                if (!gestureLib.load()) {//如果读取失败

                    tv.setText("匹配手势失败,手势文件读取失败!");

                } else {//读取成功

                    List<Prediction> predictions = gestureLib.recognize(gesture);

                    //recognize()的返回结果是一个prediction集合,

                    //包含了所有与gesture相匹配的结果。

                    //从手势库中查询匹配的内容,匹配的结果可能包括多个相似的结果,

                    if (!predictions.isEmpty()) {

                        Prediction prediction = predictions.get(0);

                        //prediction的score属性代表了与手势的相似程度

                        //prediction的name代表手势对应的名称

                        //prediction的score属性代表了与gesture得相似程度(通常情况下不考虑score小于1的结果)。

                        if (prediction.score >= 1) {

                            tv.setText("当前你的手势在手势库中找到最相似的手势:name =" + prediction.name);

                        }

                    }

                }

            }

        } else {

            tv.setText("匹配手势失败,,当前模拟器没有SD卡 - -。");

        }

    } catch (Exception e) {

        e.printStackTrace();

        tv.setText("由于出现异常,匹配手势失败啦~");

    }

}

那么最后给各位童鞋说一下,其实输入法手势操作很是适合游戏中使用,不管是触摸屏手势操作还是今天讲的输入法手势操作如果加到游戏中那都是相当赞的!但是我们公司网游引擎和框架不适合插入手势 – -、唉~

其实前两天应该发这篇的,但是因为工作忙了几天,让大家久等了,挺不好意思的,所以今天熬夜给大家写了出来,现在都凌晨 7:00 了~

   源码下载:   “输入法手势识别.rar”       下载地址: http://vdisk.weibo.com/s/hq3f2

时间: 2024-11-03 03:59:30

【ANDROID游戏开发十七】让玩家自定义手势玩转ANDROID游戏!—ANDROID GESTURE之【输入法手势技术】的相关文章

【ANDROID游戏开发二十三】自定义LISTVIEW【通用】适配器并实现监听控件!

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/374.html  ListView :在Android应用开发过程中属于最常用的系统组件之一,当然可能童鞋们问为什么会突然游戏开发中讲这个,呵呵,其实在游戏开发中,也会常常使用到系统组件,比如游戏排行榜,简单的游戏关卡选择等等,都可以来使用ListView来实现:     当然关于ListView我想大家都会使用了

android浏览器开发,地址栏用什么组件怎样设置成当获得焦点时输入法中有“前往”或“搜索”键

问题描述 android浏览器开发,地址栏用什么组件怎样设置成当获得焦点时输入法中有"前往"或"搜索"键 想用android写一个android浏览器的小DEMO,地址栏用的原生EDITTEXT组件,说到这里那么问题来了..在EDITTEXT中输入完毕之后,弹出的输入法中没有"前往"或者"搜索"键,网上下载的浏览器比如UC浏览器,地址栏输入后键盘上都有有一个"前往"按钮.这种情况应该如何设置? 解决方案 我

Android简明开发教程十一:自定义Adapter显示列表

在介绍数据绑定时,我们使用了系统自带的SimpleAdapter.Android 允许自定义Adapter ,理论上可以使用任意的View (Layout)来显示数据.下图是对AndroidGraphics2DTutorial做改动,使用自定义Adapter来显示示例Activity列表. 开发教程十一:自定义Adapter显示列表-"> 在例子中我们把原来的AndroidGraphics2DTutorial改名为AndroidGraphics2DTutorial1,重新创建一个类 And

【游戏开发备注之一】关于COCOS2DX_V1.X版本IPHONE与ANDROID运行出现图片白块、添加GAMECENTER报错问题及编译ANDROID闪退的解决办法&&CCLOG与CCLOG的区别

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/1035.html 今天备注几个童鞋们可能会遇到的问题: 1. 关于Cocos2dx v1.x版本运行在iphone与Android平台出现图片变白块,尺寸一样.图片纯白问题. 之前出现此问题原因如下: 1.1  CCSprite与CCNode强转之间的问题造成: 1.2  pvr.ccz的资源大小宽高不是正方形的话

《OpenGL ES 3.x游戏开发(上卷)》一1.3 Hello Android应用程序的开发

1.3 Hello Android应用程序的开发 本节首先将介绍如何在Eclipse中创建一个基于Android的Hello World应用程序,之后将简单介绍Android应用程序的调试,为读者以后学习高级开发铺平道路. 1.3.1 第一个Android应用程序 本小节将向读者介绍如何在Eclipse中创建一个基于Android的Hello World应用程序,基本步骤如下所列. (1)单击eclipse.exe,启动Eclipse,依次选择"File/New/ Android Applica

【IOS-COCOS2D-X 游戏开发之十】自定义CCSPRITE/LAYER/CCNODE及静态类模版&自定义类细节说明&COCOS2DX触屏事件讲解

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2dx/699.html 这里Himi又来了一篇基础篇-..不是因为充博文数量,而是Cocos2dX一个超级群里不少童鞋都有问过很基础的问题,Himi估计这些童鞋要么之前对C++不熟悉,要么就是之前没有接触过Cocos2d,而直接转入了Cocos2dx的开发行列中仂,这里首先给这些童鞋三个建议: 1. Cocos2dx

《OpenGL ES 3.x游戏开发(上卷)》一第2章 游戏开发相关的 Android基础知识

第2章 游戏开发相关的 Android基础知识 OpenGL ES 3.x游戏开发(上卷)虽然本书主要是介绍OpenGL ES 3.0 3D应用及游戏开发的,但由于很多3D游戏应用中还需要用到目标平台的一些其他应用开发方面的知识,而本书3D基础知识部分主要是借助于Android平台来介绍OpenGL ES 3.0 3D应用及游戏开发的.故本章将向读者简要介绍一些在Android游戏开发中必备的一些基础知识,如音效.文件的读取.游戏信息的存储.Socket网络.蓝牙网络等. 提示 由于介绍Andr

《OpenGL ES 3.x游戏开发(上卷)》一1.2 搭建Android开发环境

1.2 搭建Android开发环境 对Android开发稍有了解的读者都知道,Android应用程序的开发一般是使用Eclipse进行.Eclipse是一款开放源代码.基于Java的可扩展开发平台.其包括一个框架和一组服务,主要通过插件来构建开发环境.本节主要介绍如何搭建基于Eclipse的Android开发环境,同时也将介绍模拟器的创建和运行等相关知识. 1.2.1 JDK的安装及环境变量的配置 JDK是整个Java开发的核心工具包,其包括了Java运行环境.Java开发工具和Java基础类库

《OpenGL ES 3.x游戏开发(上卷)》一2.1 游戏中的音效

2.1 游戏中的音效 一款好游戏,除了具备优质的画面和较高的可玩性之外,还应该有出色的音效.音效一般指的是游戏中发生特定行为或进行特定操作时播放的效果音乐或为了渲染整体气氛播放的背景音乐等,如远处隆隆的炮声.由远而近的脚步声等. 开发人员通过精心准备的声音特效,并结合游戏酷炫的场景,可以渲染出一种紧张刺激的氛围,使玩家产生身临其境的感觉.这就像电影中的声音特效一样,假如没有了合适的音效,那么游戏和电影一样,真实感会大打折扣. 提示 按照作用的不同,可以将音效划分为即时音效和背景音乐.两种音效在A