版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36241003/article/details/75006571
学习编程两年了.
我却始终在和switch语句,界面UI做斗争.
学过不少东西,不过还是毛都不懂.
或者说我已经从入门到放弃了吧.
可笑啊.
不甘堕落却又不思进取.
懒惰却总像是潜藏在身体的瘾,稍有怠慢便上了瘾.
惶恐,不安,百无聊赖.
好了,梳理了下心情,开始干正事.
分享学习到的基础小案例,涉及到SurfaceView ,SurfaceHolder,Surface,Thread方面的知识.
想学习的同学可以滑动页面到最底部.
MainActivity
package com.example.luokexi.gameuidayone;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
public class MainActivity extends Activity {
private GameUI gameUI;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//no title
//requestWindowFeature(Window.FEATURE_NO_TITLE);
//no bar
//getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
// WindowManager.LayoutParams.FLAG_FULLSCREEN);
gameUI = new GameUI(this);
setContentView(gameUI);//底部支持一个view对象
}
/**
*
* @param event 响应触摸事件 发射炸弹
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
gameUI.handleTouch(event);
return true;
}
}
AndroidMainfest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.luokexi.gameuidayone">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
GameUI
package com.example.luokexi.gameuidayone;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.example.luokexi.gameuidayone.domain.Bomb;
import com.example.luokexi.gameuidayone.domain.Boy;
import com.example.luokexi.gameuidayone.domain.MyButton;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
import static android.R.attr.button;
/**
* Created by Luokexi on 2017/7/1.
*/
public class GameUI extends SurfaceView implements SurfaceHolder.Callback{
private boolean isRender ; // 标记是否开启线程
private MyButton mButton;
//private Bomb bomb;
private Boy boy;
// private ArrayList<Bomb> bombList = new ArrayList<Bomb>();
private CopyOnWriteArrayList<Bomb> bombList = new CopyOnWriteArrayList<Bomb>();
public GameUI(Context context) {
super(context);
SurfaceHolder holder = getHolder();//获取放映机
holder.addCallback(this);//添加会调
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isRender = true;
boy = new Boy(BitmapFactory.decodeResource(getResources(),
R.drawable.boy),new Point(0,0));
// bomb = new Bomb(BitmapFactory.decodeResource(getResources(),
// R.drawable.ic_bomb),new Point(0,0),new Point(200,200));
mButton = new MyButton(BitmapFactory.decodeResource(getResources(),
R.drawable.bottom),BitmapFactory.decodeResource(getResources(),
R.drawable.bottom_pass),new Point(30,getHeight()-400));
mButton.setClickListener(new MyButton.ClickListener() {
@Override
public void click() {
Log.d("TAG","被点击");
//boy.move(Boy.MOVE_DOWN);
int y = getHeight() - boy.mDefaultBitmap.getHeight();
if(boy.mPoint.y < y){
boy.move(Boy.MOVE_DOWN);
}
}
});
RenderThread renderThread = new RenderThread();
renderThread.start();//开启绘制线程
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isRender = false;
}
/**
*
* @param event 响应触摸事件 发射炸弹
* @return
*/
public void handleTouch(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
Point point = new Point(x,y);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if (!mButton.isClick(point)) {
Bomb bomb = boy.createBomb(getContext(), point);
bombList.add(bomb);
}else {
System.out.println("按钮被点击");
}
break;
case MotionEvent.ACTION_UP:
mButton.setClick(false);//抬起时需要将图片设为默认
default:
break;
}
}
/**
* 开启子线程 绘制界面
*/
class RenderThread extends Thread{
@Override
public void run() {
// while不断循环 保证界面不断发生变化 从而实现动画效果
while (isRender){
drawUI();
}
}
}
private void drawUI(){
//绘制界面
Canvas canvas = getHolder().lockCanvas();//获取画布对象
if(canvas != null){
Paint paint = new Paint();
paint.setColor(Color.WHITE);
canvas.drawRect(0,0,getWidth(),getHeight(),paint); //画矩形
boy.drawSelf(canvas);//绘制男孩对象
mButton.drawSelf(canvas);//绘制按钮
// if (bomb != null) {
// bomb.drawSelf(canvas);//绘制炸弹对象
// bomb.move();//炸弹移动
// }
//遍历炸弹集合画出所有炸弹
// for (int i = 0;i<bombList.size();i++){
// Bomb bomb = bombList.get(i);
// bomb.drawSelf(canvas);//绘制炸弹对象
// bomb.move();//炸弹移动
// //判断炸弹是否移除屏幕
// Point point = bomb.getPoint();
// if(point.x>getWidth()||point.x<0
// ||point.y>getHeight()||point.y<0){
// bombList.remove(i);
// } 这里用for循环会出现并发修改异常
// ArrayList<Bomb> list = new ArrayList<Bomb>();
// list.addAll(bombList);
for (Bomb bomb : bombList) {
bomb.drawSelf(canvas);
bomb.move();
//判断炸弹是否移除屏幕
Point point = bomb.getPoint();
if (point.x > getWidth() || point.x < 0
|| point.y > getHeight() || point.y < 0) {
bombList.remove(bomb);
}
}
getHolder().unlockCanvasAndPost(canvas);//提交画布
}
}
}
接下来是三个Sprite基类
Bomb
package com.example.luokexi.gameuidayone.domain;
import android.graphics.Bitmap;
import android.graphics.Point;
/**
* Created by Luokexi on 2017/7/1.
*/
public class Bomb extends Sprite {
private int speed =200;//移动速度
private int dx;//移动时x的偏移量
private int dy;//移动时y的偏移量
public Bomb(Bitmap mDefaultBitmap, Point point,Point targetPoint) {
super(mDefaultBitmap, point); // 当前坐标点 point(从父类里得到的坐标点) 目标坐标点 targetPoint
int x = targetPoint.x - point.x;
int y = targetPoint.y - point.y;
int d = (int) Math.sqrt(x*x + y*y);//获取炸弹移动距离
dx = x * speed /d;
dy = y * speed /d;
}
/**
* move 炸弹移动
*/
public void move(){
mPoint.x += dx;
mPoint.y += dy;
}
/**
* 获取炸弹坐标点
* @return
*/
public Point getPoint(){
return mPoint;
}
}
Boy
package com.example.luokexi.gameuidayone.domain;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import com.example.luokexi.gameuidayone.R;
/**
* Created by Luokexi on 2017/7/1.
*/
public class Boy extends Sprite {
public static final int MOVE_DOWN= 0;
public static final int MOVE_UP = 1;
public static final int MOVE_LEFT = 2;
public static final int MOVE_RIGHT = 3;
private Bomb bomb;
private int speed = 5;//男孩移动的速度
public Boy(Bitmap mDefaultBitmap, Point mPoint) {
super(mDefaultBitmap, mPoint);
}
/**
* 产生炸弹
* @return
* 目标点 targetPoint
*/
public Bomb createBomb(Context cxt,Point targetPoint){
bomb = new Bomb(BitmapFactory.decodeResource(cxt.getResources(),
R.drawable.ic_bomb1),new Point(mPoint.x+100,mPoint.y+225),targetPoint);
return bomb;
}
/**
* 男孩移动
* @param direction
*/
public void move(int direction){
switch (direction){
case MOVE_DOWN:
mPoint.y += speed;
break;
default:
break;
}
}
}
MyButton
package com.example.luokexi.gameuidayone.domain;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by Luokexi on 2017/7/1.
*/
public class MyButton extends Sprite {
private boolean isClick;//标记按钮是否被点击
private Bitmap mPressBitMap;//被点击后的图片
private Timer timer;//定时器一点一点走
public MyButton(Bitmap mDefaultBitmap, Bitmap mPressBitMap,Point mPoint) {
super(mDefaultBitmap, mPoint);
this.mPressBitMap = mPressBitMap;
}
/**
* 判断按钮是否被点击
* @param point
* @return
*/
public boolean isClick(Point point){
//获取按钮所在的矩形区域
Rect rect = new Rect(mPoint.x,mPoint.y,mPoint.x
+ mDefaultBitmap.getWidth(), mPoint.y
+ mDefaultBitmap.getHeight());
isClick = rect.contains(point.x,point.y);
if (isClick){
if (clickListener != null){
//启动一个定时器,当按住按钮不放时小人可以一直持续移动
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
clickListener.click();
}
},0,200);
}
}
return isClick;
}
private ClickListener clickListener;
//设置按钮点击监听
public void setClickListener(ClickListener clickListener){
this.clickListener = clickListener;
}
/**
* 按钮点击的回调接口
*/
public interface ClickListener{
public void click();
}
public void setClick(boolean isClick){
this.isClick = isClick;
if (!isClick){
if (timer != null){
timer.cancel();//停止定时器
}
}
}
@Override
public void drawSelf(Canvas canvas) {
if(!isClick){
super.drawSelf(canvas);
}else {
//mPressBitMap 按钮被点击后的图片
canvas.drawBitmap(mPressBitMap,mPoint.x,mPoint.y,null);//绘制图片
}
}
}
Sprite
package com.example.luokexi.gameuidayone.domain;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
/**
* 精灵基类
*
*/
public class Sprite {
public Bitmap mDefaultBitmap;
public Point mPoint;
public Sprite(Bitmap mDefaultBitmap, Point mPoint) {
this.mDefaultBitmap = mDefaultBitmap;
this.mPoint = mPoint;
}
public void drawSelf(Canvas canvas){
if (mDefaultBitmap != null) {
canvas.drawBitmap(mDefaultBitmap, mPoint.x, mPoint.y, null);//绘制图片
}
}
}
res/drawable文件夹下的图片
boy.png
ic_bomb1.png
botttom.png
botttom_pass.png
案例实现
以上案例讲解请见 http://pan.baidu.com/s/1qYRqzpE