Android游戏开发25:Android中贝塞尔曲线的绘制方法

       贝塞尔曲线,很多人可能不太了解,什么叫做贝塞尔曲线呢?这里先做一下简单介绍:贝塞尔曲线也可以叫做贝济埃曲线或者贝兹曲线,它由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋。一般的矢量图形软件常利用贝塞尔曲线来精确画出曲线。

       上面的介绍中,“线段像可伸缩的皮筋”这句话非常关键,但也特别好理解。至于贝塞尔曲线的详细内容大家可以查阅相关资料。

       Android提供的贝塞尔曲线绘制接口

       在Android开发中,要实现贝塞尔曲线其实还是很简单的,因为Android已经给我们提供了相关接口,但此接口方法被藏的有点深,藏于Path类中。此方法如下:

       android.graphics.Path.quadTo(float x1, float y1, float x2, float y2)

       Since: API Level 1

       参数说明:

       x1:操作点的x坐标

       y1:操作点的y坐标

       x2:结束点的x坐标

       y2:结束点的y坐标

       从API中看出,贝塞尔曲线从API-1就开始支持了。

       Android贝塞尔曲线的绘制实例

       熟悉方法后,下面就来实现:

       SurfaceView框架不多讲,看过我博客的都应该知道的。

       直接看MySurfaceView类,此类继承SurfaceView,是游戏的主视图。

       这里为了更清晰的讲解:这里部分代码先不贴出来了,最后会整体贴出。

       首先是定义相关的成员变量:

Java代码
  1. // 贝赛尔曲线成员变量(起始点,控制(操作点),终止点,3点坐标)   
  2. private int startX, startY, controlX, controlY, endX, endY;   
  3. // Path   
  4. private Path path;   
  5. // 为了不影响主画笔,这里绘制贝赛尔曲线单独用一个新画笔   
  6. private Paint paintQ;   
  7. // 随机库(让贝赛尔曲线更明显)   
  8. private Random random;  

       本类构造函数:

Java代码
  1. /**  
  2.  * SurfaceView初始化函数  
  3.  */  
  4. public MySurfaceView(Context context) {   
  5.     super(context);   
  6.     …   
  7.         //贝赛尔曲线相关初始化   
  8.         path = new Path();   
  9.         paintQ = new Paint();   
  10.         paintQ.setAntiAlias(true);   
  11.         paintQ.setStyle(Style.STROKE);   
  12.         paintQ.setStrokeWidth(5);   
  13.         paintQ.setColor(Color.WHITE);   
  14.         random = new Random();   
  15.     …   
  16. }  

       接着我把贝赛尔曲线的绘制封装成一个方法了,函数如下:

Java代码
  1. /**  
  2.  * 绘制贝赛尔曲线  
  3.  *  
  4.  * @param canvas 主画布  
  5.  */  
  6. public void drawQpath(Canvas canvas) {   
  7.     path.reset();// 重置path   
  8.     // 贝赛尔曲线的起始点   
  9.     path.moveTo(startX, startY);   
  10.     // 设置贝赛尔曲线的操作点以及终止点   
  11.     path.quadTo(controlX, controlY, endX, endY);   
  12.     // 绘制贝赛尔曲线(Path)   
  13.     canvas.drawPath(path, paintQ);   
  14. }  

       最后是用户触屏监听函数以及逻辑函数:

Java代码
  1. /**  
  2.  * 触屏事件监听  
  3.  */  
  4. @Override  
  5. public boolean onTouchEvent(MotionEvent event) {   
  6.     endX = (int) event.getX();   
  7.     endY = (int) event.getY();   
  8.     return true;   
  9. }   
  10. /**  
  11.  * 游戏逻辑  
  12.  */  
  13. private void logic() {   
  14.     if (endX != 0 && endY != 0) {   
  15.         // 设置操作点为线段x/y的一半   
  16.         controlX = random.nextInt((endX – startX) / 2);   
  17.         controlY = random.nextInt((endY – startY) / 2);   
  18.     }   
  19. }  

       整个代码很easy,主要是贝赛尔函数的参数,尤其是操作点,操作点的各种不同可以实现不同的效果,这里我简单的统一的讲操作点设置成用户触屏点的x、y的一半,呵呵偷懒了~~

       我把贝赛尔的操作点写在了逻辑logic()函数中,不断的执行,并且每次利用nextInt函数得到随机的操作点,主要为了让其曲线不断的变化从而形成一个震动的曲线运动轨迹。

       运行效果截图如下:

Android游戏开发25:Android中贝塞尔曲线的绘制方法

       这里可能由于图片是静止的,所以效果看起来不是很明显,大家可以运行源码来观察。

       下面贴出整个MySurfaceView的源码:

Java代码
  1. package com.qpath;   
  2. import java.util.Random;   
  3. import android.content.Context;   
  4. import android.graphics.Canvas;   
  5. import android.graphics.Color;   
  6. import android.graphics.Paint;   
  7. import android.graphics.Paint.Style;   
  8. import android.graphics.Path;   
  9. import android.view.KeyEvent;   
  10. import android.view.MotionEvent;   
  11. import android.view.SurfaceHolder;   
  12. import android.view.SurfaceHolder.Callback;   
  13. import android.view.SurfaceView;   
  14. /**  
  15.  * 赛贝尔曲线  
  16.  * @author Himi  
  17.  *  
  18.  */  
  19. public class MySurfaceView extends SurfaceView implements Callback, Runnable {   
  20.     private SurfaceHolder sfh;   
  21.     private Paint paint;   
  22.     private Thread th;   
  23.     private boolean flag;   
  24.     private Canvas canvas;   
  25.     public static int screenW, screenH;   
  26.     // ———–以上是SurfaceView游戏框架   
  27.     // 贝赛尔曲线成员变量(起始点,控制(操作点),终止点,3点坐标)   
  28.     private int startX, startY, controlX, controlY, endX, endY;   
  29.     // Path   
  30.     private Path path;   
  31.     // 为了不影响主画笔,这里绘制贝赛尔曲线单独用一个新画笔   
  32.     private Paint paintQ;   
  33.     // 随机库(让贝赛尔曲线更明显)   
  34.     private Random random;   
  35.     /**  
  36.      * SurfaceView初始化函数  
  37.      */  
  38.     public MySurfaceView(Context context) {   
  39.         super(context);   
  40.         sfh = this.getHolder();   
  41.         sfh.addCallback(this);   
  42.         paint = new Paint();   
  43.         paint.setColor(Color.WHITE);   
  44.         paint.setAntiAlias(true);   
  45.         setFocusable(true);   
  46.         // ———–以上是SurfaceView游戏框架   
  47.         //贝赛尔曲线相关初始化   
  48.         path = new Path();   
  49.         paintQ = new Paint();   
  50.         paintQ.setAntiAlias(true);   
  51.         paintQ.setStyle(Style.STROKE);   
  52.         paintQ.setStrokeWidth(5);   
  53.         paintQ.setColor(Color.WHITE);   
  54.         random = new Random();   
  55.     }   
  56.     /**  
  57.      * SurfaceView视图创建,响应此函数  
  58.      */  
  59.     public void surfaceCreated(SurfaceHolder holder) {   
  60.         screenW = this.getWidth();   
  61.         screenH = this.getHeight();   
  62.         flag = true;   
  63.         // 实例线程   
  64.         th = new Thread(this);   
  65.         // 启动线程   
  66.         th.start();   
  67.         // ———–以上是SurfaceView游戏框架   
  68.     }   
  69.     /**  
  70.      * 游戏绘图  
  71.      */  
  72.     public void myDraw() {   
  73.         try {   
  74.             canvas = sfh.lockCanvas();   
  75.             if (canvas != null) {   
  76.                 canvas.drawColor(Color.BLACK);   
  77.                 // ———–以上是SurfaceView游戏框架   
  78.                 drawQpath(canvas);   
  79.             }   
  80.         } catch (Exception e) {   
  81.             // TODO: handle exception   
  82.         } finally {   
  83.             if (canvas != null)   
  84.                 sfh.unlockCanvasAndPost(canvas);   
  85.         }   
  86.     }   
  87.     /**  
  88.      * 绘制贝赛尔曲线  
  89.      *  
  90.      * @param canvas 主画布  
  91.      */  
  92.     public void drawQpath(Canvas canvas) {   
  93.         path.reset();// 重置path   
  94.         // 贝赛尔曲线的起始点   
  95.         path.moveTo(startX, startY);   
  96.         // 设置贝赛尔曲线的操作点以及终止点   
  97.         path.quadTo(controlX, controlY, endX, endY);   
  98.         // 绘制贝赛尔曲线(Path)   
  99.         canvas.drawPath(path, paintQ);   
  100.     }   
  101.     /**  
  102.      * 触屏事件监听  
  103.      */  
  104.     @Override  
  105.     public boolean onTouchEvent(MotionEvent event) {   
  106.         endX = (int) event.getX();   
  107.         endY = (int) event.getY();   
  108.         return true;   
  109.     }   
  110.     /**  
  111.      * 游戏逻辑  
  112.      */  
  113.     private void logic() {   
  114.         if (endX != 0 && endY != 0) {   
  115.             // 设置操作点为线段x/y的一半   
  116.             controlX = random.nextInt((endX – startX) / 2);   
  117.             controlY = random.nextInt((endY – startY) / 2);   
  118.         }   
  119.     }   
  120.     /**  
  121.      * 按键事件监听  
  122.      */  
  123.     @Override  
  124.     public boolean onKeyDown(int keyCode, KeyEvent event) {   
  125.         return super.onKeyDown(keyCode, event);   
  126.     }   
  127.     public void run() {   
  128.         while (flag) {   
  129.             long start = System.currentTimeMillis();   
  130.             myDraw();   
  131.             logic();   
  132.             long end = System.currentTimeMillis();   
  133.             try {   
  134.                 if (end – start < 50) {   
  135.                     Thread.sleep(50 – (end – start));   
  136.                 }   
  137.             } catch (InterruptedException e) {   
  138.                 e.printStackTrace();   
  139.             }   
  140.         }   
  141.     }   
  142.     /**  
  143.      * SurfaceView视图状态发生改变,响应此函数  
  144.      */  
  145.     public void surfaceChanged(SurfaceHolder holder, int format, int width,   
  146.             int height) {   
  147.     }   
  148.     /**  
  149.      * SurfaceView视图消亡时,响应此函数  
  150.      */  
  151.     public void surfaceDestroyed(SurfaceHolder holder) {   
  152.         flag = false;   
  153.     }   
  154. }  

 


android开发学习网 » Android游戏开发25:Android中贝塞尔曲线的绘制方法