天天看点

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;  

继续阅读