初学者的漫步拾忆SurfaceView

版权声明:本文为博主原创文章,未经博主允许不得转载。 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

猜你喜欢

转载自blog.csdn.net/qq_36241003/article/details/75006571