Android研究之游戏开发摄像头更新
游戏中摄像头的原理介绍
在游戏开发中更新摄像头的位置能够决定屏幕显示的内容,尤其是RPG类游戏摄像头有着很关键的数据。我举一个样例 有时候我们在玩RPG游戏的时候进入一个新的场景 触发一段脚本后 发现镜头開始向上移动 依据镜头移动玩家能够大概浏览一下这个场景有什么东西 。触发什么样的剧情。
这个实现的方式就是游戏摄像头原理。
上章学习了Android游戏开发地图编辑器有须要的能够看下。
如图所看到的:首先摄像头显示的区域也是手机屏幕显示的区域 假设须要更改摄像头的位置 事实上是更改背景地图的位置 利用程序拖动背景地图 给玩家一种假象让玩家感觉像是摄像头在移动而不是背景地图在移动。
游戏中地图的绘制原理介绍 依据地图编辑器生成的出来的数组的每个tile 的 ID 找到每个tile的地图资源原始文件的XY坐标 算出来图片的显示位置利用程序的分割的方法把每个tile分割出来显示在手机屏幕中。 分割图片的代码所看到的:
<strong> /**
* 绘制图片中的一部分图片
*
* @param canvas
* @param paint
* @param bitmap
* @param x
* @param y
* @param src_x
* @param src_y
* @param src_width
* @param src_Height
*/
private void DrawClipImage(Canvas canvas, Paint paint, Bitmap bitmap,
int x, int y, int src_x, int src_y, int src_xp, int src_yp) {
canvas.save();
canvas.clipRect(x, y, x + src_xp, y + src_yp);
canvas.drawBitmap(bitmap, x - src_x, y - src_y, paint);
canvas.restore();
}</strong>
canvas.save();
分割图片之前先把Canvas保存起来 然后在分割 绘制结束后
canvas.restore();
在把Canvas的在状态重置回来 假设不这么做的话 第一张图片分割后就会挡住以后全部的图片,所以大家一定要记住这一点喔。
" src="http://www.cgzhw.com/wp-content/uploads/2014/07/215.jpg" style="">
图所看到的:每一张tile的绘制原理就是这样。讲到这里有些朋友可能就要问 假设我的地图无限大那依据这种方法岂不是要循环无限次?事实上屏幕须要绘制的tile数量仅仅须要绘制屏幕显示区域以内的, 屏幕现实区域以外的我们不用考虑绘制 仅仅须要更新地图的坐标数据就能够。比方我的模拟器屏幕的大小是320X480 那么我实际绘制的tile数量仅仅是 10 X15 (块)。事实上游戏开发绘制中另一个更重要的绘制技术就是双缓冲技术它能够用来解决屏幕闪烁问题,下一章中我会具体介绍。
昨天有朋友跟我提出这样的用数组的方式来绘制地图不科学我非常允许他的观点,为什么不科学? 原因是如今我们仅仅有一个场景我们用一个数组来绘制地图 万一我们的游戏有100个场景 我们岂不是要在程序中写100个数组了?事实上在实际开发中我们是把这些地图的信息转成xml文件 打到游戏的包中 玩家在切换游戏场景的时候便会读取当前游戏场景中的地图xml文件。事实上这些xml文件里也是保存这地图的二位数组信息 可是这样做的优点就是数据驱动 程序猿不用定义N个数组 做N种推断 仅仅需要依据当前切换的场景的ID就能够得到地图的信息
十分方便 也能够避免代码中因为笔误造成的的错误 何乐而不为。
可是无论用不论什么方法处理数据 它的绘制原理都是一样的。
怎样更新游戏中摄像头
效果图:程序取随机数更新游戏摄像头
" src="http://www.cgzhw.com/wp-content/uploads/2014/07/310.jpg" style="">
眼下以每10000毫秒更新一下摄像头的位置 (随机数) 我们有了摄像头的位置以后 就能够在算出背景图片的相对显示位置 移动背景图片的位置后就能够给玩家制造出一种摄像头在移动的假象了。
地图块是我新拼的 长宽的tile块数是20X20。
import java.util.Random;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 全屏显示窗体
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 获取屏幕宽高
Display display = getWindowManager().getDefaultDisplay();
// 显示自己定义的游戏View
mMapView = new MapView(this,display.getWidth(), display.getHeight());
setContentView(mMapView);
}
public final static int TILE_WIDTH = 32;
public final static int TILE_HEIGHT = 32;
public final static int TILE_WIDTH_COUNT = 20;
public final static int TILE_HEIGHT_COUNT = 20;
public final static int MAP_WIDTH = 640;
public final static int MAP_HEIGHT = 640;
public final static int CAMERA_MOVE = 10;
public int mScreenWidth = 0;
public int mScreenHeight = 0;
public final static int TILE_NULL = 0;
// 第一层游戏View地图数组
public int[][] mMapView = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1,
1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 1, 1, 1,
1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1,
1, 1, 1 },
{ 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 137, 1, 1,
1, 1, 1, 1, 1 },
{ 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137,
137, 137, 137, 137, 137, 1, 1, 1 },
{ 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137,
137, 137, 137, 137, 137, 1, 1, 1 },
{ 137, 137, 137, 1, 1, 137, 137, 137, 137, 137, 137, 137, 137,
137, 137, 137, 1, 1, 1, 1 },
{ 1, 137, 137, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 137,
137, 137, 137, 1, 137, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 137,
137, 137, 137, 137, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 1, 1, 1, 137, 137,
137, 137, 137, 137 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 1, 1, 1, 137,
137, 137, 137, 1 },
{ 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 1, 1, 1,
1, 137, 137, 137 },
{ 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
1, 137, 137 },
{ 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
137, 137, 137 },
{ 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 137, 1, 1, 1, 1,
1, 137, 137, 137 },
{ 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 137, 1, 1, 1, 1,
1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 137, 137, 137, 137, 137, 1, 1, 1, 1, 1, 1,
1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 137, 137, 137, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1 } };
public int[][] mMapAcotor = {
{ 143, 144, 0, 102, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185, 186, 187, 188 },
{ 151, 152, 0, 110, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
193, 194, 195, 196 },
{ 159, 160, 0, 110, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
201, 202, 203, 204 },
{ 0, 0, 0, 126, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
209, 210, 211, 212 },
{ 0, 0, 0, 134, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 218, 219, 220 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 227, 228 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 },
{ 102, 103, 103, 103, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 },
{ 110, 111, 111, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 },
{ 110, 111, 111, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 },
{ 126, 127, 127, 127, 128, 0, 0, 0, 0, 0, 0, 0, 165, 166, 0, 0,
0, 0, 0, 0 },
{ 123, 124, 124, 124, 125, 0, 0, 0, 0, 0, 0, 0, 173, 174, 175, 176,
0, 0, 0, 0 },
{ 229, 230, 231, 232, 0, 0, 0, 0, 0, 0, 0, 0, 181, 182, 183, 184,
0, 0, 0, 0 },
{ 237, 238, 239, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 },
{ 245, 246, 247, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 },
{ 0, 254, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 234, 235,
236, 0, 0, 0 },
{ 0, 262, 263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 242, 243,
244, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 251,
0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 259,
0, 0, 143, 144 }
};
// 下一章介绍
// ....................
Bitmap mBitmap = null;
Resources mResources = null;
Paint mPaint = null;
int mWidthTileCount = 0;
int mHeightTileCount = 0;
int mBitMapWidth = 0;
int mBitMapHeight = 0;
int mCameraPosX = 0;
int mCameraPosY = 0;
int mMapPosX =0;
int mMapPosY =0;
* 构造方法
*
* @param context
*/
public MapView(Context context,int screenWidth, int screenHeight) {
super(context);
mScreenHeight = screenHeight;
mScreenWidth = screenWidth;
mPaint = new Paint();
mBitmap = ReadBitMap(context, R.drawable.map);
mBitMapWidth = mBitmap.getWidth();
mBitMapHeight = mBitmap.getHeight();
mWidthTileCount = mBitMapWidth / TILE_WIDTH;
mHeightTileCount = mBitMapHeight / TILE_HEIGHT;
statrTime = System.currentTimeMillis();
}
protected void onDraw(Canvas canvas) {
UpdateCamera();
DrawMap(canvas, mBitmap);
DrawRectText(canvas);
super.onDraw(canvas);
invalidate();
}
int i, j;
for (i = 0; i < TILE_HEIGHT_COUNT; i++) {
for (j = 0; j < TILE_WIDTH_COUNT; j++) {
int ViewID = mMapView[i][j];
int ActorID = mMapAcotor[i][j];
int x = (j* TILE_WIDTH) + mMapPosX;
int y = (i* TILE_HEIGHT) + mMapPosY;
// 绘制地图第一层
if (ViewID > TILE_NULL) {
DrawMapTile(ViewID, canvas, mPaint, bitmap, x, y);
}
if (ActorID > TILE_NULL) {
DrawMapTile(ActorID, canvas, mPaint, bitmap, x, y);
}
}
}
}
private void DrawRectText(Canvas canvas) {
canvas.clipRect(0, 0,mScreenWidth, 30);
mPaint.setColor(Color.WHITE);
canvas.drawRect(0, 0,mScreenWidth, 30, mPaint);
mPaint.setColor(Color.RED);
canvas.drawText("当前摄像头X坐标:" + mCameraPosX + "当前摄像头Y坐标 :" + mCameraPosY, 0, 20, mPaint);
}
private void UpdateCamera() {
long nowTime = System.currentTimeMillis();
//每100毫秒更新一下摄像头的位置
if(nowTime - statrTime > 1000) {
//随机获得摄像头的坐标
mCameraPosX = UtilRandom(0,MAP_WIDTH - mScreenWidth);
mCameraPosY = UtilRandom(0,MAP_HEIGHT - mScreenHeight);
//依据摄像头的坐标更新地图坐标
mMapPosX = -mCameraPosX;
mMapPosY = -mCameraPosY;
statrTime = nowTime;
}
}
* 返回一个随机数
* @param botton
* @param top
* @return
*/
private int UtilRandom(int botton, int top) {
return ((Math.abs(new Random().nextInt()) % (top - botton)) + botton);
}
/**
* 依据ID绘制一个tile块
*
* @param id
* @param canvas
* @param paint
* @param bitmap
*/
private void DrawMapTile(int id, Canvas canvas, Paint paint,
Bitmap bitmap, int x, int y) {
// 依据数组中的ID算出在地图资源中的XY 坐标
// 由于编辑器默认0 所以第一张tile的ID不是0而是1 所以这里 -1
id--;
int count = id / mWidthTileCount;
int bitmapX = (id - (count * mWidthTileCount)) * TILE_WIDTH;
int bitmapY = count * TILE_HEIGHT;
DrawClipImage(canvas, paint, bitmap, x, y, bitmapX, bitmapY,
TILE_WIDTH, TILE_HEIGHT);
}
* 读取本地资源的图片
*
* @param context
* @param resId
* @return
*/
public Bitmap ReadBitMap(Context context, int resId) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
// 获取资源图片
InputStream is = context.getResources().openRawResource(resId);
return BitmapFactory.decodeStream(is, null, opt);
}
* 绘制图片中的一部分图片
*
* @param canvas
* @param paint
* @param bitmap
* @param x
* @param y
* @param src_x
* @param src_y
* @param src_width
* @param src_Height
*/
private void DrawClipImage(Canvas canvas, Paint paint, Bitmap bitmap,
int x, int y, int src_x, int src_y, int src_xp, int src_yp) {
canvas.save();
canvas.clipRect(x, y, x + src_xp, y + src_yp);
canvas.drawBitmap(bitmap, x - src_x, y - src_y, paint);
canvas.restore();
}
}
最后假设你还是认为我写的不够具体 看的不够爽 不要紧我把源码的下载地址贴出来 欢迎大家一起讨论学习。
源代码下载:CameraView
Android研究之游戏开发摄像头更新的更多相关文章
- Android研究之游戏开发处理按键的响应
1.onKeyDown 方法 onKeyDown 方法是KeyEvent.Callback 接口中的一个抽象方法,重写onKeyDown 方法能够监听到按键被按下的事件,我们先看看onKeyDown方 ...
- Android安卓手机游戏开发
成都传智播客Java培训,免费学Android安卓手机游戏开发,安卓android开发课程包括Android安卓应用开发和Android安卓游戏开发两个方向,可是偏向游戏开发. 依据"199 ...
- 基于Intel x86 Android的RAD游戏开发
zip文件还包含编译的"MonkeyGame-debug".可以在模拟器中运行的二进制文件.在"game.build"文件夹中有一个HTML5 build.在C ...
- Android——Cocosd2d-x手机游戏开发学习思路
手机APP应用如雨后春笋般冒了出来,而在众多的APP应用中,游戏占据了半壁江山.它丰富着人们的业余生活,增进了人们之间的沟通交流.也有许多开发的朋友对游戏开发情有独钟,他们不止是享受着有很多的人们去下 ...
- Coco2d-x android win7 Python 游戏开发环境的搭建
1:我用的电脑配置 win7 3 核 内存8G 桌面.一直想学习Coco2d 游戏开发,所以,一个星期后,需要找到,最终建立了一个良好的环境 2:我使用的版本号版本号,至于建筑android开发环境略 ...
- Android游戏开发研究帧动画实现
1.动画的原则框架 帧的动画帧的动画顾名思义,画就是帧动画. 帧动画和我们小时候看的动画片的原理是一样的,在同样区域高速切换图片给人们呈现一种视觉的假象感觉像是在播放动画,事实上只 ...
- Android游戏开发研究与主角在地图滚动
让人感动的地图过程平滑滚动 玩过rpg朋友应该都知道RPG的游戏地图一般都比較大 今天我和大家分享一下在RPG游戏中怎样来处理超出手机屏幕大小的游戏地图. 如图所看到的为程序效果 ...
- 【读书笔记《Android游戏编程之从零开始》】11.游戏开发基础(SurfaceView 游戏框架、View 和 SurfaceView 的区别)
1. SurfaceView 游戏框架实例 实例效果:就是屏幕上的文本跟着点击的地方移动,效果图如下: 步骤: 新建项目“GameSurfaceView”,首先自定义一个类"MySurfac ...
- android手机游戏开发Cocos2d-x开发分享
我想现在应该没有人没有玩过手机游戏了吧,当然所有人都玩过,但不是所有人都知道怎么去开发手机游戏,因为许多人都感觉做开发是一件很困难的事儿,身边的朋友也对此感觉难度很大.但是,现在我可以告诉你,手机游戏 ...
随机推荐
- Programming Python 3rd Edition 第三版 pdf chm下载
Programming Python 作为一款经典系列书籍 非常的耐看 建议有志于学习python的童鞋好好看看 网上 Programming Python第四版的 pdf 下载非常容易 也就是最新的 ...
- Python (Page Object实例)
Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素和功能模块的封装减少冗余代码,同时在后期维护中,若元素定位或功能模块发生变化,只需要调整页面元素或功能模 ...
- 【单调队列+尺取】HDU 3530 Subsequence
acm.hdu.edu.cn/showproblem.php?pid=3530 [题意] 给定一个长度为n的序列,问这个序列满足最大值和最小值的差在[m,k]的范围内的最长子区间是多长? [思路] 对 ...
- vue elementUI 表单校验(数组多层嵌套)
在使用vue element-ui form表单渲染的时候,会遇到这样的数据结构: { "title":''123455, "email":'123456@qq ...
- ElasticSearch 多索引
1.用逗号将索引隔开,如: $ curl -XPOST http://localhost:9200/aaa,website/_search/ { "took": 1, " ...
- 巴蜀1088 Antiprime数
Description 如果一个自然数n(n>=1),满足所有小于n的自然数(>=1)的约数个数都小于n的约数个数,则n是一个Antiprime数.譬如:1, 2, 4, 6, 12, 2 ...
- 【Codeforces Round #505 (Div. 1 + Div. 2) 】
A:https://www.cnblogs.com/myx12345/p/9843966.html B: C:https://www.cnblogs.com/myx12345/p/9844084.ht ...
- json-lib maven依赖出错的问题
项目中要用到json-lib,mvnrepository.com查找它的dependency时结果如下: xml 代码 <dependency> <groupId>net.sf ...
- sqlplus 命令 错误
SP2-1503: 无法初始化 Oracle 调用界面 用管理员运行就可以了
- 教妹学 Java:大有可为的集合
00.故事的起源 “二哥,上一篇<泛型>的反响效果怎么样啊?”三妹对她提议的<教妹学 Java>专栏很是关心. “有人评论说,‘二哥你敲代码都敲出幻想了啊.’” “呵呵,这句话 ...