一個放煙花的android程序


HolderSurfaceView.java(看名字就知道這是個啥了)

package com.yh;

import android.graphics.PixelFormat;
import android.view.SurfaceView;

/**
 * 對surfaceView進行一些設置 這是一個單例
 * 
 * @author gary
 * 
 */
public class HolderSurfaceView {
    private HolderSurfaceView() {

    }

    private static HolderSurfaceView mHolderSurfaceView = null;

    public static HolderSurfaceView getInstance() {
        if (mHolderSurfaceView == null)
            mHolderSurfaceView = new HolderSurfaceView();
        return mHolderSurfaceView;
    }

    private SurfaceView mSurfaceView;

    /**
     * 設置SurfaceView
     * 
     * @param view
     */
    public void setSurfaceView(SurfaceView view) {
        mSurfaceView = view;
        mSurfaceView.setZOrderOnTop(true);
        mSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    }

    public SurfaceView getSurfaceView() {
        return mSurfaceView;
    }
}

 

DrawTop.java(其實沒怎么用到其中的代碼,這是為另一個目的編寫的代碼)

package com.yh;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawTopBase implements Runnable, Callback ,OnTouchListener{
    protected SurfaceView mSurfaceView;
    protected SurfaceHolder mSurfaceHolder;
    protected Context mContext;
    protected Rect mSurfaceRect = new Rect(0, 0, 0, 0);

    public DrawTopBase() {
        setSurfaceView(HolderSurfaceView.getInstance().getSurfaceView());
    }

    public void setSurfaceView(SurfaceView view) {
        mSurfaceView = view;
        mContext = mSurfaceView.getContext();
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceRect.set(new Rect(0, 0, mSurfaceView.getWidth(), mSurfaceView
                .getHeight()));
        set();
    }

    /**
     * 根據長寬來設置范圍
     */
    public void set() {
        setRect(mSurfaceRect);
    }

    protected Thread mThread = null;

    /**
     * 開始,為了必免重復開始,定義線程變量
     */
    public void begin() {
        if (mThread == null) {
            mThread = new Thread(this);
            mThread.start();
        }
    }

    public void end() {
        mStatus = DrawStatus.Ending;
    }

    /**
     * 畫內容
     * 
     * @param canvas
     */
    protected void doWork(Canvas canvas) {

    }

    /**
     * 結束工作
     */
    protected void endWork() {

    }

    protected Paint mPaint = new Paint();

    /**
     * 清空
     * 
     * @param canvas
     */
    protected void clear(Canvas canvas) {
        mPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
        canvas.drawPaint(mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC));
    }

    protected void clear() {
        synchronized (mSurfaceHolder) {
            Canvas canvas = this.mSurfaceHolder.lockCanvas();
            try {
                clear(canvas);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (canvas != null)
                    mSurfaceHolder.unlockCanvasAndPost(canvas);
            }
        }
    }

    protected void doChange() {
        change();
    }

    /**
     * 變化
     */
    protected void change() {

    }

    protected Rect mRect = new Rect(0, 0, 0, 0);

    public void setRect(Rect r) {
        mRect.set(r);
    }

    public Rect getRect() {
        return mRect;
    }

    protected DrawStatus mStatus = DrawStatus.NoWork;

    /**
     * 工作狀態 noWork 沒有工作 draw 在主循環中 end 正常結束 destroy 非正常結束
     * 
     * @author gary
     * 
     */
    protected enum DrawStatus {
        NoWork, Drawing, Ending, Destroyed
    };

    protected long mBegintime;

    @Override
    public void run() {
        mStatus = DrawStatus.Drawing;
        starttime = System.currentTimeMillis();
        mBegintime = System.currentTimeMillis();
        // 建立兩次緩存
        clear();
        clear();
        while (mStatus == DrawStatus.Drawing) {
            synchronized (mSurfaceHolder) {
                Canvas canvas = this.mSurfaceHolder.lockCanvas(getRect());
                try {
                    if (canvas != null) {
                        clear(canvas);
                        doWork(canvas);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (canvas != null)
                        mSurfaceHolder.unlockCanvasAndPost(canvas);
                }
                doChange();                
            }
            calculatePerframe();

        }
        if (mStatus != DrawStatus.Destroyed)
            clear();
        mThread = null;
        endWork();
    }

    protected long starttime;
    // 每幀時間 60幀附近 第一次計算前使用 毫秒
    private float perframe = 16;

    private int count = 0;

    // 每隔多長時間測試一次幀時間
    private int mRefreshSpeed = 12;

    // 設定要求多長時間每幀 24幀每秒
    private float mFPS = 1000 / 12;
    private float sleep = mFPS;

    // 設置刷新頻率
    public void setFPS(int fps) {
        mFPS = 1000 / fps;
    }

    /**
     * 等待時間
     */
    protected void calculatePerframe() {
        count++;
        if (count == mRefreshSpeed) // 由於每幀計算會降低游戲效率。20到50差不多
        {
            long timepass = System.currentTimeMillis();
            long time = timepass - starttime;
            perframe = time / mRefreshSpeed;// 每幀時間
            sleep = perframe > mFPS ? mFPS - (perframe - mFPS) / mRefreshSpeed
                    : mFPS;
            starttime = timepass;
            count = 0;
        }
        try {
            Thread.sleep((long) (sleep));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        mSurfaceRect.set(new Rect(0, 0, width, height));
        set();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mStatus = DrawStatus.Destroyed;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        return false;
    }
}

GameSoundMedia.java(這也是來自另一個項目懶得重寫)

View Code
package com.yh;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.media.MediaPlayer;

/**
 * 需要返回值
 * 
 * @author gary
 * 
 */
public class GameSoundMedia {
    public static final int GAME_SOUND_MEDIA_COMPLETION = 1;
    private Context mContext;

    public GameSoundMedia(Context context) {
        mContext = context;
    }

    private List<MediaPlayer> mList = new ArrayList<MediaPlayer>();

    public void stopAll() {
        for (MediaPlayer i : mList) {
            if (i != null) {
                try {
                    if (i.isPlaying()) {
                        i.stop();
                        i.release();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } 
        }
        mList.clear();
    }

    public MediaPlayer playInMediaPlayer(int resid, final GameSoundEvent event) {
        MediaPlayer player = MediaPlayer.create(mContext, resid);
        player.start();
        player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if (event != null)
                    event.onEvent(GAME_SOUND_MEDIA_COMPLETION);
                mp.release();
                mList.remove(mp);
            }
        });
        mList.add(player);
        return player;
    }

    public interface GameSoundEvent {
        public void onEvent(int what);
    }
}

 

GameSoundPool.java(這個也是)

View Code
package com.yh;

import java.util.HashMap;

import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;

/**
 * 多音效
 * @author gary
 *
 */
public class GameSoundPool {
    private Context mContext;

    public GameSoundPool(Context context) {
        mContext = context;
        initSounds();
    }

    // 音效的音量
    int streamVolume;

    // 定義SoundPool對象
    private SoundPool soundPool;

    // 定義HASH表
    private HashMap<Integer, Integer> soundPoolMap;

    /***************************************************************
     * Function:initSounds(); Parameters:null Returns:None. Description:初始化聲音系統
     * Notes:none.
     ***************************************************************/
    public void initSounds() {
        // 初始化soundPool對象,第一個參數是允許有多少個聲音流同時播放,第2個參數是聲音類型,第三個參數是聲音的品質
        soundPool = new SoundPool(100, AudioManager.STREAM_MUSIC, 100);

        // 初始化HASH表
        soundPoolMap = new HashMap<Integer, Integer>();

        // 獲得聲音設備和設備音量
        AudioManager mgr = (AudioManager) mContext
                .getSystemService(Context.AUDIO_SERVICE);
        streamVolume = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
    }

    /***************************************************************
     * Function:loadSfx(); Parameters:null Returns:None. Description:加載音效資源
     * Notes:none.
     ***************************************************************/
    public void loadSfx(int raw, int ID) {
        // 把資源中的音效加載到指定的ID(播放的時候就對應到這個ID播放就行了)
        soundPoolMap.put(ID, soundPool.load(mContext, raw, ID));
    }

    /***************************************************************
     * Function:play(); Parameters:sound:要播放的音效的ID,loop:循環次數 Returns:None.
     * Description:播放聲音 Notes:none.
     ***************************************************************/
    public void play(int sound, int uLoop) {
        soundPool.play(soundPoolMap.get(sound), streamVolume, streamVolume, 1,
                uLoop, 1f);
        
    }
}

DrawYH.java(重要代碼,這個是從網找到的那個煙花代碼改裝的,里面有一些關鍵位置改一改會有不同效果)

View Code
package com.yh;

import java.util.Random;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;

public class DrawYH extends DrawTopBase {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        super.surfaceCreated(holder);
        this.begin();
        stopBGMedia();
        bgMedia = new GameSoundMedia(mContext);
        bgMedia.playInMediaPlayer(R.raw.bg, null);
    }

    private void stopBGMedia() {
        if (bgMedia != null) {
            try {
                bgMedia.stopAll();                
                bgMedia = null;
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        stopBGMedia();
        super.surfaceDestroyed(holder);
    }

    @Override
    public void set() {
        super.set();
        if (this.getRect().width() > 10 && this.getRect().height() > 10)
            init();
    }

    public DrawYH() {
        super();
        m_mouseX = 0;
        m_mouseY = 0;
        m_sleepTime = 5;
        isError = false;
        isInitialized = false;
        rand = new Random();
        bits = 10000;
        bit_px = new double[bits];
        bit_py = new double[bits];
        bit_vx = new double[bits];
        bit_vy = new double[bits];
        bit_sx = new int[bits];
        bit_sy = new int[bits];
        bit_l = new int[bits];
        bit_f = new int[bits];
        bit_p = new int[bits];
        bit_c = new int[bits];
        ru = 50;
        rv = 50;
        // init();
    }

    Canvas mCanvas;
    private Rect drawRect = new Rect(0, 0, 0, 0);
    GameSoundMedia sm;

    private GameSoundPool soundPool;
    private int id_sound1 = R.raw.firework;
    private int id_sound2 = R.raw.syu;
    GameSoundMedia bgMedia;

    public void init() {
        soundPool = new GameSoundPool(mContext);
        // Log.i("gary", mContext.toString());
        soundPool.loadSfx(R.raw.firework, id_sound1);
        soundPool.loadSfx(R.raw.syu, id_sound2);
        // soundPool.loadSfx(R.raw.bg, id_bg);

        m_nAppX = this.getRect().width() / 2;
        m_nAppY = this.getRect().height() / 2;
        drawRect = new Rect(0, 0, m_nAppX, m_nAppY);
        m_centerX = m_nAppX / 2;
        m_centerY = m_nAppY / 2;
        m_mouseX = m_centerX;
        m_mouseY = m_centerY;
        // resize(m_nAppX, m_nAppY);
        pixls = m_nAppX * m_nAppY;
        pixls2 = pixls - m_nAppX * 2;
        pix0 = new int[pixls];
        offImage = Bitmap.createBitmap(m_nAppX, m_nAppY,
                Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas();
        mCanvas.setBitmap(offImage);
        for (int i = 0; i < pixls; i++)
            pix0[i] = 0xff000000;

        // sound1 = getAudioClip(getDocumentBase(), "firework.au");
        // sound2 = getAudioClip(getDocumentBase(), "syu.au");
        for (int j = 0; j < bits; j++)
            bit_f[j] = 0;

        isInitialized = true;
    }

    @Override
    protected void doWork(Canvas canvas) {
        // TODO Auto-generated method stub
        super.doWork(canvas);
        if (offImage != null)
            canvas.drawBitmap(offImage, drawRect, this.getRect(), mPaint);
         
    }

    @Override
    protected void change() {
        super.change();
        if (isInitialized) {
            for (int j = 0; j < pixls2; j++) {
                int k = pix0[j];
                int l = pix0[j + 1];
                int i1 = pix0[j + m_nAppX];
                int j1 = pix0[j + m_nAppX + 1];
                int i = (k & 0xff0000) >> 16;
                int k1 = ((((l & 0xff0000) >> 16) - i) * ru >> 8) + i;
                i = (k & 0xff00) >> 8;
                int l1 = ((((l & 0xff00) >> 8) - i) * ru >> 8) + i;
                i = k & 0xff;
                int i2 = (((l & 0xff) - i) * ru >> 8) + i;
                i = (i1 & 0xff0000) >> 16;
                int j2 = ((((j1 & 0xff0000) >> 16) - i) * ru >> 8) + i;
                i = (i1 & 0xff00) >> 8;
                int k2 = ((((j1 & 0xff00) >> 8) - i) * ru >> 8) + i;
                i = i1 & 0xff;
                int l2 = (((j1 & 0xff) - i) * ru >> 8) + i;
                int i3 = ((j2 - k1) * rv >> 8) + k1;
                int j3 = ((k2 - l1) * rv >> 8) + l1;
                int k3 = ((l2 - i2) * rv >> 8) + i2;
                pix0[j] = i3 << 16 | j3 << 8 | k3 | 0x77000000;
                // if(pix0[j]==0x77000000)pix0[j]=0x55000000;
            }

            rend();

            mCanvas.drawBitmap(pix0, 0, m_nAppX, 0, 0, m_nAppX, m_nAppY, true,
                    mPaint);
        }
    }

    public void dot() {
        dot(rand.nextInt(m_nAppX), rand.nextInt(m_nAppY));
    }

    public void dot(int x, int y) {
        m_mouseX = x;
        m_mouseY = y;
        int k = (int) (rand.nextDouble() * 256D);
        int l = (int) (rand.nextDouble() * 256D);
        int i1 = (int) (rand.nextDouble() * 256D);
        int j1 = k << 16 | l << 8 | i1 | 0xff000000;
        int k1 = 0;
        for (int l1 = 0; l1 < bits; l1++) {
            if (bit_f[l1] != 0)
                continue;
            bit_px[l1] = m_mouseX;
            bit_py[l1] = m_mouseY;
            double d = rand.nextDouble() * 6.2800000000000002D;
            double d1 = rand.nextDouble();
            bit_vx[l1] = Math.sin(d) * d1;
            bit_vy[l1] = Math.cos(d) * d1;
            bit_l[l1] = (int) (rand.nextDouble() * 100D) + 100;
            bit_p[l1] = (int) (rand.nextDouble() * 3D);
            bit_c[l1] = j1;
            bit_sx[l1] = m_mouseX;
            bit_sy[l1] = m_nAppY - 5;
            bit_f[l1] = 2;
            if (++k1 == bit_max)
                break;
        }
    }

    void rend() {
        boolean flag = false;
        boolean flag1 = false;
        boolean flag2 = false;
        for (int k = 0; k < bits; k++)
            switch (bit_f[k]) {
            default:
                break;

            case 1: // '\001'
                bit_vy[k] += rand.nextDouble() / 50D;
                bit_px[k] += bit_vx[k];
                bit_py[k] += bit_vy[k];
                bit_l[k]--;
                if (bit_l[k] == 0 || bit_px[k] < 0.0D || bit_py[k] < 0.0D
                        || bit_px[k] > (double) m_nAppX
                        || bit_py[k] > (double) (m_nAppY - 3)) {
                    bit_c[k] = 0xff000000;
                    bit_f[k] = 0;
                } else if (bit_p[k] == 0) {
                    if ((int) (rand.nextDouble() * 2D) == 0)
                        bit_set((int) bit_px[k], (int) bit_py[k], -1);
                } else {
                    bit_set((int) bit_px[k], (int) bit_py[k], bit_c[k]);
                }
                break;

            case 2: // '\002'
                bit_sy[k] -= 5;
                if ((double) bit_sy[k] <= bit_py[k]) {
                    bit_f[k] = 1;
                    flag2 = true;
                }
                if ((int) (rand.nextDouble() * 20D) == 0) {
                    int i = (int) (rand.nextDouble() * 2D);
                    int j = (int) (rand.nextDouble() * 5D);
                    bit_set(bit_sx[k] + i, bit_sy[k] + j, -1);
                }
                break;
            }

        if (flag2 && bit_sound > 0)
            // sm.playInMediaPlayer(R.raw.firework, null);
            soundPool.play(id_sound1, 0);
    }

    void bit_set(int i, int j, int k) {
        int l = i + j * m_nAppX;
         pix0[l] = k;
    }

    protected void calculatePerframe() {
          try {
            Thread.sleep(m_sleepTime);
        } catch (InterruptedException e) { 
            e.printStackTrace();
        }
    }

    private int m_nAppX;
    private int m_nAppY;
    private int m_centerX;
    private int m_centerY;
    private int m_mouseX;
    private int m_mouseY;
    private int m_sleepTime;
    private boolean isError;
    private boolean m_isPaintFinished;
    boolean isRunning;
    boolean isInitialized;
    Thread runner;
    int pix0[];
    Bitmap offImage;
    // Image dbImg;
    int pixls;
    int pixls2;
    Random rand;
    int bits;
    double bit_px[];
    double bit_py[];
    double bit_vx[];
    double bit_vy[];
    int bit_sx[];
    int bit_sy[];
    int bit_l[];
    int bit_f[];
    int bit_p[];
    int bit_c[];
    int bit_max = 100;
    int bit_sound = 2;
    int ru;
    int rv;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // return super.onTouch(v, event);
        int x = (int) event.getX();
        int y = (int) event.getY();
        x = x / 2;
        y = y / 2;
        if (x > m_nAppX)
            x = m_nAppX;
        if (y > m_nAppY)
            y = m_nAppY;
        if (x < 0)
            x = 0;
        if (y < 0)
            y = 0;
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:

            break;
        case MotionEvent.ACTION_UP:
            this.dot(x, y);
            if (this.bit_sound > 1)
                // sm.playInMediaPlayer(R.raw.syu, null);
                soundPool.play(id_sound2, 0);
            break;
        }
        m_mouseX = x;
        m_mouseY = y;
        return true;
    }
}

使用例子

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.main);
        SurfaceView v = new SurfaceView(this);
        HolderSurfaceView.getInstance().setSurfaceView(v);
        v.setBackgroundResource(R.drawable.bg);
        this.setContentView(v);
        DrawYH yh=new DrawYH();        
        v.setOnTouchListener(yh);
        yh.begin();

最終效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM