首先是主界面的绘制。
我并没有在游戏中写登陆界面,因此只有一个activity。在主界面采取的是单击屏幕启动线程,因此需要给imageView添加OnTouchListener监听器。
需要知道的是,安卓中的UI线程是不安全的。更新UI只有在主线程中更新,因此最好在mainactivity中完成画布的布置。
监听类时用到了声明方法的匿名内部类:当某个类不是经常使用,如只使用一次,使用完后不保存该实例的对象,为了便于代码的编写常采用匿名内部类。下次再使用需要重新创建对象。 。
public class MainActivity extends Activity implements SensorEventListener {
Activity at;
ImageView imageView1;
TextView textView1;
Button button1;
Bitmap bitmap;
Canvas canvas;
Paint paint;
Myball myball;
float[] values;
int count = 0;
int firstClick = 0;
int secondClick = 0;
SensorManager sensorManager;// 定义系统的Sensor管理器
ArrayList<BallRun> list = new ArrayList<BallRun>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 实例化组件
textView1 = (TextView) findViewById(R.id.textView1);
imageView1 = (ImageView) findViewById(R.id.imageView1);
imageView1.setOnTouchListener(l);
}
private OnTouchListener l = new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
switch (arg1.getAction()) {
case MotionEvent.ACTION_DOWN:
if (bitmap == null) {
bitmap = Bitmap.createBitmap(imageView1.getWidth(),
imageView1.getHeight(), Config.ARGB_8888);
canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
paint = new Paint();
}
}
break;
default:
break;
}
return true;
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
然后是通过线程绘制运动的小球,这一部分和java中并没有很多的区别。最大的不同点就是在于线程的使用方法。
首先一个Ball类实现线程接口,生成小球(的数据),存入队列。
“`
public class Ball implements Runnable {
ImageView imageView1;
Handler handler;
Canvas canvas;
Paint paint = new Paint();
Bitmap bitmap;
float x, y, r,speedy,speedx;
ArrayList<BallRun> list;
int co;
Random ran = new Random();
public Ball(ImageView imageView1,ArrayList<BallRun> list,Canvas canvas,Paint paint,Bitmap bitmap) {
super();
this.imageView1 = imageView1;
this.list = list;
this.canvas = canvas;
this.paint = paint;
this.bitmap = bitmap;
}
@Override
public void run() {
int i = 0;
while (true) {
//Log.i("run", "调用线程Ball");
for(;i<15;i++){
//后面判断碰撞使用半径判断时,生成小球要确定至少距离边界长度有r,否则小球会在边界来回弹动
//圆心判断碰撞不存在这种问题,但不视觉效果
x = ran.nextInt((int) (imageView1.getWidth()-100))+50;
y = ran.nextInt((int) (imageView1.getHeight()-100))+50;
r = ran.nextInt(50) + 10;
speedx = ran.nextInt(20);
speedy = ran.nextInt(20);
co = Color.rgb(ran.nextInt(256), ran.nextInt(256), ran.nextInt(256));
//创建对象将数据存入队列
BallRun br = new BallRun(paint, canvas, bitmap, x, y, r, speedy, speedx, co,imageView1,list);
list.add(br);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
其次需要一个 小球方法类,根据需要写出小球的运动方法
需要注意的是,和java画小球一样,没有添加双缓冲技术时,小球移动的三种方法顺序是:擦除小球>移动小球>画小球
public class BallRun {
Paint paint;
Canvas canvas;
Bitmap bitmap;
ImageView imageView1;
float x, y, r,speedy,speedx;
int co;
ArrayList<BallRun> list;
public BallRun(Paint paint, Canvas canvas, Bitmap bitmap, float x, float y,
float r, float speedy, float speedx, int co,ImageView imageView1,ArrayList<BallRun> list) {
super();
this.paint = paint;
this.canvas = canvas;
this.bitmap = bitmap;
this.x = x;
this.y = y;
this.r = r;
this.speedy = speedy;
this.speedx = speedx;
this.co = co;
this.imageView1 = imageView1;
this.list = list;
}
//双缓冲使用后可以不用写擦除方法
public void ClearBall(){
//擦出小球
paint.setColor(Color.WHITE);
canvas.drawCircle(x, y, r, paint);
}
public void MoveBall(){
//小球移动
//Log.i("Ball", "调用MoveBall移动");
if (x < r || x + r > imageView1.getWidth())
speedx *= -1;
if (y < r || y + r > imageView1.getHeight())
speedy *= -1;
x += speedx;
y += speedy;
}
public void DrawBall(){
//小球
//Log.i("Ball", "调用DrawBall画球");
paint.setColor(co);
canvas.drawCircle(x, y, r, paint);
}
public void crash(ArrayList<BallRun> list){
for(int i = 0;i<list.size();i++){
BallRun br = list.get(i);//取出小球
if (br != this) {
float d = (this.x - br.x) * (this.x - br.x) + (this.y - br.y) * (this.y - br.y);
float e = (r + br.r) * (r + br.r);
if(d < e){
float a = speedx;
float b = speedy;
speedx = br.speedx;
speedy = br.speedy;
br.speedx = a;
br.speedy = b;
}
}
}
}
}
这里采取的是单独写出一个类画出自己的小球myball,方便与电脑小球区分(也是为了方便后续添加游戏规则)
注意,此时为了后续添加传感加速度,myball小球的move方法没有数据移动,只有一个固定不变的位置
public class Myball {
ImageView imageView1;
static Paint paint;
static Canvas canvas;
ArrayList<BallRun> list;
static float[] values;
static float x ,y ,xx,yy;
static float speedx ,speedxx;
static float speedy ,speedyy;
static float r ;
public Myball(ImageView imageView1, Paint paint, Canvas canvas,float[] values,ArrayList<BallRun> list) {
super();
this.imageView1 = imageView1;
this.paint = paint;
this.canvas = canvas;
this.values = values;
this.list = list;
x = imageView1.getWidth()/2;
y = imageView1.getHeight()/2;
r = imageView1.getWidth()/20;
}
public void ClearMyball(){
//擦除myball
paint.setColor(Color.WHITE);
canvas.drawCircle(x, y, r+1, paint);
}
public void MoveMyball(){
//为后续添加传感加速度准备,若想要其他控制方法可以自己编写
}
public void DrawMyball(){
//画出myball
paint.setColor(Color.BLACK);
canvas.drawCircle(x, y, 50, paint);
}
public static void separate(){
r -= 1;
}
public static void DrawBullet(){
//画出mybullet
xx = x;
yy = y;
paint.setColor(Color.RED);
canvas.drawCircle(xx, yy, 2, paint);
}
public static void MoveBullet(){
//移动mybullet
Log.i("MyBall", "调用MoveBullet");
speedxx = -1*values[0]*6;
speedyy = values[1]*6;
xx += -speedxx;
yy += -speedyy;
}
public void Crash(ArrayList<BallRun> list){
//myball和ball碰撞
for(int i = 0;i<list.size();i++){
BallRun br = list.get(i);
float d = (this.x - br.x) * (this.x - br.x) + (this.y - br.y) * (this.y - br.y);
float e = (r + br.r) * (r + br.r);
if(d < e){
br.speedx *= -1;
br.speedy *= -1;
}
}
}
}
然后在画小球类中通过线程画出小球,这里采用了次画布,所以不需要擦出方法
将画好小球的bitmap赋值给声明好的message对象,通过handler调用方法setmessage,将message对象寄给继承handler的类
Message msg = new Message();
msg.obj = bitmap;
handler.sendMessage(msg);
public class BallAI implements Runnable {
Handler handler;
Bitmap bitmap;
Paint paint;
Canvas canvas;
ImageView imageView1;
ArrayList<BallRun> list;
float[] values;
public BallAI(Paint paint,Canvas canvas,Handler handler, Bitmap bitmap, ImageView imageView1,ArrayList<BallRun> list,float[] values) {
super();
this.canvas = canvas;
this.paint = paint;
this.handler = handler;
this.bitmap = bitmap;
this.list = list;
this.imageView1 = imageView1;
this.values = values;
}
@Override
public void run() {
//实例化对象放在while(true)之外,只初始化一次
Myball myball = new Myball(imageView1, paint, canvas,values,list);
while (true) {
//次画布
paint.setColor(Color.WHITE);
canvas.drawRect(0, 0, imageView1.getWidth(), imageView1.getHeight(), paint);
//画出,移动myball
//myball.ClearMyball();
myball.MoveMyball();
myball.DrawMyball();
myball.Crash(list);
for (int i = 0; i < list.size(); i++) {
BallRun br = list.get(i);
//br.ClearBall();
br.MoveBall();
br.DrawBall();
br.crash(list);
}
Message msg = new Message();
msg.obj = bitmap;
handler.sendMessage(msg);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
ok到了这里,就要开始完成最重要的安卓UI的更新了,此处也就是线程的启动。
将小球画在bitmap上的之后,通过handler寄给继承handler的类中接收。
声明imageview对象调用方法将得到的message内容画在bitmap上。
值得一提的是:
方法的重写一定要加上 @Override检查是否正确!!
public class GetBall extends Handler{
Bitmap bitmap;
ImageView imageView1;
public GetBall(ImageView imageView1) {
super();
this.imageView1 = imageView1;
}
@Override
public void handleMessage(Message msg){
//Log.i("run", "收到一条消息");
bitmap = (Bitmap) msg.obj;
imageView1.setImageBitmap(bitmap);
}
}
经过这些准备工作就可以在主线程中启动线程将小球画在UI中咯!
// 实例化GetBall对象
GetBall handler = new GetBall(imageView1);
Ball ball = new Ball(imageView1, list, canvas, paint,
bitmap);
Thread th = new Thread(ball);
th.start();
BallAI ba = new BallAI(paint, canvas, handler, bitmap,
imageView1, list, values);
Thread te = new Thread(ba);
te.start();
贴上主线程完整代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 实例化组件
textView1 = (TextView) findViewById(R.id.textView1);
imageView1 = (ImageView) findViewById(R.id.imageView1);
imageView1.setOnTouchListener(l);
}
private OnTouchListener l = new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
switch (arg1.getAction()) {
case MotionEvent.ACTION_DOWN:
if (bitmap == null) {
bitmap = Bitmap.createBitmap(imageView1.getWidth(),
imageView1.getHeight(), Config.ARGB_8888);
canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
paint = new Paint();
}
// 实例化GetBall对象
GetBall handler = new GetBall(imageView1);
Ball ball = new Ball(imageView1, list, canvas, paint,
bitmap);
Thread th = new Thread(ball);
th.start();
BallAI ba = new BallAI(paint, canvas, handler, bitmap,
imageView1, list, values);
Thread te = new Thread(ba);
te.start();
count = 0;
break;
default:
break;
}
return true;
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
“`