在开发游戏开发中,android相应的提供了几个重要的模块:
1、显示界面的视图: Android 提供 View 和 SurfaceView
2、控制游戏整体结构: android 提供 Activity
3、逻辑控制类:专门用于处理游戏的逻辑计算
4、处理游戏界面与用户交互事件 : 利用 View 类提供的 onKeyDown onKeyUp onTounchEvent等方法
我们这里简单熟悉一下如何在视图上画东西。
1、View 类: android.view.View
View 是Android中的一个超类,这个类几乎包含了所有的屏幕类型。每一个View都有一个用于绘画的画布,这个画布 可以进行任何扩展。
任何一个View类都只需要重写onDraw方法来实现界面显示,任何一个View都只需要重写 OnDraw 方法来实现界面显示,自定义的视图可以是复杂的3D实现,也可以是非常简单的文本或位图。
Android 中有个重要的东东: Android UI 线程
在这里 http://blog.csdn.net/andyhuabing/article/details/11921887 有对其简要精典的介绍及注意点,这里就不再重复说明了。
这里来个简单例子说明一下View的用法,利用线程变更显示颜色,通过上下左右移动矩形
TestView.java 类如下:
package com.example.testondraw; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.View; /** * View 是Android中的一个超类,这个类几乎包含了所有的屏幕类型。每一个View都有一个用于绘画的画布,这个画布 可以进行任何扩展。 * * 任何一个View类都只需要重写onDraw方法来实现界面显示。 * */ public class TestView extends View { int miCount = 0; int x = 10, y = 10; public TestView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { if (miCount < 100) { miCount++; } else { miCount = 0; } //绘图 Paint mPaint = new Paint(); switch (miCount%4) { case 0: mPaint.setColor(Color.BLUE); break; case 1: mPaint.setColor(Color.GREEN); break; case 2: mPaint.setColor(Color.RED); break; case 3: mPaint.setColor(Color.YELLOW); break; default: mPaint.setColor(Color.WHITE); break; } // 绘制矩形 canvas.drawRect(x, y, x + 120, y + 80, mPaint); } }
如何在 Acitivty 使用呢?示例代码如下:
package com.example.testondraw; import java.util.List; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.DisplayMetrics; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; public class MainActivity extends Activity { static final String TAG = "MainActivity"; private TestView mTestView = null; private TestSurfaceView mTestSurfaceView = null; private int mWidth = 0, mHeight = 0; private MyHandler mHandler = new MyHandler(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initView(); startTestView(); // setContentView(R.layout.main); } void initView() { // 使用自定义的View mTestView = new TestView(this); setContentView(mTestView); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); mWidth = dm.widthPixels; mHeight = dm.heightPixels; Log.i(TAG, "Display Metrics " + mWidth + " mHeight:" + mHeight); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } void startTestView() { Thread th = new Thread(new Runnable() { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { // 使用postInvalidate可以直接在线程中更新界面 // mTestView.postInvalidate(); // 使用发消息给UI线程 Message msg = Message.obtain(); msg.what = 1; mHandler.sendMessage(msg); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }); th.start(); } class MyHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: mTestView.invalidate(); break; default: break; } super.handleMessage(msg); } } public boolean onKeyDown(int keyCode, android.view.KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_DOWN: if (mTestView.y >= mHeight) mTestView.y = 0; mTestView.y += 10; break; case KeyEvent.KEYCODE_DPAD_UP: if (mTestView.y <= 0) mTestView.y = mHeight; mTestView.y -= 10; break; case KeyEvent.KEYCODE_DPAD_LEFT: if (mTestView.x <= 0) mTestView.x = mWidth; mTestView.x -= 10; break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (mTestView.x >= mWidth) mTestView.x = 0; mTestView.x += 10; break; } return false; }; }
2、SurfaceView android.view.SurfaceView
当执行效率有要求很高时,View类就无法满足需求。必须使用 SurfaceView 类 -- 利用双缓冲技术
使用SurfaceView提供给需要直接画像素而不是使用画窗体部件的应用使用。
而每个Surface创建一个Canvas对象,用来管理View在Surface上的绘画操作。
简要说明一下具体的方法及使用:
SurfaceHolder 对象需要通过 getHolder() 获取
在 Layout 上摆一个 SurfaceView 组件:
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView1);
SurfaceHolder holder = mSurfaceView.getHolder();
对于SurfaceView 的创建,销毁及变更
@SuppressWarnings("unused")
private SurfaceHolder.Callback mSurfaceCbk = new SurfaceHolder.Callback() {
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) { // 在Surface 大小发生变更时触发
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) { // 在创建 Surface 时触发
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) { // 在销毁 Surface 时触发
// TODO Auto-generated method stub
}
};
添加及删除 SurfaceView 的回调函数:
display.addCallback(mSurfaceCbk);
display.removeCallback(mSurfaceCbk);
Canvas 的使用:
lockCanvas 锁定画布,绘图之前必须锁定画布才能得到当前画布对象
unlockCanvasAndPost 开始绘制时锁定画布,绘制完成之后解锁画布
下面例子是绘制一个不断变换颜色的圆,并实现 SurfaceView 的事件处理
TestSurfaceView.java 代码:
package com.example.testondraw; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * 使用SurfaceView提供给需要直接画像素而不是使用画窗体部件的应用使用。 * 而每个Surface创建一个Canvas对象,用来管理View在Surface上的绘画操作。 */ public class TestSurfaceView extends SurfaceView implements SurfaceHolder.Callback { // 控制循环 private boolean mbLoop = false; // 定义SurfaceHolder对象 private SurfaceHolder mSurfaceHolder = null; private int miCount = 0; public int x = 50, y = 50; private int mWidth = 1280,mHeight = 720; private Bitmap mBitmap = null; public TestSurfaceView(Context context) { super(context); // 实例化SurfaceHolder mSurfaceHolder = this.getHolder(); // 添加回调 mSurfaceHolder.addCallback(this); this.setFocusable(true); } public void setDisplayWH(int w, int h) { mWidth = w; mHeight = h; } public void setBitmap(Bitmap bitmap) { this.mBitmap = bitmap; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder holder) { mbLoop = true; Thread th = new Thread(new Runnable() { @Override public void run() { while (mbLoop){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } synchronized( mSurfaceHolder ){ drawBitmap(); DrawData(); } } } }); th.start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { mbLoop = false; } private void drawBitmap() { // 锁定画布,得到canvas if (mSurfaceHolder == null || this.mBitmap == null) return; Canvas canvas = mSurfaceHolder.lockCanvas(); if (canvas == null) { return; } // 绘图 Paint paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.BLUE); canvas.drawBitmap(this.mBitmap, 0, 0, paint); // 绘制后解锁,绘制后必须解锁才能显示 mSurfaceHolder.unlockCanvasAndPost(canvas); } // 绘图方法 private void DrawData() { if (mSurfaceHolder == null) return; // 锁定画布,得到canvas Canvas canvas = mSurfaceHolder.lockCanvas(); if (canvas == null) { return; } if (miCount < 100) { miCount++; } else { miCount = 0; } // 绘图 Paint mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.BLACK); // 绘制矩形--清屏作用 canvas.drawRect(0, 0, mWidth, mHeight, mPaint); switch (miCount % 4) { case 0: mPaint.setColor(Color.BLUE); break; case 1: mPaint.setColor(Color.GREEN); break; case 2: mPaint.setColor(Color.RED); break; case 3: mPaint.setColor(Color.YELLOW); break; default: mPaint.setColor(Color.WHITE); break; } // 绘制矩形-- canvas.drawCircle(x, y, 50, mPaint); // 绘制后解锁,绘制后必须解锁才能显示 mSurfaceHolder.unlockCanvasAndPost(canvas); } }
测试使用例子:
package com.example.testondraw; import java.util.List; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.DisplayMetrics; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.SurfaceHolder; import android.view.SurfaceView; public class MainActivity extends Activity { static final String TAG = "MainActivity"; private TestSurfaceView mTestSurfaceView = null; private int mWidth = 0, mHeight = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initView(); startTestSurfaceView(); // setContentView(R.layout.main); } void initView() { // 使用自定义的View mTestSurfaceView = new TestSurfaceView(this); setContentView(mTestSurfaceView); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); mWidth = dm.widthPixels; mHeight = dm.heightPixels; Log.i(TAG, "Display Metrics " + mWidth + " mHeight:" + mHeight); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } public boolean onKeyDown(int keyCode, android.view.KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_DOWN: if (mTestSurfaceView.y >= mHeight) mTestSurfaceView.y = 0; mTestSurfaceView.y += 10; break; case KeyEvent.KEYCODE_DPAD_UP: if (mTestSurfaceView.y <= 0) mTestSurfaceView.y = mHeight; mTestSurfaceView.y -= 10; break; case KeyEvent.KEYCODE_DPAD_LEFT: if (mTestSurfaceView.x <= 0) mTestSurfaceView.x = mWidth; mTestSurfaceView.x -= 10; break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (mTestSurfaceView.x >= mWidth) mTestSurfaceView.x = 0; mTestSurfaceView.x += 10; break; case KeyEvent.KEYCODE_BACK: this.finish(); break; } return false; }; void startTestSurfaceView() { mTestSurfaceView.setDisplayWH(mWidth, mHeight); } }