游戏设计中排行榜的设计和位运算的巧用


本文为作者原创,如需转载请标注出处。 http://blog.csdn.net/eclipse_c


在游戏中有各种各样的排行榜需求,比如按照战斗力来进行排行,如果战力相同,那么就比较玩家等级,等等。

下面介绍一种排行榜的设计,排名依据有多个字段,如:等级>战力>声望


简单说下需求:
宗门分为正派邪派,女宗。其中女宗也分正邪,只是多出来的一个字段来标识女性角色。


正派/邪派排名依据
宗门等级>宗主战力>宗门声望
女宗排名依据
宗主魅力>宗门等级>宗门声望
(宗主魅力通过其他玩法获得)
新秀排名依据
成立时间(越晚越靠前)


宗门等级,1~25左右
战力用一个int32来存储
宗门声望也差不多可以用一个int32来存储。


对于正邪排行榜,可以使用一个压缩的long型来作为排行的key值,对应一个treeMap,另外存储一个hashMap,其中的key为宗门id,
value为一个压缩的long。这样就形成了两个map,一一映射的关系。可以通过宗门id来查找这个宗门是否存在排行榜总,当玩家的战力宗门等级等相关值发生变化时。
查找原有的值,然后对这个值进行修改。


对于这个64位的long型的key值,可以采用将其拆分成3个部分,宗门等级占7位,后面32位用来存战力,然后剩下的32-7位来存宗门声望。



	private static final int CLAN_RANK_TYPE_GOOD_RANK = 1; // 宗门排行4种类型
	private static final int CLAN_RANK_TYPE_EVIL_RANK = 2;
	private static final int CLAN_RANK_TYPE_WOMAN_RANK = 3;
	private static final int CLAN_RANK_TYPE_NEW_RANK = 4;
	
	private static final int CLAN_RANK_GLOBAL_SIZE = 200;
	private static final int CLAN_RANK_LOCAL_SIZE = 50;
	
	//接口函数  handleClanGetBaseRankReq
	public synchronized List<SBean.ClanRankBaseInfo> getGlobalClanRank(int type)
	{
		return this.clanRank.getGlobalClanRank(type);
	}
	
	public synchronized List<SBean.ClanRankBaseInfo> getLocalClanRank(int gsid, int type)
	{
		return this.clanRank.getLocalClanRank(type, gsid);
	}
	
	public synchronized void addNewClanToRank(int clanId, int level, int prestiage, int value, String name, String ownerName)
	{
		this.clanRank.addNewRankMap(new SBean.ClanRankBaseInfo(clanId, level, prestiage, value, name, ownerName));
	}

	//宗门排行榜修改规则:当宗主战力、魅力值、宗门等级发生变化、声望发生变化时,修改排行榜的值。
	public synchronized void modefyClanRank(int gsid, int roleID, int fightPower, int charm)
	{
		long grid = GameData.getGlobalRoleID(gsid, roleID);
		Set<Integer> clanIds = mapr2c.get(grid);
		if(clanIds == null || clanIds.size() != 1)
		{
			return;
		}
		int clanIdOrError = getClanId(grid);
		execClanVisitor(clanIdOrError, clan -> {
            if(clan == null || clan.owner != GameData.getGlobalRoleID(gsid, roleID))
            {
                return;
            }
            int clanType = clan.type;
            String clanName = clan.name;
            String ownerName = clan.ownerName;
            int clanLevel = clan.level;
            int clanPrestiage = clan.prestige;
            if(charm != Clan.CLAN_DEFAULT_RANK_CHARM && charm > 0)
            {
            	this.clanRank.onClanRankChange(gsid, clanType, clanIdOrError, clanName, ownerName, clanLevel, fightPower, clanPrestiage, charm);
            }
            else{
            	this.clanRank.onClanRankChange(gsid, clanType, clanIdOrError, clanName, ownerName, clanLevel, fightPower, clanPrestiage);
            }
        });
	}
	
	// 通过clanId 来更新宗门排行榜中的宗门信息(在宗门等级声望变化时调用此函数)
	public synchronized void modifyClanRankById(int clanId)
	{
		execClanVisitor(clanId, clan -> {
            if(clan == null)
            {
                return;
            }
            long value = 0;
    		SBean.ClanRankBaseInfo info = null;
    		int charm = 0;
    		int fightPower = 0;
    		if(this.clanRank.gRank.containsKey(clanId))
    		{
    			value = this.clanRank.gRank.get(clanId);
    			info = this.clanRank.gGoodRank.get(value);
    			fightPower = getFightPowerByRankKey(value);
    		}
    		if(this.clanRank.eRank.containsKey(clanId))
    		{
    			value = this.clanRank.eRank.get(clanId);
    			info = this.clanRank.gEvilRank.get(value);
    			fightPower = getFightPowerByRankKey(value);
    		}
    		if(this.clanRank.wRank.containsKey(clanId))
    		{
    			value = this.clanRank.wRank.get(clanId);
    			info = this.clanRank.gWomanRank.get(value);
    			charm = getCharmByRankKey(value);
    		}
    		if(value == 0 || info == null)
    			return ;
    		
            int clanType = clan.type;
            String clanName = clan.name;
            String ownerName = clan.ownerName;
            int clanLevel = clan.level;
            int clanPrestiage = clan.prestige;
            int gsid = clan.getOwnerServerId();
            
            if(charm != Clan.CLAN_DEFAULT_RANK_CHARM && charm > 0)
            {
            	this.clanRank.onClanRankChange(gsid, clanType, clanId, clanName, ownerName, clanLevel, fightPower, clanPrestiage, charm);
            }
            else{
            	this.clanRank.onClanRankChange(gsid, clanType, clanId, clanName, ownerName, clanLevel, fightPower, clanPrestiage);
            }
        });
	}
	
	
	//功能函数
	private long getCheckPrestiage(long pre, int n)
	{
		if(pre > Integer.MAX_VALUE >> n)
		{
			return getCheckPrestiage(pre >> 1, n );
		}
		return pre;
	}
	
	private long getRankKeyByPAIBIE(int clanLevel, int fightPower, int clanPrestiage)
	{
		//宗门等级>宗主战力>宗门声望 2^7=128 2^32 2^25 组合成一个long型
		long result = 0;
		long level = (long)clanLevel;
		long power = (long)fightPower;
		long pre = getCheckPrestiage((long)clanPrestiage, 7);
		result |= level<<(25+32);
		result |= power<<25;
		result |= pre;
		return result;
	}
	
	private int getFightPowerByRankKey(long value)
	{
		return (int)((value>>25) & 0xffffffffL);
	}
	
	private long getRankKeyByMEILI(int charm, int clanLevel, int clanPrestiage)
	{
		//clanPrestiage > 2^25(33554432) 时会导致返回的result有问题。不过符合问题的情况出现的可能性极小
		long result = 0;
		long cha = (long)charm;
		long lev = (long)clanLevel;
		long pre = getCheckPrestiage((long)clanPrestiage, 7);
		result |= cha<<32;
		result |= lev<<(32-7);
		result |= pre;
		return result;
	}
	
	private int getCharmByRankKey(long value)
	{
		return (int)((value>>32) & 0xffffffffL);
	}
	
	private long getNextRankKey(long value, Map<Long, SBean.ClanRankBaseInfo> Rank)
	{
		if(Rank.containsKey(value))
			return getNextRankKey(value - 1, Rank);
		return value;
	}
	
	/**
	 * @date 2016.6.15
	 * @problem: 当创建2个相同的角色时候,并创建相同类型的宗门,会导致二者对应的排行key值相同,在Rank这个map中只会保存一份
	 * @solve: 解决冲突的方法:如果找到了两个相同的key,那么表示这两个排名并列,那么找到它-1的key是否存在,如果不存在则作为key值,否则继续-1找
	 * @analysis: 由于最后一位减一操作,会导致排行榜排名出现问题,但是出问题的情况仅仅是在最后一个参数(声望),即前面2个参数都相同时才会出现这个问题。
	 */
	private void changeRankMap(int clanId, SBean.ClanRankBaseInfo info, long newRank, Map<Integer, Long>rank, Map<Long, SBean.ClanRankBaseInfo> Rank , boolean isLocal)
	{
		int size = isLocal ? CLAN_RANK_LOCAL_SIZE : CLAN_RANK_GLOBAL_SIZE;
		if(Rank.size() < size)
		{
			if(rank.containsKey(clanId))
			{
				long oldRank = rank.get(clanId); 
				if(Rank.containsKey(oldRank))
				{
					rank.remove(clanId);
					Rank.remove(oldRank);
					long realRank = getNextRankKey(newRank, Rank);
					rank.put(clanId, realRank);
					Rank.put(realRank, info);
				}
			}
			else{
				long realRank = getNextRankKey(newRank, Rank);
				rank.put(clanId, realRank);
				Rank.put(realRank, info);
			}
		}
		else{ // the map size equal the CLAN_RANK_LOCAL_SIZE
			if(rank.containsKey(clanId))
			{
				long oldRank = rank.get(clanId);
				if(Rank.containsKey(oldRank))
				{
					rank.remove(clanId);
					Rank.remove(oldRank);
					long realRank = getNextRankKey(newRank, Rank);
					rank.put(clanId, realRank);
					Rank.put(realRank, info);
				}
			}
			else{
				int tempKey = 0;
				long tempValue = Long.MAX_VALUE;
				for( Integer t : rank.keySet())
				{
					if( rank.get(t) < tempValue )
					{
						tempKey = t;
						tempValue = rank.get(t);
					}
				}
				if( newRank > tempValue)
				{
					rank.remove(tempKey);
					Rank.remove(tempValue);
					long realRank = getNextRankKey(newRank, Rank);
					rank.put(clanId, realRank);
					Rank.put(realRank, info);
				}
			}
		}
	}
	
	//相同gs下宗门排行(只在ClanRank类内实例化)
	public class LocalClanRank
	{
		public LocalClanRank()
		{
			this.goodRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
				public int compare(Long a, Long b)
				{
					return b.compareTo(a);
				}
			});
			this.evilRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
				public int compare(Long a, Long b)
				{
					return b.compareTo(a);
				}
			});
			this.womanRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
				public int compare(Long a, Long b)
				{
					return b.compareTo(a);
				}
			});
			
			this.gRank = new HashMap<Integer, Long>();
			this.eRank = new HashMap<Integer, Long>();
			this.wRank = new HashMap<Integer, Long>();
		}
		
		public List<SBean.ClanRankBaseInfo> getLocalClanRank(int type)
		{
			if(type == CLAN_RANK_TYPE_GOOD_RANK)
				return new ArrayList<SBean.ClanRankBaseInfo>(goodRank.values());
			if(type == CLAN_RANK_TYPE_EVIL_RANK)
				return new ArrayList<SBean.ClanRankBaseInfo>(evilRank.values());
			if(type == CLAN_RANK_TYPE_WOMAN_RANK)
				return new ArrayList<SBean.ClanRankBaseInfo>(womanRank.values());
			return GameData.emptyList();
		}
		
		
		//刷新女宗排名
		public void onLocalClanRankChange(int clanType, int clanId, String clanName, String ownerName, int clanLevel, int fightPower, int clanPrestiage, int charm)
		{
			SBean.ClanRankBaseInfo info = new SBean.ClanRankBaseInfo(clanId, clanLevel, clanPrestiage, fightPower, clanName, ownerName);
			if(clanType == Clan.CLAN_TYPE_N)
			{
				long newRank = getRankKeyByMEILI(charm, clanLevel, clanPrestiage);
				changeRankMap(clanId, info, newRank, wRank, womanRank, true);
			}
		}
		
		//刷新排行榜,当有宗门等级/宗主战力发/宗门声望发生变化,调用这个函数。
		public void onLocalClanRankChange(int clanType, int clanId, String clanName, String ownerName, int clanLevel, int fightPower, int clanPrestiage)
		{
			//updateRoleFightPower() 这个函数是战力发生变化时候调用的。
			SBean.ClanRankBaseInfo info = new SBean.ClanRankBaseInfo(clanId, clanLevel, clanPrestiage, fightPower, clanName, ownerName);
			if(clanType == Clan.CLAN_TYPE_Z)
			{
				long newRank = getRankKeyByPAIBIE(clanLevel, fightPower, clanPrestiage);
				changeRankMap(clanId, info, newRank, gRank, goodRank, true);
			}
			if(clanType == Clan.CLAN_TYPE_X)
			{
				long newRank = getRankKeyByPAIBIE(clanLevel, fightPower, clanPrestiage);
				changeRankMap(clanId, info, newRank, eRank, evilRank, true);
			}
		}
		
		public void removeClanFromRankList(int clanId)
		{
			if(gRank.containsKey(clanId))
			{
				goodRank.remove(gRank.get(clanId));
				gRank.remove(clanId);
			}
			if(eRank.containsKey(clanId))
			{
				evilRank.remove(eRank.get(clanId));
				eRank.remove(clanId);
			}
			if(wRank.containsKey(clanId))
			{
				womanRank.remove(wRank.get(clanId));
				wRank.remove(clanId);
			}
		}
		
		private HashMap<Integer, Long> gRank; // key is clanId.两个map一一映射
		private HashMap<Integer, Long> eRank;
		private HashMap<Integer, Long> wRank;
		
		private TreeMap<Long, SBean.ClanRankBaseInfo> goodRank; // 正派、邪派、女宗、新秀排行
		private TreeMap<Long, SBean.ClanRankBaseInfo> evilRank;
		private TreeMap<Long, SBean.ClanRankBaseInfo> womanRank;
	}
	
	//该宗门服务器中的所有宗门排行(宗门排行榜只需要实例化一个这个类的对象即可)
	public class ClanRank
	{
		public ClanRank()
		{
			this.gGoodRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
				public int compare(Long a, Long b)
				{
					return b.compareTo(a);
				}
			});
			this.gEvilRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
				public int compare(Long a, Long b)
				{
					return b.compareTo(a);
				}
			});
			this.gWomanRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
				public int compare(Long a, Long b)
				{
					return b.compareTo(a);
				}
			});
			this.gNewRank = new LinkedList<SBean.ClanRankBaseInfo>();
			this.localServerRank = new HashMap<Integer, LocalClanRank>();
			this.gRank = new HashMap<Integer, Long>();
			this.eRank = new HashMap<Integer, Long>();
			this.wRank = new HashMap<Integer, Long>();
		}
		
		public List<SBean.ClanRankBaseInfo> getGlobalClanRank(int type)
		{
			if(type == CLAN_RANK_TYPE_GOOD_RANK)
				return new ArrayList<SBean.ClanRankBaseInfo>(gGoodRank.values());
			if(type == CLAN_RANK_TYPE_EVIL_RANK)
				return new ArrayList<SBean.ClanRankBaseInfo>(gEvilRank.values());
			if(type == CLAN_RANK_TYPE_WOMAN_RANK)
				return new ArrayList<SBean.ClanRankBaseInfo>(gWomanRank.values());
			if(type == CLAN_RANK_TYPE_NEW_RANK)
				return new ArrayList<SBean.ClanRankBaseInfo>(gNewRank);
			return GameData.emptyList();
		}
		
		public List<SBean.ClanRankBaseInfo> getLocalClanRank(int type, int gsId)
		{
			if(!localServerRank.containsKey(gsId))
				return GameData.emptyList();
			return localServerRank.get(gsId).getLocalClanRank(type);
		}
		
		public void addNewRankMap(SBean.ClanRankBaseInfo info)
		{
			if(gNewRank.size() >= CLAN_RANK_GLOBAL_SIZE)
			{
				gNewRank.removeLast();
			}else
			{
				gNewRank.addFirst(info);
			}
		}
		
		//刷新女宗排名
		public void onClanRankChange(int gsid, int clanType, int clanId, String clanName, String ownerName, int clanLevel, int fightPower, int clanPrestiage, int charm)
		{
			SBean.ClanRankBaseInfo info = new SBean.ClanRankBaseInfo(clanId, clanLevel, clanPrestiage, fightPower, clanName, ownerName);
			if(clanType == Clan.CLAN_TYPE_N)
			{
				long newRank = getRankKeyByMEILI(charm, clanLevel, clanPrestiage);
				changeRankMap(clanId, info, newRank, wRank, gWomanRank, false);
				//修改本服排行的女宗
				if( ! localServerRank.containsKey(gsid))
				{
					localServerRank.put(gsid, new LocalClanRank());
				}
				localServerRank.get(gsid).onLocalClanRankChange(clanType, clanId, clanName, ownerName, clanLevel, fightPower, clanPrestiage);
			}
		}
		//刷新正邪宗门排名
		public void onClanRankChange(int gsid, int clanType, int clanId, String clanName, String ownerName, int clanLevel, int fightPower, int clanPrestiage)
		{
			SBean.ClanRankBaseInfo info = new SBean.ClanRankBaseInfo(clanId, clanLevel, clanPrestiage, fightPower, clanName, ownerName);
			if(clanType == Clan.CLAN_TYPE_Z)
			{
				long newRank = getRankKeyByPAIBIE(clanLevel, fightPower, clanPrestiage);
				changeRankMap(clanId, info, newRank, gRank, gGoodRank, false);
			}
			if(clanType == Clan.CLAN_TYPE_X)
			{
				long newRank = getRankKeyByPAIBIE(clanLevel, fightPower, clanPrestiage);
				changeRankMap(clanId, info, newRank, eRank, gEvilRank, false);
			}
			//增加本服排行
			if( ! localServerRank.containsKey(gsid))
			{
				localServerRank.put(gsid, new LocalClanRank());
			}
			localServerRank.get(gsid).onLocalClanRankChange(clanType, clanId, clanName, ownerName, clanLevel, fightPower, clanPrestiage);
		}
		
		public void removeClanFromRankList(int clanId, int gsid)
		{
			if(gRank.containsKey(clanId))
			{
				gGoodRank.remove(gRank.get(clanId));
				gRank.remove(clanId);
			}
			if(eRank.containsKey(clanId))
			{
				gEvilRank.remove(eRank.get(clanId));
				eRank.remove(clanId);
			}
			if(wRank.containsKey(clanId))
			{
				gWomanRank.remove(wRank.get(clanId));
				wRank.remove(clanId);
			}
			// 移除各个gs内的排名
			if( ! localServerRank.containsKey(gsid))
				return ;
			localServerRank.get(gsid).removeClanFromRankList(clanId);
		}
		
		private HashMap<Integer, Long> gRank; // key is clanId.两个map一一映射
		private HashMap<Integer, Long> eRank;
		private HashMap<Integer, Long> wRank;
		
		private TreeMap<Long, SBean.ClanRankBaseInfo> gGoodRank; // 全区正派、邪派、女宗、新秀排行
		private TreeMap<Long, SBean.ClanRankBaseInfo> gEvilRank;
		private TreeMap<Long, SBean.ClanRankBaseInfo> gWomanRank;
		private LinkedList<SBean.ClanRankBaseInfo> gNewRank;
		
		private HashMap<Integer, LocalClanRank> localServerRank; // gs服务器ID,对应的表
	}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值