游戏设计中常常使用排行榜,根据排行发送排名奖励。

  1. 排行容器的组成
    记录排行的容器是一个由内部由vector和map组成的模板类
    1.1.容器为什么这么设计
    1.1.1vector部分的结构
    其中vector里的元素使用的是pair, pair的first部分保存的是 uid(玩家ID),second部分保存的我们想要保存的任何信息(当然是一个类,或者结构体),然而vector的排列顺序是按照名词排列的
    1.1.2. map的结构
    map的first的部分也是uid,second部分是玩家的名词
    1.1.3为什么使用vector和map的组合设计这么一个容器?
    我们知道vector的优点是取值方便,map的优点是查找快速。
    那么容器的有点有如下:

    1.1.3.1. 获得名次快速
    通过map查找uid,快速拿到名词

    1.1.3.2通过名词,快速获得我们保存的信息
    根据map查找的名次,我们作为vector的下标获取该玩家的信息。

  2. 下面提供排行模板类的代码实现

#ifndef _RANKLIST_H_
#define _RANKLIST_H_#include <vector>
#include <algorithm>
using namespace std;
#include <boost/typeof/typeof.hpp>
#include <boost/unordered_map.hpp>
using boost::unordered_map;
#include "../common/const_def.h"template<typename RankKey, int Length = 1000, class Pr = greater<RankKey> >
class RankList
{
public:RankList(){}~RankList(){ clear();}void init(vector<pair<int64, RankKey> >& rank);bool modify(int64 uid, RankKey key);void remove(int64 uid, RankKey key);void erase(int64 uid);void clear();unsigned size() const;unsigned rank(int64 uid) const;//根据uid得到名次int64 getuid(unsigned rank) const;//根据名次得到uidconst RankKey* const getkey(int64 uid) const;//根据uid得到key信息vector<int64> partialUserList(unsigned start, unsigned length) const;//取出排名在[start + 1, start + length -1]范围内的uid;const vector<pair<int64, RankKey> > & get_vec_rank(){return rank_;}//取出全部Key信息//=RankList& operator=(const RankList& myRanklist){clear();this->index_ = myRanklist.index_;this->rank_ = myRanklist.rank_;return *this;}//[]const pair<int64, RankKey>* operator[](int index){if(index < 0 || index >= int(rank_.size())){return NULL;}return &this->rank_[index];}//构造RankList(const RankList& myRanklist){clear();this->index_ = myRanklist.index_;this->rank_ = myRanklist.rank_;}const RankKey* getkey(int64 uid);
protected:void sortall();void sort(unsigned index);void trim();void swap(unsigned indexA, unsigned indexB);private:vector<pair<int64, RankKey> >  rank_;   //uid, uid对应的数据unordered_map<int64, unsigned> index_; //uid, uid对应的排名
};template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::clear()
{vector<pair<int64, RankKey> > temp;init(temp);
}template<typename RankKey, class Pr>
static bool RankComp(const pair<int64, RankKey>& l, const pair<int64, RankKey>& r)
{                                                                                        static Pr pr;return pr(l.second, r.second);
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::init(vector<pair<int64, RankKey> >& rank)
{rank_.swap(rank);sortall();trim();index_.clear();for (size_t i = 0; i < rank_.size(); i++)index_[rank_[i].first] = i;
}
template<typename RankKey, int Length, class Pr>
const RankKey* RankList<RankKey, Length, Pr>::getkey(int64 uid)
{BOOST_AUTO(it, index_.find(uid));if (it != index_.end())return &rank_[it->second].second;return NULL;
}template<typename RankKey, int Length, class Pr>
bool RankList<RankKey, Length, Pr>::modify(int64 uid, RankKey key)
{static Pr pr;BOOST_AUTO(it, index_.find(uid));size_t sz = rank_.size();// not in list now and will not be in listif (it == index_.end() && sz >= Length && !pr(key, rank_[sz-1].second))return false;if (it != index_.end()){rank_[it->second].second = key;}else{index_[uid] = rank_.size();rank_.push_back(make_pair(uid, key));}                                        sort(index_[uid]);trim();return true;
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::erase(int64 uid)
{BOOST_AUTO(it, index_.find(uid));if (it == index_.end() || rank_.size() <= 0)return;unsigned indexCurrent = it->second, indexLast = rank_.size()-1;if (indexCurrent != indexLast)swap(indexCurrent, indexLast);rank_.pop_back();index_.erase(uid);if (indexCurrent != indexLast)sort(indexCurrent);
}template<typename RankKey, int Length, class Pr>
unsigned RankList<RankKey, Length, Pr>::rank(int64 uid) const
{BOOST_AUTO(it, index_.find(uid));if (it == index_.end())return 0;return it->second + 1;
}template<typename RankKey, int Length, class Pr>
vector<int64> RankList<RankKey, Length, Pr>::partialUserList(unsigned start, unsigned length) const
{vector<int64> v;if(start < 0)return v;size_t sz = rank_.size();for (size_t i = start; i < sz && i < start + length; i++)v.push_back(rank_[i].first);return v;
}template<typename RankKey, int Length, class Pr>
unsigned RankList<RankKey, Length, Pr>::size() const
{return rank_.size();
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::sortall()
{std::sort(rank_.begin(), rank_.end(), RankComp<RankKey, Pr>);
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::sort(unsigned index)
{static Pr pr;while (index > 0 && pr(rank_[index].second, rank_[index-1].second)){swap(index-1, index);index--;}size_t sz = rank_.size();while ( sz > 0 && index < sz-1 && pr(rank_[index+1].second, rank_[index].second)){swap(index, index+1);index++;}
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::swap(unsigned indexA, unsigned indexB)
{if (indexA >= rank_.size() || indexB >= rank_.size())return;std::swap(rank_[indexA], rank_[indexB]);index_[rank_[indexA].first] = indexA;index_[rank_[indexB].first] = indexB;
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::trim()
{size_t sz = rank_.size();while (sz > Length){index_.erase(rank_[sz-1].first);rank_.pop_back();sz--;}
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::remove(int64 uid, RankKey key)
{static Pr pr;BOOST_AUTO(it, index_.find(uid));size_t sz = rank_.size();// not in list now and will not be in listif (it == index_.end() && sz >= Length && !pr(key, rank_[sz-1].second))return;int nIndex = index_[uid];if (it != index_.end()){index_.erase(uid);for(size_t i = 0; i < rank_.size(); i++){if(rank_[i].first == uid)rank_.erase(rank_.begin()+i);}}sort(nIndex);trim();
}template<typename RankKey, int Length, class Pr>
int64 RankList<RankKey, Length, Pr>::getuid(unsigned rank) const
{if (index_.size() < rank)return 0;BOOST_AUTO(iter, index_.begin());for (; iter!=index_.end(); ++iter){if ((iter->second + 1)== rank){return iter->first;break;}}return 0;
}
template<typename RankKey, int Length, class Pr>
const RankKey* const RankList<RankKey, Length, Pr>::getkey(int64 uid) const
{BOOST_AUTO(it, index_.find(uid));if (it == index_.end())return NULL;return &(rank_[it->second].second);
}#endif

4.进一步说明排行榜的参数,以及排序问题
排行榜模板类,需要三个参数,template

template<typename RankKey, int Length, class Pr>
bool RankList<RankKey, Length, Pr>::modify(int64 uid, RankKey key)
{static Pr pr;BOOST_AUTO(it, index_.find(uid));size_t sz = rank_.size();// not in list now and will not be in list//在容器已经满的情况下,并且是新数据,并且新数据比最后一个元素还要小的时候,就不会计入排行榜if (it == index_.end() && sz >= Length && !pr(key, rank_[sz-1].second))return false;if (it != index_.end()){rank_[it->second].second = key;}else{index_[uid] = rank_.size();rank_.push_back(make_pair(uid, key));}                                        //其中sort的个根据我们写好的排序规则进行排序sort(index_[uid]);//如果超出排行的限制,那么让排行榜的大小变为我们传入参数legth的大小trim();return true;
}

5.排行榜的应用

//定义我们保存数据内容,以及排序规则
struct RankKey
{RankKey(int score, int64 time, int64 uid) : m_score(score),m_time(time),m_uid(uid) {}bool operator >(const RankKey &that) const { if (m_score ==  that.m_score){if (m_time == that.m_time)return m_uid < that.m_uid;elsereturn m_time < that.m_time;}elsereturn m_score > that.m_score;}int getScore(){ return m_score;}int64 getUid(){ return m_uid;}int64 getTime() {return m_time;}
}RankList<RankKey, 100> m_levelRankList;//等级排行榜//当有数据更新或者有新数据时调用如下
for(int i = 0; i < 10; i++)
{int64 uid = i;time_t newtime= time(NULL) + i * 100;int lvl = i * 10;m_levelRankList.modify(uid, RankKey(lvl, newtime , uid));
}
//那么我们就进行了排行,假设我们想要根据排名发送奖励
//那么我们可以调用vector<int64> partialUserList(unsigned start, unsigned length) const;//取出排名在[start + 1, start + length -1]范围内的uid;获取排名的uid,然后调用发送邮件的函数接口进行,发送奖励//题外话,发送玩奖励一般调用clear,将排行榜清空,防止逻辑错误重复发奖

5.题外话:

 其中排行榜的一般和另外一个map结合使用map<int64, int > m_mapAlldata//玩家uid,玩家的得分(这里保存所有玩家的数据,不管是否进入排行榜)
RankList<RankKey, 100> m_scoreRankList;//分数排行榜(这里仅仅保存进入排行榜的数据)一般情况下是先更新m_mapAlldata,然后更新排行榜(调用modify)
这样就实现了游戏中的排行榜

6 缺点
sort的时候,其实是对vector的操作,排序时挪动元素比较耗时

游戏中排行榜代码实现相关推荐

  1. 用 Redis 搞定游戏中的实时排行榜,附源码!

    原文:segmentfault.com/a/1190000019139010 1. 前言 前段时间刚为项目(手游)实现了一个实时排行榜功能, 主要特性: 实时全服排名 可查询单个玩家排名 支持双维排序 ...

  2. threejs 微信小游戏中的离屏渲染做UI和排行榜

    微信小游戏对threejs真的是一次桎酷啊...呵呵. 规定不能用html锁死了我们之前两个html标签的可能了... 不过微信还是允许了大家的离屏渲染,要不是我们在跳一跳之类的游戏中也看不到排行榜和 ...

  3. [原创]游戏中的实时排行榜实现

    1. 前言 2. 排行榜分类 3. 思路 4. 实现 复合排序 4.1 等级排行榜 4.2 通天塔排行榜 4.3 坦克排行榜 5. 排名数据的动态更新 6. 取排行榜 7. Show The Code ...

  4. 有关计算机代码的游戏,七灯游戏是一款经典的益智类游戏。游戏中,有七盏灯排成一圈,如图a所示,初始时灯的开关状态随机生成,操作其中某一盏灯,则可以切换该灯的“开/关”状态,同时,这盏灯-组卷网...

    七灯游戏是一款经典的益智类游戏.游戏中,有七盏灯排成一圈,如图a所示,初始时灯的开关状态随机生成,操作其中某一盏灯,则可以切换该灯的"开/关"状态,同时,这盏灯对面的两盏灯也会切换 ...

  5. 一行Java代码实现游戏中交换装备

    摘要:JDK 1.5 开始 JUC 包下提供的 Exchanger 类可用于两个线程之间交换信息. 本文分享自华为云社区<一行Java代码实现两玩家交换装备[并发编程]>,作者:陈皮的Ja ...

  6. mc是用java写的吗_都说MC的代码特别差劲,你觉得它在所有游戏中,能排第几?...

    原标题:都说MC的代码特别差劲,你觉得它在所有游戏中,能排第几? 虽然说我的世界这款游戏非常的好玩,销量世界第一,无论国内国外都非常的火热,但是大家都知道,一款游戏他的最原本的面貌是由一个又一个的代码 ...

  7. lua游戏代码_在游戏中如何使用LUA脚本语言

    当你希望在你的游戏开始的时候读取一些信息,以配置你的游戏,这些信息通常都是放到一个文本文件中,在你的游戏启动的时候,你需要打开这个文件,然后解析字符串,找到所需要的信息. 或许你认为这样就足够了,为什 ...

  8. unity中通过代码控制游戏中画质

    最近在开发项目的时候突然想到可以添加一个调整画质的按钮或者DropDown或者Slider的UI来控制游戏中的画质 因为我之前写过一篇关于DropDown的使用方法的博客 DropDown的使用方法地 ...

  9. java2d游戏代码_Java 2d游戏中的“JUMP”

    我有这个代码,我想在java 2d游戏中启动一个跳转,事情是我的对象没有去任何地方,它只是停留在那里...我想我的对象跳,当我按下键和程序显示我的图像上下移动..我试图通过简单的repaint()方法 ...

最新文章

  1. 七、Linux串口编程
  2. 学习windows编程 day6 之模拟记事本
  3. 【AGC013D】Pilling Up dp
  4. 通过jconsole监控tomcat JVM 内存、线程、CPU
  5. 1381. 设计一个支持增量操作的栈
  6. JFinalConfig
  7. 信息安全系统设计基础实验一 2013521120135216
  8. 怎样从 Ubuntu 12.10 升级到 Ubuntu 13.04
  9. MySQL抽稀_Android GPS定位轨迹抽稀之道格拉斯-普克(Douglas-Peuker)算法详解
  10. 【eclipse反编译工具】最好的反编译工具
  11. redis HSCAN命令及jedis的hscan方法
  12. sublime text3和package control
  13. python数据分析之航空公司客户价值分析
  14. 感觉自己技术还可以?十几个外包平台分享给你,让你外包接到手软!
  15. java基础--狂神
  16. 历届奥斯卡最佳影片及下载地址
  17. 推荐一下十三款内网穿透工具(超全)
  18. springboot拦截器Interceptor
  19. Installation failed with message Failed to finalize session : INSTALL_FAILED_INVALID_APK:
  20. 【大数据入门核心技术-Tez】(四)Tez与Hdfs整合

热门文章

  1. hdoj 1878 欧拉回路
  2. 手机html编辑器微信,手机微信编辑器,秒书是唯一支持手机的微信编辑器
  3. 职业教育计算机教育美育,中职计算机职业素质教育
  4. Python使用pycrypto进行RSA长字符串加密
  5. 岭南师范学院专插本计算机,2019年岭南师范学院专插本招生专业
  6. Deepin linux安装五笔输入法
  7. spring cloud oauth2系列篇(三)password模式获取access_token
  8. Java_表达式和运算符(算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和三元运算符)
  9. CoaXPress接口助CMOS相机实现更高速率
  10. 西工大-网安学院-2021复试-面试题目