原文转载地址:http://blog.csdn.net/i646372587/article/details/46852835
作为一个标准的程序员应该有写博客的习惯,其实早就有这个念头了,只是不知道该写点什么,最近一直有朋友问我捕鱼达人鱼游动的时候鱼的方向转动该如何实现。
其实我没有写过捕鱼达人,一年前有个朋友公司做捕鱼达人类的游戏,然后问我如何写鱼游动这一块,那个时候我就思考过这个问题。
其实鱼游动的实现可以分为3部分:1,鱼本身的游动图片的切换,即一个帧动画。2,鱼的坐标的变化,也就是鱼沿着路径游动的位置变化。3,鱼的方向的变化,简单的说就是鱼头的转向。
对于第一部分,我相信大家都会了,就是一个帧动画的播放而已;然后第二部分,坐标的变化也不难,可以自己设计一个鱼游走的路径算法,如果不想写那么复杂的算法,也可以直接写好几套路径保存在文件中直接读取;到了第三部分,也就是我人生中第一篇博文的内容,就是鱼的转向。
其实我也不明白,很多人问我关于捕鱼达人中鱼的游动的重点都是鱼的转向该如何实现,其实并不难,我以前只是把思路告诉他们,没有真正敲出代码来,今天又有一位小伙伴问我,我答应他下班帮他写个小demo,也就是这篇博文了。
先说一下思路:鱼的游动中,第一部分播放鱼的帧动画其实跟后面两个部分没什么关系,除非你还需要根据鱼的转向播放不同的帧动画,如果有朋友在这部分处理遇到难题的话,可以给我留言。
第二部分和第三部分其实有着密切的关系,鱼游动的路径其实决定着鱼的转向,我们来从数学的角度来分析一下,首先鱼的路径是一条曲线,而鱼在每个位置的转向是如何的呢?其实就是该点在曲线上的切线方向!没错!就是这么简单!那如何得到切线的系数k呢?利用我们的数学知识很容易就可以解决,只要获取一个不久之前某个时刻的坐标P1跟当前坐标P2,即可大概算出当前所在点的切线的系数K。然后每隔一段很短的时间就获取一次K的值,然后修改鱼的转向即可。大家很容易就可以看出,要想提高K的精度,只有一个方法,那就是让P1更加接近P2,也就是选取相隔的时间越短(纯粹的数学知识)。
好了,废话那么多,也该上代码了,首先,我们先让鱼游动:
m_fish = Sprite::create("fish.png");
m_fish->setPosition(0, m_winSize.height);
this->addChild(m_fish);
//随便设置一个贝塞尔曲线
ccBezierConfig bezier;
bezier.controlPoint_1 = Vec2(m_winSize.width/4, 0);
bezier.controlPoint_2 = Vec2(m_winSize.width*3/4, m_winSize.height);
bezier.endPosition = Vec2(m_winSize.width, 0);
FiniteTimeAction* beizerAction=CCBezierTo::create(10,bezier);
m_fish->runAction(beizerAction);
#include "Pond.h"
const static float s_dt = 0.05;
Scene* Pond::createScene()
{
auto scene = Scene::create();
auto layer = Pond::create();
scene->addChild(layer);
return scene;
}
bool Pond::init()
{
if (!Layer::init())
{
return false;
}
m_winSize = Director::getInstance()->getWinSize();
m_fish = Sprite::create("fish.png");
m_fish->setPosition(0, m_winSize.height);
this->addChild(m_fish);
//随便设置一个贝塞尔曲线
ccBezierConfig bezier;
bezier.controlPoint_1 = Vec2(m_winSize.width/4, 0);
bezier.controlPoint_2 = Vec2(m_winSize.width*3/4, m_winSize.height);
bezier.endPosition = Vec2(m_winSize.width, 0);
FiniteTimeAction* beizerAction=CCBezierTo::create(10,bezier);
m_fish->runAction(beizerAction);
this->schedule(schedule_selector(Pond::refreshFish), s_dt);
return true;
}
void Pond::refreshFish( float dt )
{
static Vec2 lastPoint = Vec2(0, m_winSize.height);
Vec2 curPoint = m_fish->getPosition(); //获取鱼当前坐标
if (curPoint == lastPoint) //
{
this->unschedule(schedule_selector(Pond::refreshFish));
return ;
}
float K = atan( (curPoint.x - lastPoint.x) / (curPoint.y - lastPoint.y) );
m_fish->setRotation(K*180/3.14159265);
lastPoint = curPoint; //保存当前的坐标给下一轮刷新使用
}
网友评论