消消乐学习心得
设计思路
一、实体类,封装一个水果图标。包含x,y坐标,图片(bitmap),一个id用于匹配,宽、高
二、布局方面一个Activity和一个自定义的View,主角当然是我们这个View。
三、在构造方法里面初始化游戏相关数据
public GameView(Context context, AttributeSet attr) {
super(context, attr);
screenHeight = DisplayUtil.getScreenHeight(context);
screenWidth = DisplayUtil.getScreenWidth(context);
// 音乐相关初始化
bgMedia = MediaPlayer.create(this.getContext(), R.raw.bg_game);
bgMedia.setOnCompletionListener(this);
bgMedia.start();
// swap = MediaPlayer.create(this.getContext(), R.raw.swap);
// int ave = screenWidth / (row + 2); // 将屏幕宽度分为 row + 2 等份
int ave = 0;
int size = (screenWidth - ave * 2) / row; // 其它两分为:舞台距离屏幕左右边的像素
ZooUtil.initZooData(size, size, this.getResources()); // 初始化动物头像数据
// 背景图片
background = BitmapFactory.decodeResource(this.getResources(), R.mipmap.game_bg);
floorBg = BitmapFactory.decodeResource(this.getResources(), R.mipmap.floor_bg);
/*
* 计算出舞台距离左边屏幕的距离
* 计算方式为:
* (屏幕总宽度 - 人物头像的宽 * 总行数) / 2
*/
int leftSpan = (screenWidth - ZooUtil.getAnimalWidth() * row) / 2;
int topSpan = (screenHeight - ZooUtil.getAnimalHeight() * col) / 3;
// 将游戏舞台的坐标、高宽保存起来
StageUtil.initStage(leftSpan, topSpan,
leftSpan + ZooUtil.getAnimalWidth() * row,
topSpan + ZooUtil.getAnimalHeight() * col);
// 实例化画笔
paint = new Paint();
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true); // 消除锯齿
initGamePoint();
}
/**
* 生成游戏坐标
*/
private void initGamePoint() {
currScore = 0; // 清空当前得分
bitmaps = new FlashBitmap[row][col];
// 生成背景图片的坐标(仅背景图片,后续可考虑将特效也加进来)
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
do {
// 计算头像坐标
FlashBitmap bitmap = ZooUtil.getAnimal();
bitmap.setX(StageUtil.getStage().getX() + i * ZooUtil.getAnimalWidth());
bitmap.setY(StageUtil.getStage().getY() + j * ZooUtil.getAnimalHeight());
transBitmap[i][j] = bitmap.clone();
bitmap.setY(0); // 在顶部慢慢下落
bitmaps[i][j] = bitmap;
} while(StageUtil.checkClearPoint(bitmaps));
}
}
}
四、重写该View的onDraw方法,在这个方法里面进行水果图像的绘制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制背景图片
Bitmap bgBitmap = DisplayUtil.resizeBitmap(background, screenWidth, screenHeight);
canvas.drawBitmap(bgBitmap, 0, 0, paint);
Bitmap floor = DisplayUtil.resizeBitmap(floorBg, ZooUtil.getAnimalWidth(), ZooUtil.getAnimalHeight());
// 每一个小头像背后的背景
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
if(transBitmap[i][j] != null){
int x = (int) transBitmap[i][j].getX();
int y = (int) transBitmap[i][j].getY();
canvas.drawBitmap(floor, x, y, paint);
}
}
}
// 舞台中的所有动物头像
FlashBitmap bitmap;
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
bitmap = bitmaps[i][j];
if(bitmap != null // 不为空并且坐标点要进入舞台
&& StageUtil.inStage(bitmap.getX(), bitmap.getY() + bitmap.getHeight() / 2)){
canvas.drawBitmap(bitmap.getBitmap(), bitmap.getX(), bitmap.getY(), paint);
}
}
}
// 是否需要加载消除
synchronized (this){
if (load) {
pool.execute(new Runnable() {
@Override
public void run() {
clearBitmap();
}
});
load = false;
}
}
paint.setColor(Color.WHITE);
paint.setTextSize(32);
paint.setTypeface(Typeface.create(Typeface.DEFAULT_BOLD , Typeface.BOLD));
canvas.drawText("当前关卡:" + level, 10, StageUtil.getStage().getHeight() + 70, paint);
canvas.drawText("当前得分:" + currScore, 10, StageUtil.getStage().getHeight() + 120, paint);
canvas.drawText("通关分数:" + accessScore[level - 1], 10, StageUtil.getStage().getHeight() + 170, paint);
// 刷新屏幕的频率(理论上小于25,人就会感觉物体是在移动)
postInvalidateDelayed(1);
}
五、重写onTouchEvent方法监听该View的按下、抬起、移动等相关事件
@Override
public boolean onTouchEvent(MotionEvent event) {
// 判断交换状态是否完毕
if(swapState){
return false;
}
// 如果正在做下落动画不允许操作
if(loadAnimalState){
return false;
}
// 获取当前触控位置
float ex = event.getX();
float ey = event.getY();
switch (event.getAction()) {
// 按下
case MotionEvent.ACTION_DOWN:
// 判断是否该点是按在舞台上
if (!isDown && StageUtil.inStage(ex, ey)) {
p1.setX(ex);
p1.setY(ey);
isDown = true;
}
break;
// 移动
case MotionEvent.ACTION_MOVE:
// 判断是否该点是按在舞台上
if (!isDown && StageUtil.inStage(ex, ey)) {
p1.setX(ex);
p1.setY(ey);
isDown = true;
}
break;
// 抬起
case MotionEvent.ACTION_UP:
if (isDown) {
p2.setX(ex);
p2.setY(ey);
isDown = false;
prepSwap(); // 预处理交换
}
break;
}
// 使系统响应事件,返回true
return true;
}
总结
结合坦克大战的制作经验,深刻的认识了多线程,用安卓做的,其实安卓里面嵌入H5也比较合适的。(新人,不喜勿喷)