Android 自定義 View 之彈球游戲

主程序代碼:

package com.toby.personal.testlistview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    final private static String TAG = "Toby_Test";
    final private static int MSG_WHAT = 170411;

    private boolean isOver = false;

    // 桌面的寬高
    private int tableWidth;
    private int tableHeight;
    // 球拍的垂直位置
    private int racketY;
    // 球拍的寬高
    private final int RACKET_WIDTH = 70;
    private final int RACKET_HEIGHT = 20;
    // 小球的大小
    private final int BALL_SIZE = 12;
    // 小球的縱向速度
    private int ySpeed = 20;
    private Random random = new Random();
    // 返回一個(gè)介于 -0.5 ~ 0.5 之間的比率,用于控制小球的運(yùn)行方向
    private double xyRate = random.nextDouble() - 0.5;
    // 小球的橫向速度
    private int xSpeed = (int) (ySpeed * xyRate * 2);
    // 小球的坐標(biāo)
    private int ballX = random.nextInt(200) + 20;
    private int ballY = random.nextInt(10) + 20;
    // 球拍的水平位置
    private int racketX = random.nextInt(200);

    // 球拍上次的 x 坐標(biāo)
    private float racketLastX = racketX;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        final GameView gameView = new GameView(this);
        setContentView(gameView);

        WindowManager windowManager = getWindowManager();
        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();
        display.getMetrics(metrics);

        tableWidth = metrics.widthPixels;
        tableHeight = metrics.heightPixels - 400;

        racketY = tableHeight - 80;

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == MSG_WHAT) {
                    gameView.invalidate();
                }
                super.handleMessage(msg);
            }
        };

        gameView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                float x = event.getX();

                if (x < racketLastX) {
                    if (racketX > 0) racketX -= 10;
                } else {
                    if (racketX < tableWidth - RACKET_WIDTH) racketX += 10;
                }

                racketLastX = x;
                return true;
            }
        });

        final Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (ballX <= 0 || ballX >= tableWidth - BALL_SIZE) {
                    xSpeed = -xSpeed;
                }

                if (ballY >= racketY - BALL_SIZE
                        && (ballX < racketX || ballX > racketX + RACKET_WIDTH)) {
                    timer.cancel();
                    isOver = true;
                } else if (ballY <= 0 || (ballY >= racketY - BALL_SIZE
                        && ballX > racketX && ballX <= racketX + RACKET_WIDTH)) {
                    ySpeed = -ySpeed;
                }

                ballY += ySpeed;
                ballX += xSpeed;

                handler.sendEmptyMessage(MSG_WHAT);
            }
        }, 0, 100);

    }

    class GameView extends View {
        Paint paint = new Paint();

        public GameView(Context context) {
            super(context);
            setFocusable(true);
            paint.setStyle(Paint.Style.FILL);
            paint.setAntiAlias(true);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawColor(Color.GRAY);
            if (isOver) {
                paint.setColor(Color.RED);
                paint.setTextSize(40);
                canvas.drawText("Game Over!", 50, 200, paint);
            } else {
                paint.setColor(Color.rgb(240, 240, 80));
                canvas.drawCircle(ballX, ballY, BALL_SIZE, paint);

                paint.setColor(Color.rgb(80, 80, 200));
                canvas.drawRect(racketX, racketY, racketX + RACKET_WIDTH, racketY + RACKET_HEIGHT,
                        paint);
            }
        }
    }

}

運(yùn)行效果:

顯示效果

本文參考文獻(xiàn):《瘋狂Android講義 : 第2版

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,466評(píng)論 25 708
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,973評(píng)論 19 139
  • 文:小耳機(jī)七七 影評(píng)《陸垚知馬俐》 兩個(gè)人,一個(gè)高傲,一個(gè)自卑,明明相愛(ài),卻在徘徊中丟失了那么多美好的時(shí)光。那些錯(cuò)...
    小七七大哈哈閱讀 992評(píng)論 4 12
  • 最近什么都不怕,連我媽我姐囑咐我的不要出門(mén)的話(huà)都不聽(tīng),我懷疑我腦袋有病,因?yàn)椴宦?tīng)老人言,吃虧在眼前。 來(lái)到遠(yuǎn)方上大...
    方禾6666閱讀 217評(píng)論 0 0
  • 喧囂的塵世 此刻靜謐無(wú)比 想起他的柔情萬(wàn)分 流淌過(guò)心里的痕跡 有人在此刻遙喚著遠(yuǎn)方的那個(gè)人 喚他的乳名 只屬于她的...
    安飛灑閱讀 238評(píng)論 0 1