cocos2d-x v3.2 FlappyBird 各个类对象具体代码分析(3)

今天介绍两个比较简单的类

GameBegin.h

LandLayer.h

需要注意的有两点,一个是草地的滚动,还有一个是物理模型,都在LandLayer.h中实现,分析都在代码注释中。

先上GameBegin场景的效果图

这张图可以解析为

背景图的添加

游戏名字

小鸟以及小鸟飞行动画

按钮

草地(草地是会滚动的)

//GameBegin.h
#pragma once
#include "cocos2d.h"
class GameBegin:public cocos2d::Layer
{
public:
	GameBegin();
	~GameBegin();
	static cocos2d::Scene * createScene();
	bool init();
	void landMove(float);
	void startGame();
	CREATE_FUNC(GameBegin);
private:
	cocos2d::Sprite * land1;
	cocos2d::Sprite * land2;

};
//GameBegin.cpp
#include "GameBegin.h"
#include "define.h"
#include "GameLayer.h"
USING_NS_CC;
GameBegin::GameBegin()
{
}

GameBegin::~GameBegin()
{
}

cocos2d::Scene * GameBegin::createScene()
{
	auto scene=Scene::create();
	auto gameLayer=GameBegin::create();
	scene->addChild(gameLayer);
	return scene;
}

bool GameBegin::init()
{
	if (!Layer::init())
	{
		return false;
	}
	//获取 OpenGL 视图的初始化时的可见大小
	auto origin=Director::getInstance()->getVisibleOrigin();
	auto visibleSize=Director::getInstance()->getVisibleSize();

	//背景图片,根据时间加载晚上和白天的图片,这个功能是来自原作者
	time_t t=time(NULL);
	tm * lt=localtime(&t);
	int hour=lt->tm_hour;

	Sprite * bg;

	if (hour>=6&&hour<=17)
	{
		bg=Sprite::createWithSpriteFrameName("bg_day.png");
	}
	else
	{
		bg=Sprite::createWithSpriteFrameName("bg_night.png");
	}

	bg->setPosition(Point(origin.x+visibleSize.width/2,origin.y+visibleSize.height/2));
	this->addChild(bg);

	//游戏草坪的移动,这边的草地移动是没有物理模型的
	//所有的草地移动都在LandLayer类中介绍,这里不介绍了
	//这个类和LandLayer类是没有任何联系的,这里的草地移动和那边的草地移动也是不一样的
	//至于为什么不直接调用那个类,只能怪我刚开始写的时候没有策划好
	//那个LandLayer类是后面补上去给,别的类使用的,所以这边没有改
	land1=Sprite::createWithSpriteFrameName("land.png");
	land1->setAnchorPoint(Point::ANCHOR_BOTTOM_LEFT);
	land1->setPosition(Point::ZERO);
	land1->getTexture()->setAliasTexParameters();
	this->addChild(land1);

	land2=Sprite::createWithSpriteFrameName("land.png");
	land2->setAnchorPoint(Point::ANCHOR_BOTTOM_LEFT);
	land2->setPosition(Point(origin.x+land1->getPositionX()+land1->getContentSize().width-2,origin.y));
	land2->getTexture()->setAliasTexParameters();
	this->addChild(land2);

	this->schedule(schedule_selector(GameBegin::landMove),LAND_VELOCITY);

	//游戏名字
	auto title=Sprite::createWithSpriteFrameName("title.png");
	title->setPosition(Point(origin.x+visibleSize.width/2,origin.y+visibleSize.height*0.8));
	this->addChild(title);

	//小鸟
	auto bird=Sprite::createWithSpriteFrameName("bird0_0.png");
	bird->setPosition(Point(origin.x+visibleSize.width/2,origin.y+visibleSize.height*0.65));
<span style="white-space:pre">	</span>//小鸟的动画就是我们存在缓存中的,今天拿来用
	bird->runAction(RepeatForever::create(Animate::create(AnimationCache::getInstance()->getAnimation(BIRDANIMATION_0))));
	this->addChild(bird);

	//开始按钮
	auto start_sprite=Sprite::createWithSpriteFrameName("button_play.png");
	//按钮这里一共有2中状态,一是弹起状态
	//二是按下状态,下面的第一个参数和第二个参数就表示这两中状态
	//第三个参数就是按钮的回调函数
	auto start_button=MenuItemSprite::create(start_sprite,start_sprite,CC_CALLBACK_0(GameBegin::startGame,this));
	start_button->setPosition(Point(origin.x+visibleSize.width/2,origin.y+visibleSize.height*0.5));
	//这个是按钮菜单
	auto menu=Menu::create(start_button,NULL);
	menu->setAnchorPoint(Point::ANCHOR_BOTTOM_LEFT);
	menu->setPosition(Point::ZERO);
	this->addChild(menu);

	return true;
}

void GameBegin::landMove(float)
{
	land1->setPositionX(land1->getPositionX()-2);
	land2->setPositionX(land1->getPositionX()+land1->getContentSize().width-2);
	if (land2->getPositionX()==0)
	{
		land1->setPositionX(0);
	}
}
//按钮回调
void GameBegin::startGame()
{
	//场景切换
	Director::getInstance()->replaceScene(TransitionFade::create(CHANGESCENE_TIME,GameLayer::createScene()));
	log("replaceScene");
}
//LandLayer.h
#pragma once
#include "cocos2d.h"

class LandLayer:public cocos2d::Layer
{
public:
	LandLayer();
	~LandLayer();
	bool init();
	//草地移动
	void landMove(float);
	//草地停止移动
	void stopLand();
	CREATE_FUNC(LandLayer);
private:
	//草地精灵1
	cocos2d::Sprite * land1;
	//草地精灵2
	cocos2d::Sprite * land2;
};
//LandLayer.cpp
#include "LandLayer.h"
#include "define.h"
USING_NS_CC;
LandLayer::LandLayer()
{
}

LandLayer::~LandLayer()
{
}

bool LandLayer::init()
{
	if (!Layer::init())
	{
		return false;
	}
	auto origin=Director::getInstance()->getVisibleOrigin();
	auto visibleSize=Director::getInstance()->getVisibleSize();

	//游戏草坪的移动
	land1=Sprite::createWithSpriteFrameName("land.png");
	land1->setPosition(Point(origin.x+land1->getContentSize().width/2,origin.y+land1->getContentSize().height/2));
	//下面这个接口是防止两个精灵叠加时出现黑边
	land1->getTexture()->setAliasTexParameters();

	//下面是草地的物理模型
	//因为猪脚在飞的过程中会撞到两种东西
	//一是管子
	//二就是草地
	//所以我们要给草地添加物理模型,刚开始写的时候我是没有接触过物理模型
	//所以翻了很多资料,包括原作者的,百度的,研究了好长时间
	//现在也就懂了点皮毛

	//创造一个物理body,是不是应该叫刚体
	auto body1=PhysicsBody::create();
	//给body一个框架(外壳???),这里我们就是草地的对应的长方形
	auto shape_1=PhysicsShapeBox::create(land1->getContentSize());
	//把这个外壳给那个物理body
	body1->addShape(shape_1);
	//把刚体设为静态的
	//如果是动态刚体,它会受到力的作用
	//如果用另个刚体碰撞它的话,这个动态刚体就会运动或者旋转什么的
	//做为草地,它只能是一个安静的美男子......所以我们设为静态的
	body1->setDynamic(false);
	//这个是把重力取消掉,草地时没有重力的
	body1->setGravityEnable(false);
	//下面三个函数很复杂,我也是不怎么懂,网上的资料也不多
	//就是说要添加上去,貌似是碰撞检测要用到的
	body1->setCategoryBitmask(1);
	body1->setCollisionBitmask(-1);
	body1->setContactTestBitmask(-1);
	//下面的叫线性阻尼,我把它理解成摩擦力吧
	body1->setLinearDamping(0.7f);
	//把刚体付给草地
	land1->setPhysicsBody(body1);
	this->addChild(land1,2);

	land2=Sprite::createWithSpriteFrameName("land.png");
	//把草地2接在草地1的后面,这边减去2个像素,是为了防止移动过程出现黑边
	//因为,我们每移动一次的像素就是2
	land2->setPosition(Point(origin.x+land1->getPositionX()+land1->getContentSize().width-2,land1->getPositionY()));
	land2->getTexture()->setAliasTexParameters();
	auto body2=PhysicsBody::create();
	auto shape_2=PhysicsShapeBox::create(land1->getContentSize());
	body2->addShape(shape_2);
	body2->setDynamic(false);
	body2->setGravityEnable(false);
	body2->setCategoryBitmask(1);
	body2->setCollisionBitmask(-1);
	body2->setContactTestBitmask(-1);
	body2->setLinearDamping(0.7f);
	land2->setPhysicsBody(body2);
	this->addChild(land2,2);

	this->schedule(schedule_selector(LandLayer::landMove),LAND_VELOCITY);

	return true;
}
//草地滚动的实现
//如何实现草地滚动,在上面我们实例了两个草地精灵
//并且这两个草地的首尾接在了一起(具体看他们坐标X,草地2是接在草地1后面的)
//在定时器运行过程中,每执行一次函数,草地1和草地2的X坐标就减去2
//并且检测草地2的坐标有没有超过限定值(这里就是草地1起始的坐标值)
//如果超过,就重置两个草地的坐标
void LandLayer::landMove( float )
{
	land1->setPositionX(land1->getPositionX()-2);
	land2->setPositionX(land1->getPositionX()+land1->getContentSize().width-2);
	if (land2->getPositionX()==land2->getContentSize().width/2)
	{
		land1->setPositionX(land2->getContentSize().width/2);
	}
}
//草地停止移动,以后要用到
void LandLayer::stopLand()
{
	this->unschedule(schedule_selector(LandLayer::landMove));
}
时间: 2024-07-28 17:02:20

cocos2d-x v3.2 FlappyBird 各个类对象具体代码分析(3)的相关文章

cocos2d-x v3.2 FlappyBird 各个类对象具体代码分析(6)

今天我们要讲三个类,这三个类应该算比较简单的 HelpLayer类 NumberLayer类 GetLocalScore类 HelpLayer类,主要放了两个图形精灵上去,一个是游戏的名字,一个是提示游戏怎么玩的,就一张图: NumberLayer类,涉及到自定义字体的制作,我们提取出来的资源里,有很多数字图片: 现在我们要把它们做成这样子的: 这个跟游戏图片资源差不多,做成这样就可以直接拿来用,省了很多事情,那怎么做了,这里我们要用到一个叫软件,具体使用方法和过程,我这里就不介绍了,大家直接戳

cocos2d-x v3.2 FlappyBird 各个类对象具体代码分析(5)

今天介绍的是管道层 PipeLayer.h PipeLayer.cpp 管道层主要实现的是管道从右边往左边平移,结束后移除,而且管道还要长短高低不一样,然后就是如何判断小鸟通过一个管道.先说管道的平移,这个很简单,用一个函数把两跟管道封装好,让它moveby或者moveto好了,平移结束后,用一个回调函数移除自己就够了,当然封装好管道后,我们要把每一个管道放到一个数组里,方便管理嘛:然后就是管道高低不一样这里用一张图表示: 最后就是小鸟通过管道判断,这里我们是判断一个完整的管道是否通过屏幕中心线

cocos2d-x v3.2 FlappyBird 各个类对象具体代码分析(1)

好久没写博客了,今天早上起来不知怎么的就打开了csdn,工作简历也投了好几家,都石沉大海,在学校也闲着没事,就打算把以前写的Flappy Bird里面的一些代码分析发出来. Flappy Bird 网上也有很多的教程,我其中的有些代码也是参考网上的,不能算是完全原创吧,但是也有很大一部分代码都是按照我自己的想法,设计写出来的,接触cocos2d-x已经差不多有一年了,从以前的2x到现在的3x,改变了很多东西,作为一个新手我还有很多东西要去学习. 开始前有几点注意事项要说明: 1)我的Flappy

cocos2d-x v3.2 FlappyBird 各个类对象具体代码分析(7)

今天我们介绍最后两个类 GameOverLayer类 GameLayer类 GameLayer类是整个游戏中最重要的类,因为是整个游戏的中央系统,控制着各个类(层)之间的交互,这个类中实现了猪脚小鸟和它的敌人(管道和草地- . -)碰撞检测,说道物理引擎的碰撞检测,我也是第一次接触,也没多大难度,就直接调用了cocos2d-x的接口,这个类就是游戏的主场景,游戏就是在这里进行的. GameOverLayer类,游戏结束后一些分数的显示,还有就是奖牌的实现(楼主写的很简单......),这边比较有

cocos2d-x v3.2 FlappyBird 各个类对象具体代码分析(4)

今天要讲的使我们猪脚类 SpriteBird.h SpriteBird.cpp 猪脚类要注意的是三种状态的切换,和单点触控侦听的设置,还有就是小鸟在飞行的过程中,头部会上下的摆动,物理模型这里就不说了,小鸟头部的摆动是靠小鸟Y轴的速度来判定的,当小鸟向上飞的时候,速度是正的,所以头部摆动的旋转角度也是向上,当小鸟下落的时候,速度是负的,所以头部摆动的旋转角度是向下的. 小鸟的三种状态: 下面是代码 //SpriteBird.h #pragma once #include "cocos2d.h&q

面向对象--多继承&amp;派生类对象内存布局分析&amp;各基类指针所指向的位置分析

背景 原文链接:ordeder  http://blog.csdn.net/ordeder/article/details/25477363 关于非虚函数的成员函数的调用机制,可以参考: http://blog.csdn.net/yuanyirui/article/details/4594805 成员函数的调用涉及到面向对象语言的反射机制. 虚函数表机制可以查看下面这个blog: http://blog.csdn.net/haoel/article/details/1948051 总结为: 其一

黑马程序员_类对象创建代码的执行顺序测试总结

class StaticCode { // 类的非静态成员变量(实例变量)定义语句: // 作用:用来存储对象的特有数据的成员变量. // 运行:当类对象被创建时就执行,按照顺序自上而下执行,和构造代码块平级.(即当有多个构造函数 // 代码块和多个非静态成员变量时,JVM按照自上而下的顺序来执行所有语句,包括构造代码块里的代码 // 和非静态成员的声明.) // 存储位置:非静态变量位于堆内存中的对象实体中. int num = 3; // 构造代码块 { System.out.println

java 类对象使用

在学习反射机制时,总结一下获得类对象方式: 第一种方式:通过类本身来获得对象 Class<?> classname = this.getClass(); 或者this.class 第二种方式:通过子类的实例获取父类对象 ClassName cn = new ClassName(); UserClass = cn.getClass(); Class<?> SubUserClass = UserClass.getSuperclass(); 第三种方式:通过类名加.class获取对象 C

C++实现根据类名动态生成类对象

在开发后台服务的过程中,我们常常需要从数据库中取数据,并将数据缓存在本地中,另外,我们的服务还需要有更新数据的能力:包括定时的主动更新以及数据库数据更新时服务收到通知的被动更新. 之前在需要用到以上功能的时候,模仿着组内通用的数据Cache部分的代码来写,十分方便,基本上只需要自己写两个类:一个是取数据并缓存数据的类XXXData,一个是扇出数据的类XXXFetcher. 在需要使用数据的时候,通过: FetcherFactory::getFetcher<XXXFetcher>() 即可获取一