开始前必须知道的知识:
视觉暂留
视觉暂留现象即视觉暂停现象(Persistence of vision,Visual staying phenomenon,duration of vision)又称“余晖效应”.
1824年由英国伦敦大学教授皮特‘马克’罗葛特在他的研究报告《移动物体的视觉暂留现象》中最先提出.
人眼在观察景物时,光信号传入大脑神经,需经过一段短暂的时间,光的作用结束后,视觉形象并不立即消失
这种残留的视觉称“后像”,视觉的这一现象则被称为“视觉暂留”.
图像刷新的慢的话,看到的游戏画面就会卡屏,类似FPS(每秒传输帧数(Frames Per Second))
!!!正常情况下,一秒时间内刷新得画面个数是24个
为什么使用SurfaceView:
双缓冲:消除由复杂绘制操作造成的图像闪烁
SurfaceView带有双缓冲机制,但是View没有(双缓冲:在内存中把显示的图像处理好,然后再加载到屏幕,详细可自行百度)
代码流程:
1.创建Android项目(把默认产生的layout文件删除,这里使用自定义视图类实例化图像)
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MySurafaceView(this)); //实例化自定义的视图类
}
}
2.SurfaceView类的创建 (创建一个新类名字叫MySurafaceView继承SurView)
implements anroid.view.SurfaceHolaer.Callback产生回调
//在mysurfaceView创建的时候要做什么
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
}
//在视图改变的时候要做什么
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
}
//在视图销毁的时候要做什么
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
3.创建线程,进行图像的更新
implements Runnable
重写Run方法
public void draw(){ //实际画图操作
}
@Override
public void run() { //进行图像更新,不断的绘图
while (runFLag){
draw();
}
}
4.创建surfaceHolder对象用来操作surfaceView,并添加监听
public SurfaceHolder surfaceHolder;
在构造方法里面
public MySurafaceView(Context context) {
super(context);
surfaceHolder = this.getHolder(); //实例化
surfaceHolder.addCallback(this); //添加监听
}
5.在surfaceCreated创建Thread类对象(很重要)
为什么要在surfaceCreated创建线程
因为如果是在构造方法中创建线程,会导致图没构造出来就开始画图
所以要在surfaceCreated(画出图形后)才能继续进行想要的绘图操作
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) { //surfaceView创建的时候
runFLag = true;
thread = new Thread(this);
thread.start();
}
6.完成draw方法的画图操作
public void draw(){
try {
canvas = surfaceHolder.lockCanvas(); //在任意时刻,只有一个线程能够操作屏幕,并且实例化
if(canvas != null){
canvas.drawColor(Color.BLACK);
canvas.drawText("Hello!!",100,100,paint);
}
}catch (Exception e){
}finally {
surfaceHolder.unlockCanvasAndPost(canvas); //在最后要做解锁
}
}
**为什么要上锁,因为在一个游戏中,有许多线程来对一个屏幕画图(刷新),这时候必须保证一个顺序问题
7.做线程的频率刷新
@Override
public void run() { //进行图像更新,不断的绘图
while (runFLag){
long start = System.currentTimeMillis(); //画图执行前时间
draw();
long end = System.currentTimeMillis(); //画图完成后时间
if(end-start<50){ //控制频率为50ms一次 人的暂留视觉大概是1/24 秒,也就是一秒24张图
try {
thread.sleep(50-(end-start));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
8.用户触摸时,可移动画出来的图像
@Override
public boolean onTouchEvent(MotionEvent event) { //触摸监听事件
x = (int) event.getX(); //得到当前事件的x坐标
y = (int) event.getY(); //得到当前事件的y坐标
return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { //按键按下事件
return super.onKeyDown(keyCode, event);
}
9.全屏化
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); //窗口无标题
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); //设置
setContentView(new MySurafaceView(this)); //这里不使用默认产生的Layout文件,这里是实例化MySurafaceView,游戏一般都是自定义视图
}
}
10.线程循环
while (runFLag){ //满足某个条件
//do something
}
完整的代码:
//MainActivity
package com.example.adminis.newgameapp;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new MySurafaceView(this));
}
}
//MySurafaceView类
package com.example.adminis.newgameapp;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* Created by Adminis on 2016/12/4.
*/
public class MySurafaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable {
public boolean runFLag = true;
public SurfaceHolder surfaceHolder;
private Thread thread;
public Paint paint; //画笔
public Canvas canvas; //画布
public int x = 100,y = 100; //用于储存触摸的坐标
public MySurafaceView(Context context) {
super(context);
surfaceHolder = this.getHolder(); //实例化
surfaceHolder.addCallback(this); //添加监听
paint = new Paint();
paint.setColor(Color.WHITE);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) { //surfaceView创建的时候
runFLag = true;
thread = new Thread(this);
thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { //视图进行更新的时候
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) { //视图进行销毁的时候
}
public void draw(){
try {
canvas = surfaceHolder.lockCanvas(); //在任意时刻,只有一个线程能够操作屏幕,并且实例化
if(canvas != null){
canvas.drawColor(Color.BLACK);
canvas.drawText("Hello!!", x, y, paint);
}
}catch (Exception e){
}finally {
surfaceHolder.unlockCanvasAndPost(canvas); //在最后要做解锁
}
}
@Override
public void run() { //进行图像更新,不断的绘图
while (runFLag){
long start = System.currentTimeMillis(); //画图执行前时间
draw();
long end = System.currentTimeMillis(); //画图完成后时间
if(end-start<46){ //控制频率为50ms一次 人的暂留视觉大概是1/24 秒,也就是一秒24张图
try {
thread.sleep(46-(end-start));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) { //触摸监听事件
x = (int) event.getX(); //得到当前事件的x坐标
y = (int) event.getY(); //得到当前事件的y坐标
return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { //按键按下事件
return super.onKeyDown(keyCode, event);
}
}