天天看點

android畫圖之貝塞爾曲線講解

首先對于《賽貝爾曲線》不是很了解的童鞋,請自覺白度百科、google等等...

為了友善偷懶的童鞋,這裡給個《貝賽爾曲線》百科位址,以及一段話簡述《貝賽爾曲線》:

貝塞爾曲線又稱貝茲曲線或貝濟埃曲線,一般的矢量圖形軟體通過它來精确畫出曲線,貝茲曲線由線段與節點組成,節點是可拖動的支點,線段像可伸縮的皮筋;

上面這一段話其實就“線段像可伸縮的皮筋”這一句比較重要,也很容易了解;

        至于貝賽爾曲線的實作,在android中極其的簡單,因為它是android封裝的一個方法,這個能不簡單麼。。。。。。隻不過它隐藏的比較深,它隐藏于path類中,方法如下:

此方參數解釋:

第一個參數:操作點的x坐标

第二個參數:操作點的y坐标

第三個參數:結束點的x坐标

第四個參數:結束點的y坐标

從api中看出,賽貝爾曲線從api-1就開始支援了;

熟悉方法後,下面就來實作:

surfaceview架構不多講,看過我部落格的都應該知道的;

直接看mysurfaceview類,此類繼承surfaceview ,是遊戲的主視圖

這裡為了更清晰的講解:這裡部分代碼先不貼出來了,最後會整體貼出,當然源碼也是免費在最後提供~

首先是定義相關的成員變量:

// 貝賽爾曲線成員變量(起始點,控制(操作點),終止點,3點坐标)  

private int startx, starty, controlx, controly, endx, endy;  

// path  

private path path;  

// 為了不影響主畫筆,這裡繪制貝賽爾曲線單獨用一個新畫筆  

private paint paintq;  

// 随機庫(讓貝賽爾曲線更明顯)  

private random random;  

本類構造函數:

/** 

 * surfaceview初始化函數 

 */  

public mysurfaceview(context context) {  

    super(context);  

    ...  

        //貝賽爾曲線相關初始化  

        path = new path();  

        paintq = new paint();  

        paintq.setantialias(true);  

        paintq.setstyle(style.stroke);  

        paintq.setstrokewidth(5);  

        paintq.setcolor(color.white);  

        random = new random();  

}  

  接着我把繪制貝賽爾曲線封裝一個方法了,函數如下:

 * 繪制貝賽爾曲線 

 *  

 * @param canvas 主畫布 

public void drawqpath(canvas canvas) {  

    path.reset();// 重置path  

    // 貝賽爾曲線的起始點  

    path.moveto(startx, starty);  

    // 設定貝賽爾曲線的操作點以及終止點  

    path.quadto(controlx, controly, endx, endy);  

    // 繪制貝賽爾曲線(path)  

    canvas.drawpath(path, paintq);  

最後是使用者觸屏監聽函數以及邏輯函數:

 * 觸屏事件監聽 

@override  

public boolean ontouchevent(motionevent event) {  

    endx = (int) event.getx();  

    endy = (int) event.gety();  

    return true;  

 * 遊戲邏輯 

private void logic() {  

    if (endx != 0 && endy != 0) {  

        // 設定操作點為線段x/y的一半  

        controlx = random.nextint((endx - startx) / 2);  

        controly = random.nextint((endy - starty) / 2);  

    }  

整個代碼很easy~主要是貝賽爾函數的參數,尤其是操作點,操作點的各種不同可以實作不同的效果,這裡我簡單的統一的講操作點設定成使用者觸屏點的x,y的一半,呵呵偷懶了~嘻嘻~

我把貝賽爾的操作點寫在了邏輯logic()函數中,不斷的執行,并且每次利用nextint函數得到随機的操作點,主要為了讓其曲線不斷的變化進而形成一個震動的曲線運動軌迹;

ok,效果接圖如下:

android畫圖之貝塞爾曲線講解
android畫圖之貝塞爾曲線講解
android畫圖之貝塞爾曲線講解
android畫圖之貝塞爾曲線講解

     這裡可能由于圖檔是靜止的效果看起來不是很明顯,大家可以運作源碼來觀察 ,好了~本節就這樣吧;下面貼出整個mysurfaceview的源碼:(最後有本項目的源碼下載下傳位址)

package com.qpath;  

import java.util.random;  

import android.content.context;  

import android.graphics.canvas;  

import android.graphics.color;  

import android.graphics.paint;  

import android.graphics.paint.style;  

import android.graphics.path;  

import android.view.keyevent;  

import android.view.motionevent;  

import android.view.surfaceholder;  

import android.view.surfaceholder.callback;  

import android.view.surfaceview;  

 * 賽貝爾曲線 

 * @author himi 

public class mysurfaceview extends surfaceview implements callback, runnable {  

    private surfaceholder sfh;  

    private paint paint;  

    private thread th;  

    private boolean flag;  

    private canvas canvas;  

    public static int screenw, screenh;  

    // -----------以上是surfaceview遊戲架構  

    // 貝賽爾曲線成員變量(起始點,控制(操作點),終止點,3點坐标)  

    private int startx, starty, controlx, controly, endx, endy;  

    // path  

    private path path;  

    // 為了不影響主畫筆,這裡繪制貝賽爾曲線單獨用一個新畫筆  

    private paint paintq;  

    // 随機庫(讓貝賽爾曲線更明顯)  

    private random random;  

    /** 

     * surfaceview初始化函數 

     */  

    public mysurfaceview(context context) {  

        super(context);  

        sfh = this.getholder();  

        sfh.addcallback(this);  

        paint = new paint();  

        paint.setcolor(color.white);  

        paint.setantialias(true);  

        setfocusable(true);  

        // -----------以上是surfaceview遊戲架構  

     * surfaceview視圖建立,響應此函數 

    public void surfacecreated(surfaceholder holder) {  

        screenw = this.getwidth();  

        screenh = this.getheight();  

        flag = true;  

        // 執行個體線程  

        th = new thread(this);  

        // 啟動線程  

        th.start();  

     * 遊戲繪圖 

    public void mydraw() {  

        try {  

            canvas = sfh.lockcanvas();  

            if (canvas != null) {  

                canvas.drawcolor(color.black);  

                // -----------以上是surfaceview遊戲架構  

                drawqpath(canvas);  

            }  

        } catch (exception e) {  

            // todo: handle exception  

        } finally {  

            if (canvas != null)  

                sfh.unlockcanvasandpost(canvas);  

        }  

     * 繪制貝賽爾曲線 

     *  

     * @param canvas 主畫布 

    public void drawqpath(canvas canvas) {  

        path.reset();// 重置path  

        // 貝賽爾曲線的起始點  

        path.moveto(startx, starty);  

        // 設定貝賽爾曲線的操作點以及終止點  

        path.quadto(controlx, controly, endx, endy);  

        // 繪制貝賽爾曲線(path)  

        canvas.drawpath(path, paintq);  

     * 觸屏事件監聽 

    @override  

    public boolean ontouchevent(motionevent event) {  

        endx = (int) event.getx();  

        endy = (int) event.gety();  

        return true;  

     * 遊戲邏輯 

    private void logic() {  

        if (endx != 0 && endy != 0) {  

            // 設定操作點為線段x/y的一半  

            controlx = random.nextint((endx - startx) / 2);  

            controly = random.nextint((endy - starty) / 2);  

     * 按鍵事件監聽 

    public boolean onkeydown(int keycode, keyevent event) {  

        return super.onkeydown(keycode, event);  

    public void run() {  

        while (flag) {  

            long start = system.currenttimemillis();  

            mydraw();  

            logic();  

            long end = system.currenttimemillis();  

            try {  

                if (end - start < 50) {  

                    thread.sleep(50 - (end - start));  

                }  

            } catch (interruptedexception e) {  

                e.printstacktrace();  

     * surfaceview視圖狀态發生改變,響應此函數 

    public void surfacechanged(surfaceholder holder, int format, int width,  

            int height) {  

     * surfaceview視圖消亡時,響應此函數 

    public void surfacedestroyed(surfaceholder holder) {  

        flag = false;  

繼續閱讀