时隔几天终于该写分数榜了,最近实在是有事,导致博客现在才更新,还请各位见谅哈!废话不多说了,我们就来实现一下这个分数榜吧!这里我们需要用到CCTableView这个控件,前几篇博客我有写到这个控件,还不明白怎么用的请先看一下去。使用CCTableView这个控件的时候要明确cell的概念,什么是cell,在本例中cell就是每条分数记录,这条分数记录上有排名的显示,有得分的显示,有图片的显示,这些都是cell的内容,cell本身也有大小,也有点击以后的响应事件,不过在本例中这个响应事件是没有什么用的,我也就没有实现。好了,在上篇博客用户数据保存的基础上,我们开始本篇博客的分数榜实现,先看下效果吧!

小塔1024——实现分数榜

 

小塔1024——实现分数榜

 

底下的那张图片是XML文件中的内容,大家可能发现和上篇博客有些不同,这里把最大的分数排在了最上面,我在写分数榜的时候为了方便处理特意做了一下更改,其实很简单,就是在往XML文件中存放数据的时候把set集合中的内容倒着放进去就好了!改动以后的代码是这样的。

void PopScene::save()
{
	//将玩家的分数保存到set集合中,以便排序,默认是按升序进行排序的
	int score = MyUILayer::sharedMyUILayer()->getScore();
	score_set->insert(score);

	//将玩家的得分保存在文件中
	std::set<int>::const_iterator iterator = score_set->end();
	iterator--;
	for(int i=0;i<score_set->size();i++)
	{
		CCString * index = CCString::createWithFormat("%d",i);
		m_userDefault->setIntegerForKey(index->getCString(),*iterator);
		iterator--;
	}
	//如果添加的分数是原来set集合中存在的set集合中是添加不进去的,因为set中保存的是没有重复值的元素
	//所以这里刷新一下count的值,以免产生bug
	m_userDefault->setIntegerForKey("count",score_set->size());
	m_userDefault->flush();
}

 就改动了三句话哈。好了,现在看看这个分数榜场景怎么写吧!

#ifndef _SCORE_SCENE_H_
#define _SCORE_SCENE_H_
#include "cocos2d.h"
//包含扩展库的头文件和命名空间
#include "cocos-ext.h"
USING_NS_CC_EXT;

USING_NS_CC;

//必须继承以下的接口
class ScoreScene : public CCLayer,public CCTableViewDelegate,public CCTableViewDataSource
{
public:
	bool init();
	CREATE_FUNC(ScoreScene);
	static CCScene * scene();
	//继承上述的接口必须实现以下的虚函数
	void tableCellTouched(CCTableView *table,CCTableViewCell * cell);
	CCTableViewCell * tableCellAtIndex(CCTableView * table,unsigned int index);
	CCSize tableCellSizeForIndex(CCTableView * table,unsigned int index);
	unsigned int numberOfCellsInTableView(CCTableView * table);

	//因为CCTableView继承自CCScrollView,所以必须实现以下的接口
	void scrollViewDidScroll(CCScrollView * ){};
	void scrollViewDidZoom(CCScrollView *){};

	//关闭按钮的响应函数
	void close(CCObject * obj);
private:
	//定义设备的大小
	CCSize size;
};

#endif
#include "ScoreScene.h"

CCScene * ScoreScene::scene()
{
	CCScene * scene = CCScene::create();
	ScoreScene * layer = ScoreScene::create();
	scene->addChild(layer);

	return scene;
}

bool ScoreScene::init()
{
	if(!CCLayer::init())
	{
		return false;
	}

	//初始化设备的大小
	size = CCDirector::sharedDirector()->getWinSize();

	//加载一张背景图片
	CCSprite * sprite = CCSprite::create("rankbg.png");
	sprite->setPosition(ccp(size.width/2,size.height/2));
	this->addChild(sprite);

	//以下代码就是对CCTableView的实现

	//第一个参数是datasource的代理,第二个参数是tableview的大小
	CCTableView * table = CCTableView::create(this,CCSize(size.width,size.height*0.7));
	table->setPosition(CCPointZero);
	//设置滑动的放向是竖直的
	table->setDirection(kCCScrollViewDirectionVertical);
	//设置delegate的代理
	table->setDelegate(this);
	//index的顺序是从上到下依次的增大
	table->setVerticalFillOrder(kCCTableViewFillTopDown);
	//用当前的配置去刷新cell
	table->reloadData();

	this->addChild(table);

	//做一个关闭的菜单
	CCMenuItemImage * close = CCMenuItemImage::create("guanbi_1.png","guanbi_2.png",this,
		menu_selector(ScoreScene::close));
	CCMenu * menu = CCMenu::create(close,NULL);
	menu->setPosition(ccp(size.width*0.9,size.height*0.89));
	this->addChild(menu);

	return true;
}

void ScoreScene::close(CCObject * obj)
{
	CCDirector::sharedDirector()->popScene();
}

//这里是设置当我们点击每个cell的时候触发的函数,这里我把它置为空的实现,因为我们只是需要读取分数的记录
void ScoreScene::tableCellTouched(CCTableView *table,CCTableViewCell * cell)
{
}

//这个函数比较关键,是用来设置每个cell的内容的
CCTableViewCell * ScoreScene::tableCellAtIndex(CCTableView * table,unsigned int index)
{
	//设置每条记录前边的文本内容
	CCString * index_text = CCString::createWithFormat("%d",index+1);

	//dequeuecell这个函数是获得一个可用的cell,因为如果我们没增加一条分数记录就创建一个cell,可想而知如果
	//分数记录很多的话,cell不是超级的多了吗,这个时候内存占用就会很大,而这个函数的功能是把那些没有渲染的
	//cell拿过来,这样的话就减小了内存的消耗
	CCTableViewCell * cell = table->dequeueCell();
	if(cell == NULL)
	{
		//创建一个cell
		cell = new CCTableViewCell();
		cell->autorelease();

		//创建显示排名的文本信息
		CCLabelTTF * text = CCLabelTTF::create(index_text->getCString(),"",50);
		text->setTag(1024);
		text->setColor(ccc3(255,0,0));
		//文本信息在cell的中间
		text->setPosition(ccp(size.width*0.3,size.height*0.025));
		cell->addChild(text);

		//显示用户得分的文本信息
		CCString * index_score = CCString::createWithFormat("%d",index);
		//根据index值获得得分的文本,因为这个时候的score是int型,所以还需要转化一下类型,这里有点麻烦
		int i_score = CCUserDefault::sharedUserDefault()->getIntegerForKey(index_score->getCString());
		CCString * str = CCString::createWithFormat("%d",i_score);
		CCLabelTTF * score = CCLabelTTF::create(
			str->getCString(),"",50);
		score->setTag(2048);
		//设置坐标
		score->setPosition(ccp(size.width*0.7,size.height*0.025));
		score->setColor(ccc3(255,0,0));
		cell->addChild(score);

	}
	//这里获得的cell是原来的cell,所以原来cell的文本信息等还是原来的,所以要做一些改变
	else
	{
		//通过tag值获得文本,并且改变,虽然CCLabelTTF调用setString函数不好,但是这里为了省事就这么用吧
		CCLabelTTF * text = (CCLabelTTF *)cell->getChildByTag(1024);
		text->setString(index_text->getCString());

		//改变分数
		CCLabelTTF * score = (CCLabelTTF *)cell->getChildByTag(2048);
		CCString * index_score = CCString::createWithFormat("%d",index);
		//根据index值获得得分的文本,因为这个时候的score是int型,所以还需要转化一下类型,这里有点麻烦
		int i_score = CCUserDefault::sharedUserDefault()->getIntegerForKey(index_score->getCString());
		CCString * str = CCString::createWithFormat("%d",i_score);
		score->setString(str->getCString());

		if(cell->getChildByTag(100) != NULL)
		{
			CCSprite * sprite = (CCSprite *)cell->getChildByTag(100);
			sprite->removeFromParentAndCleanup(true);
		}
	}

	if(index == 0 || index==1 || index==2)
	{
		CCSprite * sprite;
		switch(index)
		{
			//代表的是冠军
		case 0:
			sprite = CCSprite::create("gold.png");
			break;
		case 1:
			sprite = CCSprite::create("silvere.png");
			break;
		case 2:
			sprite = CCSprite::create("tong.png");
			break;
		}
		sprite->setPosition(ccp(size.width*0.1,size.height*0.025));
		sprite->setTag(100);
		cell->addChild(sprite);
	}

	return cell;
}

//这个函数是用来设置每个cell的大小的
CCSize ScoreScene::tableCellSizeForIndex(CCTableView * table,unsigned int index)
{
	return CCSize(size.width,size.height*0.05);
}

//这个函数是用来设置cell的个数的
unsigned int ScoreScene::numberOfCellsInTableView(CCTableView * table)
{
	//个数是从XML文件中读取到的,有多少条记录,就设置多少个cell,如果刚开始没有count这个字段,就返回0
	int count = CCUserDefault::sharedUserDefault()->getIntegerForKey("count",0);

	return count;
}

代码唯一不好理解的地方就是设置cell内容的那里,那我就在这里说一下。这个cell的内容是根据index的值设置的,不同的index对应的cell是不同的,试想一下如果我们有100个cell如果就new出来100个cell对象,有1000个就new出来1000个对象,那我们的程序不是得崩溃吗?所以通过函数dequeueCell就是为了获得一个目前不显示的cell,既然获得了这个cell,那这个cell原来存在的东西还是在的吧,所以我们要不就更新一下内容,就像更新排名的文本和分数的文本,要不就将原来cell中的内容移除掉,就像移除那个显示金银牌的精灵一样。好了,这个CCTableView就算解决了,剩下的就是场景之间的调用了,我相信这个就不用我说了吧!