首先對於《賽貝爾曲線》不是很瞭解的童鞋,請自覺白度百科、google.
為了方便偷懶的童鞋,這裡給個《貝賽爾曲線》百科地址,以及一段話簡述《貝賽爾曲線》:
《貝賽爾曲線》白度百科快速地址:http://baike.baidu.com/view/4019466.htm
貝茲路徑又稱貝茲曲線或貝濟埃曲線,一般的向量圖形軟體通過它來精確畫出曲線,貝茲曲線由線段與節點群組成,節點是可拖動的支點,線段像可伸縮的皮筋。
上面這一段話其實就“線段像可伸縮的皮筋”這一句比較重要,也很容易理解。
至於貝賽爾曲線的實現,在Android中極其的簡單,因為它是Android封裝的一個方法,這個能不簡單麼。。。。。。只不過它隱藏的比較深,它隱藏於Path類中,方法如下:
android.graphics.Path.quadTo(float x1, float y1, float x2, float y2)
Since: API Level 1
此方參數解釋:
第一個參數:操作點的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,效果接圖如下:
這裡可能由於圖片是靜止的效果看起來不是很明顯,大家可以運行源碼來觀察 ,好了~本節就這樣吧;下面貼出整個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遊戲架構
// 貝賽爾曲線相關初始化
path = new Path();
paintQ = new Paint();
paintQ.setAntiAlias(true);
paintQ.setStyle(Style.STROKE);
paintQ.setStrokeWidth(5);
paintQ.setColor(Color.WHITE);
random = new Random();
}
/**
* SurfaceView視圖建立,響應此函數
*/
public void surfaceCreated(SurfaceHolder holder) {
screenW = this.getWidth();
screenH = this.getHeight();
flag = true;
// 執行個體線程
th = new Thread(this);
// 啟動線程
th.start();
// -----------以上是SurfaceView遊戲架構
}
/**
* 遊戲繪圖
*/
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);
}
}
/**
* 按鍵事件監聽
*/
@Override
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;
}
}