关于Android使用SurfaceView实现绘图功能之2D游戏学习

以下内容是实现两个画面的转换和一个画面的运动的效果,实现了一个我们也就可以举一反三了,其余的实现也就容易了。废话了一段,下面进入正题:

 说得不好的各位大神尽管拍砖!

第一步:

建立工程什么的就不用说了,自己回去建立,不懂也不要问,自己Google~~

第二部:

新建一个类Welcome继承至SurfaceView类并实现其接口SurfaceHolder.Callback,这里实现的事第一个画面的类,也就是我们现实两个画面就使用两个类来实现,封装两个类。继承了SurfaceView之后就实现相应的创建,改变,销毁三个方法,这是这个类必须要求实现的,对于其中的为什么我也不懂。。创建方法的实现也就是我们创建这个类之后我们就开启这个类,由于我们在接下来还要定义一个内嵌线程,所以我们可以在创建里面实现我们的线程的启动start()方法。对于其他的什么构造方法什么的就自己看着办了,以及初始化什么的就自己看着办你想初始化什么就初始化什么了,想我现在用到一个需要绘制的图片还有坐标什么的我就自己在里面初始化就可以了。也就是这段内嵌线程的代码

class TutorialThread extends Thread{//刷帧线程
private int span = 500;//睡眠的毫秒数
private SurfaceHolder surfaceHolder;
private Welcome view;
private boolean flag = false;
public TutorialThread(SurfaceHolder surfaceHolder, Welcome view) {//构造器
this.surfaceHolder = surfaceHolder;
this.view = view;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() { //重写run方法,实现现场的不断循环
Canvas c;
while (this.flag) {
c = null;
try {
// 锁定整个画布,在内存要求比较高的情况下,建议参数不要为null
c = this.surfaceHolder.lockCanvas(null);
synchronized(this.surfaceHolder) {
view.draw(c);  //实现绘图的draw()方法,只好我们也会重写
}
} finally {
if (c != null) {
//更新屏幕显示内容
this.surfaceHolder.unlockCanvasAndPost(c);
}
}
try{
Thread.sleep(span);
}
catch(Exception e){
e.printStackTrace();
}
}
}
}

线程一直调用我们的run方法循环,draw()方法就不听的绘制我们的图片,下面是我们的draw()方法

public void draw(Canvas canvas) {

int px = viewX/5*3;
int py = viewY/5*3;
canvas.drawColor(Color.BLACK);
goods.draw(canvas);

//canvas.drawBitmap(background,10,10, null);
canvas.drawBitmap(button, px, py, null);
}

同样的想有几个画面的话可以多创建几个相似的类,或者在同一个类里面控制状态什么是盖显示什么也行,这里我使用一个消息参数来传回主Activity使用主Activity来控制显示状态,也就是我们转场标记

第三步:

我们在每一个继承至SurfaceView的画面类,添加了一个touchEvent监听时间,这样只要我们控制时间发生时我们向主Activity发送相应的消息参数我们就可以实现我们的画面的跳转了

例如在Welcome里面我们用一个按钮来触发时间的发生,当点击按钮时,我们就传递一个消息参数会主Activity然后由主Activity设置需要转换的画面

public boolean onTouchEvent(MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
int px = (int)event.getX();
int py = (int)event.getY();
if(px > viewX/5*3 && px < viewY/5*3+button.getWidth()
&& py > viewY/5*3 && py < viewY/5*3+button.getHeight()){//点击了重新游戏按钮

testActivity.myHandler.sendEmptyMessage(1);//向主activity发送Handler消息
}
// testActivity.myHandler.sendEmptyMessage(1);
}
return super.onTouchEvent(event);

}

在主Activity里面我们使用的是

Handler myHandler = new Handler(){//用来更新UI线程中的控件
public void handleMessage(Message msg) {
if(msg.what == 1)
{
if(welcome != null)
{
welcome = null;
}
toLoading();

}
else if(msg.what == 2)
{
if(loading != null)
{
loading = null;
}
toWelcome();

}
}
};

 

至此我们就可以实现了画面的切换,根据不同的状态信息绘制我们不同的画面了。

一下给出我写的一个简单我程序部分源代码:

第一个是Welcome:

package com.test;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Welcome extends SurfaceView implements SurfaceHolder.Callback {

TestActivity testActivity;
SurfaceHolder surfaceHolder;
TutorialThread thread;

Bitmap background;
Bitmap button;

int viewX;
int viewY;

MoveThread moveThread;
good goods;

public Welcome(TestActivity activity2) {
super(activity2);
this.testActivity = activity2;
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
thread = new TutorialThread(surfaceHolder,this);
moveThread = new MoveThread(this);

viewX = activity2.viewX;
viewY = activity2.viewY;
initBitmap();

}

private void initBitmap() {
this.background = BitmapFactory.decodeResource(getResources(), R.drawable.backgroud);
this.button = BitmapFactory.decodeResource(getResources(),R.drawable.icon);
goods = new good(10, 400, background);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
this.thread.setFlag(true);
this.thread.start();

this.moveThread.setFlag(true);
this.moveThread.start();

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setFlag(false);
moveThread.setFlag(false);
while (retry) {
try {
moveThread.join();
thread.join();
retry = false;
}
catch (InterruptedException e) {//不断地循环,直到刷帧线程结束
}
}
// TODO Auto-generated method stub

}

public void draw(Canvas canvas) {

int px = viewX/5*3;
int py = viewY/5*3;
canvas.drawColor(Color.BLACK);
goods.draw(canvas);

//canvas.drawBitmap(background,10,10, null);
canvas.drawBitmap(button, px, py, null);
}
public boolean onTouchEvent(MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
int px = (int)event.getX();
int py = (int)event.getY();
if(px > viewX/5*3 && px < viewY/5*3+button.getWidth()
&& py > viewY/5*3 && py < viewY/5*3+button.getHeight()){//点击了重新游戏按钮

testActivity.myHandler.sendEmptyMessage(1);//向主activity发送Handler消息
}
// testActivity.myHandler.sendEmptyMessage(1);
}
return super.onTouchEvent(event);

}

class TutorialThread extends Thread{//刷帧线程
private int span = 500;//睡眠的毫秒数
private SurfaceHolder surfaceHolder;
private Welcome view;
private boolean flag = false;
public TutorialThread(SurfaceHolder surfaceHolder, Welcome view) {//构造器
this.surfaceHolder = surfaceHolder;
this.view = view;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
Canvas c;
while (this.flag) {
c = null;
try {
// 锁定整个画布,在内存要求比较高的情况下,建议参数不要为null
c = this.surfaceHolder.lockCanvas(null);
synchronized(this.surfaceHolder) {
view.draw(c);
}
} finally {
if (c != null) {
//更新屏幕显示内容
this.surfaceHolder.unlockCanvasAndPost(c);
}
}
try{
Thread.sleep(span);
}
catch(Exception e){
e.printStackTrace();
}
}
}
}

}

第二个是:Loding

package com.test;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Loading extends SurfaceView implements SurfaceHolder.Callback {

TestActivity testActivity;
SurfaceHolder surfaceHolder;
TutorialThread thread;

Bitmap background2;
Bitmap button2;

public Loading(TestActivity activity1) {
super(activity1);
this.testActivity = activity1;
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
thread = new TutorialThread(surfaceHolder, this);
initBitmap();
}

private void initBitmap() {
this.background2 = BitmapFactory.decodeResource(getResources(), R.drawable.menu);
this.button2 = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
}

public void draw(Canvas canvas) {

canvas.drawColor(Color.BLACK);
canvas.drawBitmap(background2, 0, 0, null);
canvas.drawBitmap(button2, 250, 350, null);
}

public boolean onTouchEvent(MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
int px = (int)event.getX();
int py = (int)event.getY();
if(px > 250 && px < 250+button2.getWidth()
&& py > 350 && py < 350+button2.getHeight()){//点击了重新游戏按钮
testActivity.myHandler.sendEmptyMessage(2);//向主activity发送Handler消息
}
// testActivity.myHandler.sendEmptyMessage(2);
}
return super.onTouchEvent(event);

}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setFlag(true);
thread.start();

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setFlag(false);
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {//不断地循环,直到刷帧线程结束
}
}
// TODO Auto-generated method stub

}
class TutorialThread extends Thread{//刷帧线程
private int span = 500;//睡眠的毫秒数
private SurfaceHolder surfaceHolder;
private Loading view;
private boolean flag = false;
public TutorialThread(SurfaceHolder surfaceHolder, Loading view) {//构造器
this.surfaceHolder = surfaceHolder;
this.view = view;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
Canvas c;
while (this.flag) {
c = null;
try {
// 锁定整个画布,在内存要求比较高的情况下,建议参数不要为null
c = this.surfaceHolder.lockCanvas(null);
synchronized (this.surfaceHolder) {
view.draw(c);
}
} finally {
if (c != null) {
//更新屏幕显示内容
this.surfaceHolder.unlockCanvasAndPost(c);
}
}
try{
Thread.sleep(span);
}
catch(Exception e){
e.printStackTrace();
}
}
}
}

 

}

 

第三个是:主TestActivity

package com.test;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;

public class TestActivity extends Activity {

Welcome welcome;
Loading loading;
Process process;
int viewX;
int viewY;

Handler myHandler = new Handler(){//用来更新UI线程中的控件
public void handleMessage(Message msg) {
if(msg.what == 1)
{
if(welcome != null)
{
welcome = null;
}
toLoading();

}
else if(msg.what == 2)
{
if(loading != null)
{
loading = null;
}
toWelcome();

}
}
};

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置为全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//强制为横屏

WindowManager windowManager = getWindowManager();
Display display = windowManager.getDefaultDisplay();
viewX = display.getWidth();
viewY = display.getHeight();

toWelcome();
}
public void toLoading() {
//process = new Process(this);
loading = new Loading(this);
setContentView(loading);
new Thread(){//线程
public void run(){
Looper.prepare();
process = new Process(TestActivity.this);//初始化GameView
Looper.loop();
}
}.start();//启动线程
}

public void toWelcome() {
welcome = new Welcome(this);
setContentView(welcome);
}
}

 

程序代码就贴这么多吧。。应该可以看得懂了的。

关于用Surface绘图类实现的绘图功能,以至于实现简单的2D游戏~

第一步:

首先是我们创建一个Android项目,建立建立之后我们会得到一个activity类,之后我们再建立一个需要实现的绘图类,比如GameSurfaceView类

第二步:

编写GameSurfaceView使其继承制SurfaceView并实现借口 SurfaceHolder同时还有实现回调函数 SurfaceHolder.Callback也就是

public class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback

第三步:系统会提示创建必须实现的三个方法一个是在surface的大小发生改变时激发surfaceChanged()、在surface创建时激发surfaceCreated、在surface销毁时激发

第四部:

我们就可以可以在类GameSurfaceView类里面写我们需要定义的一些对象如:SurfaceHolder mSurfaceHolder; 构造函数实现初始化父级构造函数super(context);之后就是可以实例化我们第的对象

// 实例化SurfaceHolder
mSurfaceHolder = this.getHolder();

// 添加回调
mSurfaceHolder.addCallback(this);
this.setFocusable(true);
//从图片资源中装载图片资源

mBitQQ=((BitmapDrawable)getResources().getDrawable(R.drawable.background2)).getBitmap();

第五步:

实例化完后,在surfaceCreated函数里面建立一个线程实现类的线程的开始new Thread(this).start();

第六步:

就是重写我们的线程函数RUN();在run函数里面,我们就可以控制循环的情况,

while (mbLoop)
{
try
{
Thread.sleep(200);
}
catch (Exception e)
{

}
synchronized( mSurfaceHolder )
{
Draw();
}

}

然后在缓冲实现我们的图像的绘制的缓冲以及调用我们的绘制函数

第七步:

实现我们的Draw()函数

锁定一个画布,

//锁定画布,得到canvas
Canvas canvas= mSurfaceHolder.lockCanvas();

之后就是建立一个画笔Paint mPaint = new Paint();

设置画笔的颜色和形状

mPaint.setColor(Color.BLACK);
//绘制矩形–清屏作用
canvas.drawRect(0, 0, 320, 480, mPaint);

当然我们还可以绘制我们的图片

/* 在屏幕(0,0)处绘制图片mBitQQ */
GameSurfaceView.drawImage(canvas, mBitQQ, 0, 0);
// 绘制后解锁,绘制后必须解锁才能显示
mSurfaceHolder.unlockCanvasAndPost(canvas);

绘制后要记得解锁画布才会显示

最后是关于DrawImage()我们写成函数以提高封装性

private static void drawImage(Canvas canvas, Bitmap mBitQQ2, int x, int y) {
// TODO Auto-generated method stub
canvas.drawBitmap(mBitQQ2, x, y, null);
}

第八步:

我们在我们的activity里面的onCreate设置我们的类的一个引用(activity里面都可以用的,也即在类下面的属性),建立一个对象mGameSurfaceView = new GameSurfaceView(this);

之后就可以设置我们显示

//设置显示GameSurfaceView视图
setContentView(mGameSurfaceView);

到这里就实现了我们的一张图片的绘制功能,也就是用SurfaceView实现我们的绘图功能,以便今后实现游戏的图画的绘制。

当然希望大家今后都可以成为技术大牛,做出自己的游戏,技术持续更新中~~

 

关于Android开发环境的搭建

关于Android开发环境的搭建

系统环境

第一步

先安装好Java的运行环境,也就是安装Jdk 由于本系统之前已经安装好了,所以在此不再重复安装

第二步

安装Eclipse 本系统由于已经安装好了eclipse-SDK-3.5-win32  所以也不再安装,安装过程也就点击运行安装即可

安装后启动Eclipse 也就如下图所示

 

启动完成后

 

第三步

下载安装Android SDK 只有安装了SDK我们才可以进行Android的开发,一般SDK可以在Android的官网下载,但是一般情况下,其官网不能访问,所以本SDK是通过115网盘找到的,下载后安装

下载后解压,解压后就如同图片所示

 

我们读SDK Readme 后会发现,仅仅有sdk还是不能进行Android的开发的,我们还需要运行SDK Manager来下载相应的开发工具

在运行完SDK Manager 我们会发现在platforms目录下会生成相应的许多android版本

这时候我们就已经下载了相应的开发工具

第四步

              在安装好Eclipse之后我们还需要下载Eclipse的android开发插件ADT 我下载的版本是android-sdk_r10-windows和ADT-10.0.0 介于有时候版本不一致可能会出现异常,所以在我安装时,我选择安装的是相同的10.0的版本

       下面在Eclipse下点击 HELP->install new software即可进入如下界面

之后选择你下载的ADT位置 在ADD里面选择本地的ADT进行安装,然后把下面的连接以更新选项去掉,否则他会联网更新文件,当你下次启动的时候就有可能不能使用了。我就挨过、、所以最好把选项给去掉。

第五步

安装完成后,由于我们的SDK里面的tools里面的工具都是在命令行下使用的,所以我们需要配置一下环境变量

       首先我们进入环境变量下,在系统变量下新建一个ANDROID 然后把相应的tools的路径添加进去,之后在Path里面添加一句 %ANDROID%即可配置,之后选择确定,然后我们进入命令行模式,如果输入adb回车出现如下图所示即说明环境变量配置成功

第六步

配置完环境变量后,我们下面就来配置我们的Eclipse 我们点击Eclipse里面的windows->Preferences选择Android 然后配置我们的SDK 选择Browser添加本地的SDK,添加完成后我们就会发现他会显示我们刚刚在android manager下载的各版本的开发工具,,还有我们也可以在此设置相应的开发环境的基本文本编辑的环境.

第七步

       安装完成后,我们即可发现在Eclipse里面有一个像是小机器人一样的按钮,我们点击按钮  然后选择NEW新建一个ANDROID的虚拟手机

建立完成后我们即可选择启动ANDROID虚拟开发环境

启动完成后我们就可以看见一个虚拟的安卓手机,之后我们就可以在Eclipse下编辑ANDROID程序,然后在虚拟机运行了。

团支部考评那点事~~

我想说的是我再也不想为了拿个什么五四红旗团支部什么的做PPT了,每次都是一个人慢慢熬出来!!

我想说的是我现在的左脚的膝盖都是痛的了,坐了一天加一个晚上的时间,膝盖都受不了了。

有点点想回家休息一两天了,然后却是星期六又要有基地考评,星期日还得开会,关于软件项目实训的会议。

这就是身在其中由不得自己嘛?或许是吧,还是那句话,在你没有成为权威之前,你就得服从权威。有点点想去锻炼下了,想下阳朔去走走,其实好想带上你一起去,但是却怕你不愿意~~

想会阳朔走一圈,散散心了,这一个星期来也过得蛮艰苦的~都不得找你,也不懂可以选择做什么,能做的就是坐等~~不想这样~

自己也好久没打电话回家了,估计也差不多一个月了吧,话说这么近,说起来好像是不用怎么打的,每个月回家一次就可以了,其实不然的~~我觉得爸妈在家都是希望我可以打电话回家的,美两个星期一次~~不管回不回家吧,明晚还是打个电话回家吧~~今晚打算打的,后面忙着忙着又忘记了·~~唉

又是两点半了~~昨晚因为弄这个博客弄到了两点半,今晚因为一个ppt 弄到两点半~~改睡觉了~~~不然你又说又是老得快了~~

晚安了·亲耐滴~~今晚没有得聊天~也没有得说晚安~~

明天会是好心情~~~