Cocos 您所在的位置:网站首页 缓动函数原理 Cocos

Cocos

2023-09-16 00:26| 来源: 网络整理| 查看: 265

一、序言

本篇只讲述贝塞尔曲线数学公式的运用原理,不进行公式的背景介绍和推导内容,如需请移步贝塞尔曲线公式推导原理。

在现实中,我们也只需要掌握其大致原理和开发中实际应用即可。

二、贝塞尔曲线原理

原文链接:https://www.jianshu.com/p/6075f9782743

A. 二阶贝塞尔曲线

要素:1 个起点,1 个终点,1 个控制点

知识点

三阶的话就是 2 个控制点,四阶的话就是 3 个,以此类推,N 阶的话就是 N - 1 个控制点。而起点和终点始终只有一个。

步骤如下:

1.绘制 1 个起点,1 个终点和 1 个控制点,分别为 S 、E、C。然后将 SC、CE 分别连线。如下图所示。

2.从点 S 向 C 出发找到一个 D 点,从 C 向 E 出发找到一个 F 点,使得SD / SC = CF / CE。然后连接 DF。如下图所示。

3.在 DF 之间找到点 M,使得SD / SC = CF / CE = DM / DF

总结下:

(1) 二阶贝塞尔中,起初是 3 个点,然后我们再找 2 个点,然后再找 1 个点。这个点就是我们要找到的点。(2) 我们需要由 S 向 C 出发,由 C 向 E 出现,找到所有的 D 和 F,再找到所有的 M。(3) 将所有的 M 连接起来就构造出了最后的所需要的贝塞尔曲线了。

借用一个图,来详细观察一下其构造的过程。

 

B. 三阶贝塞尔曲线

三阶和二阶是类似的: 1.连接 A,B 形成 AB 线段,连接 B,C 形成 BC 线段,连接 C,D 形成 CD 线段。

 

2.在AB线段取一个点 E,BC 线段取一个点 F,CD 线段取一个点 G,使其满足条件: AE/AB = BF/BE = CG/CD。连接 E,F 形成线段 EF,连接 F,G 形成线段 FG。

 

3.在EF线段取一个点 H,FG 线段取一个点 I,使其满足条件: AE/AB = BF/BE = CG/CD = EH/EF = FI/FG。连接 H,I 形成线段 HI。

4.在 HI 线段取一个点 J,使其满足条件: AE/AB = BF/BE = CG/CD = EH/EF = FI/FG = HJ/HI。

5.而满足这些条件的所有的J点所形成的轨迹就是三阶贝塞尔曲线,动态过程如下:

 

综合上式列表,可以总结出一般性规律:

三、cocos中的贝塞尔曲线

在Cocos2d-x中贝塞尔曲线运动分为CCBezierTo和CCBezierBy。

CCBezierTo:参数均为绝对坐标

CCBezierBy:参数均为相对于运动物体当前位置的相对坐标

这两个Action都需要传入一个参数ccBezierConfig,这是一个结构体,这个结构体有三个字段

1.CCPoint endPosition:结束点

2.CCPoint controlPoint_1:控制点1

3.CCPoint controlPoint_2:控制点2

c++示例:

//曲线配置 ccBezierConfig cfg; cfg.controlPoint_1 = ccp(100, 300); cfg.controlPoint_2 = ccp(200, 500); cfg.endPosition = ccp(500, 500); //使用CCEaseInOut让曲线运动有一个由慢到快的变化,显得更自然 node->runAction(CCSpawn::create(CCEaseInOut::create(CCBezierTo::create(t,cfg),0.5)));

lua中ccBezierConfig参数和顺序为:

1.CCPoint controlPoint_1:控制点1

2.CCPoint controlPoint_2:控制点2

3.CCPoint endPosition:结束点

lua示例:

self.sprite1 = cc.Sprite:create(icon[1]) self.rootNode:addChild(self.sprite1, 99) self.sprite1:setPosition(cc.p(300, 300)) local x, y = self.sprite1:getPosition() local offsetX = 200 local offsetY = 200 local bezierPoint1 ={ cc.p( x - offsetX, y ), cc.p( x - offsetX, y + offsetY ), cc.p( x, y + offsetY ) } local bezierPoint2 ={ cc.p( x + offsetX , y + offsetY ), cc.p( x + offsetX, y ), cc.p( x, y ) } local duration = 2 local bezierTo1 = cc.BezierTo:create( duration, bezierPoint1 ) local bezierTo2 = cc.BezierTo:create( duration, bezierPoint2 ) local action = cc.Sequence:create( bezierTo1, bezierTo2 ) self.sprite1:runAction(cc.RepeatForever:create(action))

两个控制点的会影响曲线的变化趋势。 Cocos2d-x中实现的是三阶贝塞尔曲线运动。 曲线的每个点的坐标是根据一个区间为0到1的变量t、开始点、结束点和两个控制点,通过方程计算出来的。

如上图所示:A、D分别为起点和终点,B、C分别为控制点1和控制点2。

四、c++源码

更新部分:

void BezierBy::update(float time) { if (_target) { float xa = 0; float xb = _config.controlPoint_1.x; float xc = _config.controlPoint_2.x; float xd = _config.endPosition.x; float ya = 0; float yb = _config.controlPoint_1.y; float yc = _config.controlPoint_2.y; float yd = _config.endPosition.y; float x = bezierat(xa, xb, xc, xd, time); float y = bezierat(ya, yb, yc, yd, time); #if CC_ENABLE_STACKABLE_ACTIONS Vec2 currentPos = _target->getPosition(); Vec2 diff = currentPos - _previousPosition; _startPosition = _startPosition + diff; Vec2 newPos = _startPosition + Vec2(x,y); _target->setPosition(newPos); _previousPosition = newPos; #else _target->setPosition( _startPosition + Vec2(x,y)); #endif // !CC_ENABLE_STACKABLE_ACTIONS } }

bezierat方法:

static inline float bezierat( float a, float b, float c, float d, float t ) { return (powf(1-t,3) * a + 3*t*(powf(1-t,2))*b + 3*powf(t,2)*(1-t)*c + powf(t,3)*d ); }

五、应用

抛物线(待优化)

local icon = { "ccbResources/HXH_league_icon/gonghuitouxiang1.png", } self.sprite1 = cc.Sprite:create(icon[1]) self.rootNode:addChild(self.sprite1, 99) self.sprite1:setPosition(cc.p(300, 300)) local x, y = self.sprite1:getPosition() -- 参数依次为 运动时间、运动物体、运动终点、最高点、两控制点与y轴夹角、物体自转 local function Parabola(t, startPoint, endPoint, height, angle, selfRotate) -- 角度转换为弧度 local startPoint = ccp(startPoint:getPosition()) local radian = angle * math.pi/180 local p1x = startPoint.x+(endPoint.x - startPoint.x)/4.0 local p1 = cc.p(p1x, height + startPoint.y + math.cos(radian)*p1x) local p2x = startPoint.x + (endPoint.x - startPoint.x)/2.0 local p2 = cc.p(p2x, height + startPoint.y + math.cos(radian)*p2x) local cfg = {p1, p2, endPoint} return cc.Spawn:create( cc.RotateBy:create(1,selfRotate), cc.EaseInOut:create(cc.BezierTo:create(t,cfg), 0.5) ) end self.sprite1:runAction(Parabola(1,self.sprite1,ccp(900,300),100,60,360))

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有