登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

查看: 1484414|回复: 185

Android游戏开发之摄像头的原理以及更新 (五)

  [复制链接]

249

主题

278

帖子

17

安币

初级码农

Rank: 1

发表于 2011-9-2 22:26:19 | 显示全部楼层 |阅读模式
带你走进游戏开发的世界之摄像头的原理以及更新

游戏中摄像头的原理介绍

       在游戏开发中更新摄像头的位置可以决定屏幕显示的内容,尤其是RPG类游戏摄像头有着非常重要的作用,我举一个例子 有时候我们在玩RPG游戏的时候进入一个新的场景 触发一段脚本后 发现镜头开始向上移动 根据镜头移动玩家可以大概浏览一下这个场景有什么东西 ,触发什么样的剧情。这个实现的方式就是游戏摄像头原理。


如图所示:首先摄像头显示的区域也是手机屏幕显示的区域 如果需要更改摄像头的位置  其实是更改背景地图的位置 利用程序拖动背景地图  给玩家一种假象让玩家感觉像是摄像头在移动而不是背景地图在移动。

游戏中地图的绘制原理介绍

       根据地图编辑器生成的出来的数组的每一个tile 的 ID 找到每一个tile的地图资源原始文件的XY坐标 算出来图片的显示位置利用程序的切割的方法把每一个tile切割出来显示在手机屏幕中。

切割图片的代码所示:
  1.         /**
  2.          * 绘制图片中的一部分图片
  3.          *
  4.          * @param canvas
  5.          * @param paint
  6.          * @param bitmap
  7.          * @param x
  8.          * @param y
  9.          * @param src_x
  10.          * @param src_y
  11.          * @param src_width
  12.          * @param src_Height
  13.          */
  14.         private void DrawClipImage(Canvas canvas, Paint paint, Bitmap bitmap,
  15.                 int x, int y, int src_x, int src_y, int src_xp, int src_yp) {
  16.             canvas.save();
  17.             canvas.clipRect(x, y, x + src_xp, y + src_yp);
  18.             canvas.drawBitmap(bitmap, x - src_x, y - src_y, paint);
  19.             canvas.restore();
  20.         }
复制代码
canvas.save();
切割图片之前先把Canvas保存起来 然后在切割  绘制结束后
canvas.restore();
在把Canvas的在状态重置回来 如果不这么做的话 第一张图片切割后就会挡住以后所有的图片,所以大家一定要记住这一点喔。

       如图所示:每一张tile的绘制原理就是这样,说到这里有些朋友可能就要问 如果我的地图无限大那根据这个方法岂不是要循环无限次?其实屏幕须要绘制的tile数量只需要绘制屏幕显示区域以内的, 屏幕现实区域以外的我们不用考虑绘制 只需要更新地图的坐标数据就可以,比如我的模拟器屏幕的大小是320X480 那么我实际绘制的tile数量只是 10 X15 (块)。其实游戏开发绘制中还有一个更重要的绘制技术就是双缓冲技术它可以用来解决屏幕闪烁问题,下一章中我会详细介绍。

        
       昨天有朋友跟我提出这种用数组的方式来绘制地图不科学我很同意他的观点,为什么不科学? 原因是现在我们只有一个场景我们用一个数组来绘制地图 万一我们的游戏有100个场景 我们岂不是要在程序中写100个数组了?其实在实际开发中我们是把这些地图的信息转成xml文件 打到游戏的包中 玩家在切换游戏场景的时候便会读取当前游戏场景中的地图xml文件。其实这些xml文件中也是保存这地图的二位数组信息 但是这样做的好处就是数据驱动  程序员不用定义N个数组 做N种判断 只须要根据当前切换的场景的ID就可以得到地图的信息 十分方便 也可以避免代码中由于笔误造成的的错误 何乐而不为。

       但是不管用任何方法处理数据 它的绘制原理都是一样的。

如何更新游戏中摄像头

效果图:程序取随机数更新游戏摄像头



        目前以每10000毫秒更新一下摄像头的位置 (随机数) 我们有了摄像头的位置以后 就可以在算出背景图片的相对显示位置 移动背景图片的位置后就可以给玩家制造出一种摄像头在移动的假象了。

             地图块是我新拼的 长宽的tile块数是20X20。
  1. package cn.m15.xys;

  2. import java.io.InputStream;
  3. import java.util.Random;


  4. import android.app.Activity;
  5. import android.content.Context;
  6. import android.content.res.Resources;
  7. import android.graphics.Bitmap;
  8. import android.graphics.BitmapFactory;
  9. import android.graphics.Canvas;
  10. import android.graphics.Color;
  11. import android.graphics.Paint;
  12. import android.os.Bundle;
  13. import android.view.Display;
  14. import android.view.View;
  15. import android.view.Window;
  16. import android.view.WindowManager;

  17. public class CameraAcitvity extends Activity {

  18.     MapView mMapView = null;
  19.     @Override
  20.     public void onCreate(Bundle savedInstanceState) {
  21.         super.onCreate(savedInstanceState);
  22.         // 全屏显示窗口
  23.         requestWindowFeature(Window.FEATURE_NO_TITLE);
  24.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  25.                 WindowManager.LayoutParams.FLAG_FULLSCREEN);
  26.         // 获取屏幕宽高
  27.         Display display = getWindowManager().getDefaultDisplay();
  28.         // 显示自定义的游戏View
  29.         mMapView = new MapView(this,display.getWidth(), display.getHeight());
  30.         setContentView(mMapView);
  31.     }

  32.     public class MapView extends View {

  33.         // tile块的宽高
  34.         public final static int TILE_WIDTH = 32;
  35.         public final static int TILE_HEIGHT = 32;

  36.         // tile块的宽高的数量
  37.         public final static int TILE_WIDTH_COUNT = 20;
  38.         public final static int TILE_HEIGHT_COUNT = 20;

  39.         // 地图的宽高的
  40.         public final static int MAP_WIDTH = 640;
  41.         public final static int MAP_HEIGHT = 640;
  42.        
  43.         //镜头移动范围
  44.         public final static int CAMERA_MOVE = 10;
  45.        
  46.         // 屏幕的宽高
  47.         public int mScreenWidth = 0;
  48.         public int mScreenHeight = 0;
  49.        
  50.         // 数组元素为0则什么都不画
  51.         public final static int TILE_NULL = 0;
  52.         // 第一层游戏View地图数组
  53.         public int[][] mMapView = {
  54.                 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1,
  55.                         1, 1, 1 },
  56.                 { 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 1, 1, 1,
  57.                         1, 1, 1, 1 },
  58.                 { 1, 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1,
  59.                         1, 1, 1 },
  60.                 { 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 137, 1, 1,
  61.                         1, 1, 1, 1, 1 },
  62.                 { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137,
  63.                         137, 137, 137, 137, 137, 1, 1, 1 },
  64.                 { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137,
  65.                         137, 137, 137, 137, 137, 1, 1, 1 },
  66.                 { 137, 137, 137, 1, 1, 137, 137, 137, 137, 137, 137, 137, 137,
  67.                         137, 137, 137, 1, 1, 1, 1 },
  68.                 { 1, 137, 137, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 137,
  69.                         137, 137, 137, 1, 137, 1 },
  70.                 { 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 137,
  71.                         137, 137, 137, 137, 1 },
  72.                 { 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 1, 1, 1, 137, 137,
  73.                         137, 137, 137, 137 },
  74.                 { 1, 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 1, 1, 1, 137,
  75.                         137, 137, 137, 1 },
  76.                 { 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 1, 1, 1,
  77.                         1, 137, 137, 137 },
  78.                 { 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
  79.                         1, 137, 137 },
  80.                 { 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
  81.                         137, 137, 137 },
  82.                 { 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 1, 1, 1, 1,
  83.                         1, 137, 137, 137 },
  84.                 { 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 1, 1, 1, 1,
  85.                         1, 1, 1, 1 },
  86.                 { 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
  87.                         1, 1, 1 },
  88.                 { 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
  89.                         1, 1, 1 },
  90.                 { 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
  91.                         1, 1, 1 },
  92.                 { 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 1, 1, 1, 1, 1, 1, 1, 1,
  93.                         1, 1 } };

  94.         // 第二层游戏实体actor数组
  95.         public int[][] mMapAcotor = {
  96.                 { 143, 144, 0, 102, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  97.                     185, 186, 187, 188 },
  98.                     { 151, 152, 0, 110, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  99.                     193, 194, 195, 196 },
  100.                     { 159, 160, 0, 110, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  101.                     201, 202, 203, 204 },
  102.                     { 0, 0, 0, 126, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  103.                     209, 210, 211, 212 },
  104.                     { 0, 0, 0, 134, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  105.                     0, 218, 219, 220 },
  106.                     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  107.                     0, 0, 227, 228 },
  108.                     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  109.                     0, 0, 0, 0 },
  110.                     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  111.                     0, 0, 0, 0 },
  112.                     { 102, 103, 103, 103, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  113.                     0, 0, 0, 0 },
  114.                     { 110, 111, 111, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  115.                     0, 0, 0, 0 },
  116.                     { 110, 111, 111, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  117.                     0, 0, 0, 0 },
  118.                     { 126, 127, 127, 127, 128, 0, 0, 0, 0, 0, 0, 0, 165, 166, 0, 0,
  119.                     0, 0, 0, 0 },
  120.                     { 123, 124, 124, 124, 125, 0, 0, 0, 0, 0, 0, 0, 173, 174, 175, 176,
  121.                     0, 0, 0, 0 },
  122.                     { 229, 230, 231, 232, 0, 0, 0, 0, 0, 0, 0, 0, 181, 182, 183, 184,
  123.                     0, 0, 0, 0 },
  124.                     { 237, 238, 239, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  125.                     0, 0, 0, 0 },
  126.                     { 245, 246, 247, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  127.                     0, 0, 0, 0 },
  128.                     { 0, 254, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 234, 235,
  129.                     236, 0, 0, 0 },
  130.                     { 0, 262, 263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 242, 243,
  131.                     244, 0, 0, 0 },
  132.                     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 251,
  133.                     0, 0, 0, 0 },
  134.                     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 259,
  135.                     0, 0, 143, 144 }
  136.                     };

  137.         // 第三层游戏碰撞物理层数组
  138.         // 下一章介绍
  139.         // ....................

  140.         // 游戏地图资源
  141.         Bitmap mBitmap = null;

  142.         // 资源文件
  143.         Resources mResources = null;

  144.         // 游戏画笔
  145.         Paint mPaint = null;

  146.         // 横向纵向tile块的数量
  147.         int mWidthTileCount = 0;
  148.         int mHeightTileCount = 0;

  149.         // 横向纵向tile块的数量
  150.         int mBitMapWidth = 0;
  151.         int mBitMapHeight = 0;

  152.         //摄像头的焦点  0.0点为焦点在中心。
  153.         int mCameraPosX = 0;
  154.         int mCameraPosY = 0;
  155.        
  156.         //地图左上角锚点坐标
  157.         int mMapPosX =0;
  158.         int mMapPosY =0;
  159.        
  160.         //记录上次时间
  161.        
  162.         private long statrTime = 0;
  163.        
  164.         /**
  165.          * 构造方法
  166.          *
  167.          * @param context
  168.          */
  169.         public MapView(Context context,int screenWidth, int screenHeight) {
  170.             super(context);
  171.             mScreenHeight = screenHeight;
  172.             mScreenWidth = screenWidth;
  173.             mPaint = new Paint();
  174.             mBitmap = ReadBitMap(context, R.drawable.map);
  175.             mBitMapWidth = mBitmap.getWidth();
  176.             mBitMapHeight = mBitmap.getHeight();
  177.             mWidthTileCount = mBitMapWidth / TILE_WIDTH;
  178.             mHeightTileCount = mBitMapHeight / TILE_HEIGHT;
  179.             statrTime = System.currentTimeMillis();
  180.         }

  181.         @Override
  182.         protected void onDraw(Canvas canvas) {
  183.             UpdateCamera();
  184.             DrawMap(canvas, mBitmap);
  185.             DrawRectText(canvas);
  186.             super.onDraw(canvas);
  187.             invalidate();
  188.         }

  189.         private void DrawMap(Canvas canvas, Bitmap bitmap) {
  190.             int i, j;
  191.             for (i = 0; i < TILE_HEIGHT_COUNT; i++) {
  192.                 for (j = 0; j < TILE_WIDTH_COUNT; j++) {
  193.                     int ViewID = mMapView[i][j];
  194.                     int ActorID = mMapAcotor[i][j];
  195.                     int x = (j* TILE_WIDTH) + mMapPosX;
  196.                     int y = (i* TILE_HEIGHT) + mMapPosY;
  197.                     // 绘制地图第一层
  198.                     if (ViewID > TILE_NULL) {
  199.                         DrawMapTile(ViewID, canvas, mPaint, bitmap, x, y);
  200.                     }

  201.                     // 绘制地图第二层
  202.                     if (ActorID > TILE_NULL) {
  203.                         DrawMapTile(ActorID, canvas, mPaint, bitmap, x, y);
  204.                     }
  205.                 }
  206.             }
  207.         }
  208.         private void DrawRectText(Canvas canvas) {
  209.             canvas.clipRect(0, 0,mScreenWidth, 30);
  210.             mPaint.setColor(Color.WHITE);
  211.             canvas.drawRect(0, 0,mScreenWidth, 30, mPaint);
  212.             mPaint.setColor(Color.RED);
  213.             canvas.drawText("当前摄像头X坐标:" + mCameraPosX + "当前摄像头Y坐标 :" + mCameraPosY, 0, 20, mPaint);
  214.         }
  215.         private void UpdateCamera() {
  216.             long nowTime = System.currentTimeMillis();
  217.             //每100毫秒更新一下摄像头的位置
  218.             if(nowTime - statrTime > 1000) {
  219.                 //随机获得摄像头的坐标
  220.                 mCameraPosX = UtilRandom(0,MAP_WIDTH - mScreenWidth);
  221.                 mCameraPosY = UtilRandom(0,MAP_HEIGHT - mScreenHeight);
  222.                 //根据摄像头的坐标更新地图坐标
  223.                 mMapPosX = -mCameraPosX;
  224.                 mMapPosY = -mCameraPosY;
  225.                 statrTime = nowTime;
  226.             }
  227.         }
  228.        
  229.         /**
  230.         * 返回一个随机数
  231.         * @param botton
  232.         * @param top
  233.         * @return
  234.         */
  235.         private int UtilRandom(int botton, int top) {
  236.             return ((Math.abs(new Random().nextInt()) % (top - botton)) + botton);
  237.         }
  238.         /**
  239.          * 根据ID绘制一个tile块
  240.          *
  241.          * @param id
  242.          * @param canvas
  243.          * @param paint
  244.          * @param bitmap
  245.          */
  246.         private void DrawMapTile(int id, Canvas canvas, Paint paint,
  247.                 Bitmap bitmap, int x, int y) {
  248.             // 根据数组中的ID算出在地图资源中的XY 坐标
  249.             // 因为编辑器默认0 所以第一张tile的ID不是0而是1 所以这里 -1
  250.             id--;
  251.             int count = id / mWidthTileCount;
  252.             int bitmapX = (id - (count * mWidthTileCount)) * TILE_WIDTH;
  253.             int bitmapY = count * TILE_HEIGHT;
  254.             DrawClipImage(canvas, paint, bitmap, x, y, bitmapX, bitmapY,
  255.                     TILE_WIDTH, TILE_HEIGHT);
  256.         }

  257.         /**
  258.          * 读取本地资源的图片
  259.          *
  260.          * @param context
  261.          * @param resId
  262.          * @return
  263.          */
  264.         public Bitmap ReadBitMap(Context context, int resId) {
  265.             BitmapFactory.Options opt = new BitmapFactory.Options();
  266.             opt.inPreferredConfig = Bitmap.Config.RGB_565;
  267.             opt.inPurgeable = true;
  268.             opt.inInputShareable = true;
  269.             // 获取资源图片
  270.             InputStream is = context.getResources().openRawResource(resId);
  271.             return BitmapFactory.decodeStream(is, null, opt);
  272.         }

  273.         /**
  274.          * 绘制图片中的一部分图片
  275.          *
  276.          * @param canvas
  277.          * @param paint
  278.          * @param bitmap
  279.          * @param x
  280.          * @param y
  281.          * @param src_x
  282.          * @param src_y
  283.          * @param src_width
  284.          * @param src_Height
  285.          */
  286.         private void DrawClipImage(Canvas canvas, Paint paint, Bitmap bitmap,
  287.                 int x, int y, int src_x, int src_y, int src_xp, int src_yp) {
  288.             canvas.save();
  289.             canvas.clipRect(x, y, x + src_xp, y + src_yp);
  290.             canvas.drawBitmap(bitmap, x - src_x, y - src_y, paint);
  291.             canvas.restore();
  292.         }
  293.        
  294.     }
  295. }
复制代码
最后如果你还是觉得我写的不够详细 看的不够爽 不要紧我把源代码的下载地址贴出来 欢迎大家一起讨论学习

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

0

主题

49

帖子

19

安币

程序猿

Rank: 2

QQ达人

发表于 2011-9-13 15:59:21 | 显示全部楼层
好东西!

1

主题

25

帖子

12

安币

初级码农

Rank: 1

发表于 2011-9-13 11:27:09 | 显示全部楼层
{:soso_e179:}

0

主题

74

帖子

144

安币

程序猿

Rank: 2

发表于 2011-9-12 15:43:33 | 显示全部楼层
好帖啊!

0

主题

21

帖子

6

安币

初级码农

Rank: 1

发表于 2011-9-22 08:59:01 | 显示全部楼层
very good tank you

0

主题

85

帖子

32

安币

初级码农

Rank: 1

QQ达人

发表于 2011-9-28 00:56:00 | 显示全部楼层
GOOD  学习 了  谢谢

0

主题

85

帖子

32

安币

初级码农

Rank: 1

QQ达人

发表于 2011-9-28 00:56:57 | 显示全部楼层
very good tank you

0

主题

85

帖子

32

安币

初级码农

Rank: 1

QQ达人

发表于 2011-9-28 01:00:32 | 显示全部楼层
穷了   谢谢了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区
联系我们
关闭
合作电话:
15618560077
Email:
805941275@qq.com
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

快速回复 返回顶部 返回列表