博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Android游戏开发二十五】在Android上的使用《贝赛尔曲线》!
阅读量:3519 次
发布时间:2019-05-20

本文共 5824 字,大约阅读时间需要 19 分钟。

首先对于《赛贝尔曲线》不是很了解的童鞋,请自觉白度百科、google等等…

为了方便偷懒的童鞋,这里给个《贝赛尔曲线》百科地址,以及一段话简述《贝赛尔曲线》:

《贝赛尔曲线》白度百科快速地址:

贝塞尔曲线又称贝兹曲线或贝济埃曲线,一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋;

上面这一段话其实就“线段像可伸缩的皮筋”这一句比较重要,也很容易理解;

至于贝赛尔曲线的实现,在Android中极其的简单,因为它是Android封装的一个方法,这个能不简单么。。。。。。只不过它隐藏的比较深,它隐藏于Path类中,方法如下:

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

Since: 

此方参数解释:

第一个参数:操作点的x坐标

第二个参数:操作点的y坐标

第三个参数:结束点的x坐标

第四个参数:结束点的y坐标

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

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

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

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

这里为了更清晰的讲解:这里部分代码先不贴出来了,最后会整体贴出,当然源码也是免费在最后提供~

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

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

本类构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 
* 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();
    
...
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 
* 绘制贝赛尔曲线
 
*
 
* @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);
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 
* 触屏事件监听
 
*/
@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的源码:(最后有本项目的源码下载地址)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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
;
    
}
}

本章源码下载: ”贝赛尔曲线.zip”           下载地址:  

转载地址:http://vvpqj.baihongyu.com/

你可能感兴趣的文章
设计模式七大原则
查看>>
手写 | spring事务
查看>>
AndroidStudio Gradle手动下载
查看>>
SpringBoot入门(二)场景启动器
查看>>
SpringBoot入门--自动配置
查看>>
springboot读取配置文件 例:读取配置文件的优先顺序;在主配置文件中激活其他配置文件;加载非主配置文件
查看>>
自动配置原理
查看>>
TCP协议
查看>>
关于Linux系统使用遇到的问题-1:vi 打开只读(readonly)文件如何退出保存?
查看>>
redis 持久化详解,RDB和AOF是什么?他们优缺点是什么?运行流程是什么?
查看>>
spring注解版(一)
查看>>
SpringBoot中访问控制层(controller)得不到Json数据
查看>>
react项目报出警告Warning: Cannot update during an existing state transition (such as within `render`).
查看>>
BFC(Block Formatting Context)
查看>>
什么是作用域,什么是闭包,什么是作用域链
查看>>
惰性求值,面向对象
查看>>
lodash源码分析之baseSlice()函数
查看>>
数据结构之列表
查看>>
发布/订阅模式 vs 观察者模式
查看>>
es5中的arguments对象
查看>>