整体实现思路
1、创建一个BackGround类,用来实现循环滚动的背景图片
2、分别创建一个MyPlane类与BossPlane类,绘制出玩家的飞机和Boss的飞机
3、绘制出子弹
4、判断碰撞,实现子弹与飞机之间的碰撞以及飞机与飞机之间的碰撞
5、绘制爆炸效果,当玩家子弹与Boss飞机碰撞时会出现爆炸的效果
6、添加音效,飞机发出子弹的时候还有发生碰撞的时候都会产生声音效果
如何绘制循环滚动的背景图片
首先把图片添加到mipmap,然后使用drawBitmap方法绘制背景图片,在屏幕上绘制两次,以此来实现最简单的地图滚动效果,而且图片的重复使用可以节约资源,当第一张背景图片移除屏幕时,立即把这张背景图片移至另一张背景图片的上方
代码如下:
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* 背景
*/
public class BackGroud {
private int y1;
private int y2;
private Bitmap bitmap;
public BackGroud(Bitmap bitmap){
this.bitmap = bitmap;
y1 = 0;
y2 = y1-bitmap.getHeight();
}
public void draw(Canvas canvas){
logic();
Paint paint = new Paint();
canvas.drawBitmap(bitmap,0, y1,paint);
canvas.drawBitmap(bitmap,0, y2,paint);
}
public void logic(){ //逻辑方法
y1+=10;
y2+=10;
if(y1>=bitmap.getHeight()){
y1 = y2-bitmap.getHeight(); //移动到第二张上面
}
if(y2>=bitmap.getHeight()){
y2=y1-bitmap.getHeight();
}
}
}
如何绘制飞机
给飞机定义一个初始位置,xy坐标默认为屏幕的最下方,但是要减去半个飞机的宽度,因为这样才能到达正中心,不然就会在中间偏右这个位置,其次就是添加飞机被击中闪烁 、无敌时间效果
代码如下:
public Myplane(Bitmap bitmap, Bitmap bitmapHp){
this.bitmap = bitmap;
this.bitmapHp = bitmapHp;
x = MySurfaceView.width/2-bitmap.getWidth()/2;
y = MySurfaceView.height-bitmap.getHeight();
width = bitmap.getWidth();
height = bitmap.getHeight();
}
public void draw(Canvas canvas,Paint paint){
if(hp<=0){
MySurfaceView.GAME_STATE = 2;
}
if (noCollision){
noCollisionCount++;
if (noCollisionCount%10==0){
canvas.drawBitmap(bitmap,x,y,paint);//飞机闪烁
}
if (noCollisionCount>100){//无敌时间
noCollision = false;
noCollisionCount = 0;
}
}else {
//非无敌状态
canvas.drawBitmap(bitmap,x,y,paint);
}
for (int i = 0; i<hp; i++){
canvas.drawBitmap(bitmapHp,i*bitmapHp.getWidth(),MySurfaceView.height-bitmapHp.getHeight(),paint);
}
}
如何绘制子弹
定义一个Vector数组存储Bullet的对象 ,因为Vector是线程安全的,在MySurfaceView中定义一个计数器count,每次运行run方法中while中的内容时,就让计数器count进行++。接着在while中进行判断,当count%50=0时,就往数组bullet中添加一个Bullet的对象,再用for循环bullet.elementAt(i)调用Bullet中的draw方法,设置每次画出子弹后让子弹的y轴–,最后判断子弹是否击中目标或者飞出屏幕,再选择是否remove该对象, Boss子弹同理 ,在此附上BossBullet的创建代码
代码如下:
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
public class Bullet {
private Bitmap bitmap;
private int x, y;
private int speed = 10;
private boolean isDead;
private int type;
public Bullet(Bitmap bitmap, int x, int y,int type) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
this.type = type;
}
public Bullet() {
}
public void draw(Canvas canvas, Paint paint) {
canvas.drawBitmap(bitmap, x, y, paint);
logic();
}
public void logic() {
switch (type){
//玩家子弹
case 0:
y -= speed+5;
if (y < 0) {
isDead = true;
}
break;
//Boss子弹
case 1:
y += speed+8;
if (y < 0) {
isDead = true;
}
break;
default:
break;
}
}
如何判断碰撞
1、飞机与子弹碰撞
碰撞的主要内容是进行判断,当飞机的坐标和子弹的坐标重合在一起的时候,就会实现玩家飞机血量的减少,以此来体现玩家飞机与子弹的碰撞,但是要做好几个判断。首先Boss子弹和玩家飞机碰撞的时候,当子弹的右边碰上飞机的左边并且子弹的左边小于飞机的左边、子弹的右边小于飞机的右边,当子弹的右边大于飞机的左边并且子弹的左边小于飞机的右边的时候就是飞机与子弹的碰撞。
public boolean isCollision(Bullet bullet) {
if (noCollision) {
return false;
}
if (bullet.getX() > x && bullet.getX() < x + width && bullet.getY() > y && bullet.getY() < y + height) {
noCollision = true;
if (Hp > 0) {
Hp--;
}
return true;
}
return false;
}
2、玩家飞机与Boss飞机碰撞
此处用到了方法的重写,判断的条件与子弹碰撞飞机一样
public boolean Attack(Bossplane bossplane) {
if (noCollision) {
return false;
}
if(y<bossplane.getY()+bossplane.getFrameH()&&y+height>bossplane.getY() ){
if (x < bossplane.getX() && x+width > bossplane.getX()) {//我方战机左边碰撞
noCollision = true;
if (Hp > 0) {
Hp--;
}
return true;
}
if (x > bossplane.getX() && x+width < bossplane.getX() + bossplane.getFrameW()) {//我方飞机中间碰撞
noCollision = true;
if (Hp > 0) {
Hp--;
}
return true;
}
if (x < bossplane.getX() && x+width > bossplane.getX()+bossplane.getFrameW()) {//我方飞机右边碰撞
noCollision = true;
if (Hp > 0) {
Hp--;
}
return true;
}
}
return false;
}
如何绘制爆炸效果
爆炸效果用到了图片的裁剪,需要每次往左偏移七分之一爆炸图片的宽度,因为我的爆炸图片是七帧的,这里的裁剪中高度都是一样的,所以可以不用裁剪,用W来除以总个数就可以了。
代码如下:
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
public class GameSoundPool {
private SoundPool soundPool;
private int s1;
private int s2;
private int s3;
}
public void playSound(int s) {
switch (s){
case 1:
soundPool.play(s1,1,1,1,1,1.0f);
break;
case 2:
soundPool.play(s2,1,1,1,1,1.0f);
break;
case 3:
soundPool.play(s3,1,1,1,1,1.0f);
break;
}
}
}
如何添加音效
创建一个GameSoundPool类 ,定义一个SoundPool对象 ,定义int对象 s,在构造方法中给s赋初始值,音乐文件用soundPool.play播放,在该音乐对应的事件发生时,用GameSoundPool的对象调用即可
代码如下:
package com.example.lenovo.myapplication;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
public class GameSoundPool {
private SoundPool soundPool;
private int s1;
private int s2;
public GameSoundPool(Context context){
this.soundPool = new SoundPool(2,AudioManager.STREAM_MUSIC,0);
this.soundPool = new SoundPool(1,AudioManager.STREAM_MUSIC,0);
s1 = soundPool.load(context,R.raw.shoot,1);
s2 = soundPool.load(context,R.raw.button,1);
}
public void playSound(){
soundPool.play(s1,1,1,1,1,1.0f);
soundPool.play(s2,1,1,1,1,1.0f);
}
}
用到封装、继承、多态、方法重载、接口的地方
封装
每一个类中的属性基本都用到了封装这个方法
继承
这个项目除了MySurfaceView类之外没有用到继承
public class MySurfaceView extends SurfaceView
多态
没用到,就不说了
方法重载
在飞机和子弹、飞机与飞机的碰撞中定义了同一个类名,但是它们的参数列表不一样,调用的时候,就会按照里面的参数来进行传参。
接口
在MysufaceView中实现了两个接口
SurfaceHolder.Callback与Runnable
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable
我的收获与感悟
因为之前没有接触过Android studio,所以运用起来感觉很陌生,大多数东西都是现学现用,不过也让我认识到了自学的重要性。经过这一个月的·实训,我也明白了知识在于积累,平时不努力,最后还是会自讨苦吃。以后我会认真学习知识,不能再做临时抱佛脚的事情。还有要感谢江哥,因为在江哥身上学到了很多东西,江哥不仅传授我们知识,还告诉了我们很多道理。而且江哥讲课也很好,说实话,之前的Java老师上课,我学的可以说是不怎么样,很多知识点掌握的都不牢固,现在江哥来上课,在传授知识的同时还告诉了我们很多编程的技巧,比如eclipse的快捷键等。一直以来都感觉自己的基础不好,时时会产生会不会跟不上的想法,但是现在我要用哈佛大学图书馆上面的名言来告诫自己,“觉得为时已晚的时候,恰恰是最早的时候!”