首先對于《賽貝爾曲線》不是很了解的童鞋,請自覺白度百科、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,效果接圖如下:
這裡可能由于圖檔是靜止的效果看起來不是很明顯,大家可以運作源碼來觀察 ,好了~本節就這樣吧;下面貼出整個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;
}