Cocos2d-x《雷电大战》(6) 智能敌机AI来袭--飞行路径算法设计与实现(上)

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

本文要实现飞机类游戏中的一连串飞机的跟随出和和并行出出。而网上找了一些Cocos2dx开发的飞行类游戏,都只找到一些简单的智能敌机。基本上没什么AI,这样游戏玩起来就太没意思了。然后又去找敌机飞行路径的相关资料,发现相关的也很少。想想还是自己来设计吧!

飞机类游戏设计中,智机的飞行路径设计和智能子弹的设计绝对一个飞行类游戏好坏是的核心。敌机智能也是分级别的。BOSS机就不说了,而飞行游戏由于其特殊性,还经常有那种一连串一起出现的敌机。这种又可分为以下两种:

跟随:相同的位置,相同的飞行路径,不同的启动时间,一般是按时间间隔。

并飞:不同的位置,相同的运行路径,相同的启动时间。

效果如下:

跟随,还未做碰撞判断

并飞,还未做碰撞判断

Cocos2d-x版本:3.4

工程环境:VS30213

一、跟随飞行

在跟随飞行中,简单一点的跟随飞行路线就是直线了,比如从左到右,从一个角到另一个角。这种做法都比较简单,没什么难度。实际游戏开发中,也很少见这种的跟随飞行,比较多的还是变化的曲线。而这种曲线一般都是贝赛尔曲线。飞机中不仅要飞行,还是进行实时的角度变化,这样才更加模拟真实的游戏场景!

1.1  贝赛尔曲线简介
       贝塞尔曲线是应用于二维图形应用程序的数学曲线。曲线的定义有四个点:起始点、终止点(也称锚点)以及两个相互分离的中间点。滑动两个中间点,贝塞尔曲线的形状会发生变化 .

       P0P1P2P3四个点在平面或在三维空间中定义了三次方贝塞尔曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1P2;这两个点只是在那里提供方向资讯。P0P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。


p0起点,p3是终点,p1,p2是控制点

1.2 游戏应用
       我们可能需要在游戏中模拟导弹或箭的移动轨迹,用才cocos2d-x下的bezier可以轻松的模拟出来
cocos2d-x下为我们提供了两个action BezierBy和BezierTo,使用也很简单,只需要填充结构体:

	//设置贝塞尔曲线参数
	ccBezierConfig tr0;
	tr0.endPosition = Vec2(0, 10);//终点
	tr0.controlPoint_1 = Vec2(250, 300);//控制点1
	tr0.controlPoint_2 = Vec2(180, 150);//控制点2
	ActionInterval* bezierForward = BezierTo::create(3.f, tr0);//创建运行的贝塞尔曲线

我们只需要提供两个控制点和一个终点位置就可以了,这里要注意的是
CCBezier这个action是以当前位置为起始点的,两个控制点和终点都是相对于起始点的偏移值
如:tr0.endPosition = ccp(280,240); 是相对于起始点的偏移

1.3 代码

这里只是要验证算法,所以代码还没有单独封装成类,而且也还没有将图像都打包成plist或用 SpriteBatchNode来优化内存。笔者打算把敌机飞行路径和敌机子弹设计完成之后,再统一来优化内存!

在GameMain.h中添加一个定时器:

	void enemyBuild1(float dt);//跟随

然后就是GameMain.cpp的init()函数打开定时,这里设置每隔0.5

	//每隔0.5S调用一次
	schedule(schedule_selector(GameMain::enemyBuild1), 0.5f);

最后就是实现了:

void GameMain::enemyBuild1(float dt){
	Size winSize = Director::getInstance()->getWinSize();
	auto spritePlane = Sprite::create("air3.png");
	spritePlane->setRotation(90);
	spritePlane->setPosition(Vec2(0,400));
	spritePlane->setScale(0.25);
	this->addChild(spritePlane);

	//设置贝塞尔曲线参数
	ccBezierConfig tr0;
	tr0.endPosition = Vec2(0, 10);//终点
	tr0.controlPoint_1 = Vec2(250, 300);//控制点1
	tr0.controlPoint_2 = Vec2(180, 150);//控制点2

	ActionInterval* bezierForward = BezierTo::create(3.f, tr0);//创建运行的贝塞尔曲线
	ActionInterval *forwardBy = RotateBy::create(3.f,180);     // 第二个参数:如果是正数则是顺时针,否则逆时针
	Spawn* spawn = Spawn::create(bezierForward, forwardBy,NULL);//创建合成动作

	//飞机执行完动作后进行函数回调,调用移除飞机函数
	auto actionDone = CallFuncN::create(
		CC_CALLBACK_1(GameMain::enemyRemove, this));

	//连续动作
	Sequence* sequence = Sequence::create(spawn,actionDone, NULL);
	spritePlane->runAction(sequence);

}

别看代码少,里面涉及到的内容不少呢!

其中删除飞机的函数:

void GameMain::enemyRemove(Node* pNode){
	if (NULL == pNode) {
		return;
	}
	Sprite* plane = (Sprite*)pNode;
	this->removeChild(plane,true);
}

要记得先在GameMain.h中定义

	void enemyRemove(Node* pNode);

最后就是运行了,效果如下:

二、并飞飞行

并飞就比简单了,因为是相同的路径方法。而且一般都不考虑到角度旋转的问题。游戏中最多出现的是左右并飞或者上下并飞。无非就是设置几架飞机在一排线上,然后设置飞行路径。最后执行就是了,下面直接来看看代码吧,注释很详细,有需要的直接拿过去,很方便自己扩展,把图像名改下就好。要记得,这里还未做内存优化,如果想做的话,有两种方法。一种是图像做成plist,另一种是用 SpriteBatchNode来做。在这里在,我推荐用前者,但是最好等游戏全开发完了再来弄吧。

首先GameMain.h添加定时器:

	void enemyBuild2(float dt);//并飞

打开定时器:

    //每隔3S调用一次
    schedule(schedule_selector(GameMain::enemyBuild2), 3.0f);

最后就是实现了:

void GameMain::enemyBuild2(float dt){
	Size winSize = Director::getInstance()->getWinSize();
	Point origin = Director::getInstance()->getVisibleOrigin();

	//生成精灵
	auto spritePlane1 = Sprite::create("air4.png");
	auto spritePlane2 = Sprite::create("air4.png");
	auto spritePlane3 = Sprite::create("air4.png");
	//得到精灵宽和高
	float height = spritePlane1->getContentSize().height;
	float width = spritePlane1->getContentSize().width;

	//旋转的角度
	spritePlane1->setRotation(180);
	spritePlane2->setRotation(180);
	spritePlane3->setRotation(180);

	//设置缩放
	//spritePlane1->setScale(0.3);
	//spritePlane2->setScale(0.3);
	//spritePlane3->setScale(0.3);

	//设置位置
	spritePlane1->setPosition(Vec2(width, winSize.height + height));
	spritePlane2->setPosition(Vec2(winSize.width / 2, winSize.height - height));
	spritePlane3->setPosition(Vec2(winSize.width - width, winSize.height + height));

	//层中加入精灵
	this->addChild(spritePlane1);
	this->addChild(spritePlane2);
	this->addChild(spritePlane3);

	//计算飞行时间
	float flyVelocity =200;//运行速度,可以自己控制,每秒所走的像素
	float flyLen = winSize.height;
	float realFlyDuration = flyLen / flyVelocity;//实际飞行的时间

	//子弹运行的距离和时间,从飞机处开始运行到屏幕底部
	auto actionMove1 = MoveBy::create(realFlyDuration, Point(0, -winSize.height - height));
	auto actionMove2 = MoveBy::create(realFlyDuration, Point(0, -winSize.height -height));
	auto actionMove3 = MoveBy::create(realFlyDuration, Point(0, -winSize.height - height));

	//子弹执行完动作后进行函数回调,调用移除子弹函数
	auto actionDone = CallFuncN::create(
		CC_CALLBACK_1(GameMain::enemyRemove, this));

	//连续动作
	Sequence* sequence1 = Sequence::create(actionMove1, actionDone, NULL);
	Sequence* sequence2 = Sequence::create(actionMove2, actionDone, NULL);
	Sequence* sequence3 = Sequence::create(actionMove3, actionDone, NULL);

	//飞机开始跑动
	spritePlane1->runAction(sequence1);
	spritePlane2->runAction(sequence2);
	spritePlane3->runAction(sequence3);

}

来看看效果:

都还没做碰撞检测,可以看到。敌机按照我们的要求生成并运动了。

这就是群飞飞机群的两种方式,也可以将并飞和跟随相结合。就可以生成很多种不同的飞机路径。这在后头我将会再来讲解,今天就先到这里了。敌机类最好是自己封装,这里还没有实现。有需要的可以自己把函数改改就OK了!最后,再放张图!

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

时间: 2024-08-11 01:41:47

Cocos2d-x《雷电大战》(6) 智能敌机AI来袭--飞行路径算法设计与实现(上)的相关文章

Cocos2d-x游戏《雷电大战》开源啦!要源码要资源快快来~~

写在前面的话:这是笔者开发的第二个小游戏<雷电大战>,之前就过这个游戏和<赵云要格斗>一样,最终将会开源.由于自己的一些个人原因.这个游戏还没有完成,但是许多网友都过来寻求代码或资源,本着开源的精神,笔者今天将它们共享给出大家. 注:目前游戏还没有完成,代码全是笔者原创,资源有一部分原创,有一部分网上搜集. 若是觉得本项目对你有用,那么请给辛苦的笔者的GitHub右上角Star一颗星星!不胜感激---- 下载地址 https://github.com/appleappleapple

Cocos2d-x《雷电大战》(3)-子弹无限发射

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文要实现雷电游戏中,游戏一開始,英雄飞机就无限发射子弹的功能. 这里的思想是单独给子弹弄一个层.在这个层不设置一个定时器,每隔一个时间,依据当前英雄飞机传入的位置,生成子弹,并设置子弹的移动事件,和移动后的事件(就是把子弹删除掉,节省内存). 终于效果: Cocos2d-x版本号:3.4 project环境:VS30213 一.英雄子弹层 1.HeroBulletLayer.h /** *

Cocos2d-x《雷电大战》(4)-策略模式实现不同子弹切换!!

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文从设计模式中的策略模式入手,主讲了飞机大战中英雄飞机切换不同的子弹.这里分为三种子弹.第一种:每次发一个子弹,垂直发射;第二种:每次发两个子弹,两个都是垂直发射:第三种;每次发三个子弹,两边的子弹有一定的角度,而中间的子弹垂直发射;设计模式是游戏开发经常用到的思想,建议有兴趣的同学可以好好研究下!好了,下面开始吧. 效果如下: Cocos2d-x版本:3.4 工程环境:VS30213 一

Cocos2d-x《雷电大战》(5)-单例模式英雄飞机闪亮登场!

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文将实现用单例模式实现一个英雄飞机类的设计,单例模式是游戏开发中最常用到的一种设计模式,原理也比较简单,仔细研究下就可以掌握好. 来看看效果: Cocos2d-x版本:3.4 工程环境:VS30213 一.单例模式解析 单例模式也称为单件模式.单子模式,可能是使用最广泛的设计模式.其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享.有很多地方需要这样的功

智能狗ai智能伪原创伪原创”产业链洗选稿成300,000

"智能狗ai智能伪原创伪原创"产业链洗选稿成300,000 沉毅(化名)是一位业余自传媒体作家4月5日,他在微信公众号上发表了自己的评论.该文章首先在微信上发布,然后分发到其他平台.在其中一个平台中,文章显示"内容敏感",审查失败.使用人工智能伪原始技术的智能狗ai智能伪原创伪原始软件,基于NLP算法的手稿很难区分谁是原始的,甚至比原来的更好. 但是第二天在平台上,他发现他的文章完全是从媒体上复制过来的,标题只改了两个字.报告投诉后,平台删除了同时复制的文章. 两周

C#PDA智能程序图片动态变化进度条设计及实现

前言:SmartProject 项目是C#桌面程序的精简版,很多属性和事件可能都没有设置进SDK中.在最近的PDA程序中,我没用使用进度条.为了防止用户乱点,最开始想使用windows提供的进度条,但是觉得又不适合,所以就试图用图片切换的方式来实现.  原理:开启线程切换图片实现显示(子线程不影响主线程而继续往下执行). 1.进度界面设计效果 2.界面切换效果 点击质检按钮后跳转(during the new thread running the UI will be changed): 等待业

算法 - 智能拼图AI

继上一篇博文,已经半年没有写过博文了 因为不想打字和语文能力比较差 所以就懒得写了 不过也不是坏事 上一篇就是一个拼图的游戏   这篇写的是这个游戏的AI [是AI不是外挂 ] 这个是智能拼图游戏http://www.cnblogs.com/magicianlyx/p/5205799.html 网上的 贪食蛇AI 俄罗斯方块AI 见得比较多并且他们的算法思路都是比较普遍我就不重复造轮子了,自己也多拼图这个游戏比较有兴趣 先来几张效果的样张 6*6的gif 556步 5秒生成 14*14的   因

Cocos2d-x 《雷电大战》-精灵随手指移动,你点哪我走哪!

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文要实现飞机游戏中,人的手指按着飞机,就能拖着飞机走动,这里实现了当你手指按在手机的图片上,手指一直按着屏幕,飞机就会跟着你走.同时,还加入了边界判断条件,让飞机在你的视野内移动,实现的效果完全和我们手机上的飞机游戏一样. 效果: Cocos2d-x版本:3.4 工程环境:VS30213 一.代码编写 1.头文件GameMain.h /** *@作者 林炳文(邮箱:[email prote

Cocos2d-x 《雷电大战》-双层地图无限滚动

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文要实现飞机射击游戏中的地图无限滚动的功能,这里分为两个层,一个层无限向下滚动,一个层无限向上滚动,这样子结合起来效果就非常有层次感,也非常逼真,这里我把地图层都写成一个类,自己把地图改下,就可以成为你自己的了!下面,我们开始吧 先来看看效果: Cocos2d-x版本:3.4 工程环境:VS30213 一.实现思路 其实就是两张图片,然后同时一起向下(向上)滚动,当一张图片完全出视野后,就