几个月的断断续续开发,终于也将H5斗地主游戏的前后端都基本完成了,也实现了电脑端和手机端的适应。总的来说,从这个项目中学到的挺多,不论是后台业务的开发还是前端功能的实现。从想法的最初萌生到功能一次次的累加和优化以至完成,都经历了精心的设计和尝试。
因此,特地开了这系列博客,希望能记录下设计的大致思路和逻辑。如果你感兴趣的话,那便是极好的。在第一节,我将会给大家介绍应用的模块分割,以及个体的设计(对应在编程则是 Java 实体类)。
我将后台应用主要分成了以下的三个模块:
算法模块构成了游戏的规则判断的实现,有点类似 “ 裁判 ” 的角色,它主要提供的功能有:
业务模块搭建和玩家客户端(前端)的通信桥梁,负责处理房间管理(创建房间、退出房间),叫牌、出牌以及游戏结束后计分逻辑的具体实现。
在H5中,我们需要及时更新房间内的信息(例如某个玩家加入、游戏开始、玩家出牌等操作),就必须要使用到webSocket
协议来支持。因此需要利用通过模块来通知前端这些事件的发生,让玩家的客户端能及时反应这些事件的发生。
接下来我们再来针对个体来讨论,并根据游戏中的个体创建所对应的POJO
实体类。让我们想象这个游戏有哪些个体?
17
张(地主为20
张);接下来我们根据这些个体,来创建对应的实体类。
房间的属性并不复杂,主要的属性由以下几个。有个特殊的属性stepNum
主要是用来判断当前是否是某个玩家的出牌回合,后面会做具体的讲解。
@Data
public class Room {
private String id; // 房间号
private String password; // 房间密码
private boolean locked; // 房间是否设置密码,true为设置
private List<Player> playerList; // 当前玩家列表
private RoomStatusEnum status; // 房间的状态(准备/开始)
private int multiple; // 房间底分
private int stepNum; // 每局走的步数,用来控制玩家的出牌回合
}
public enum RoomStatusEnum {
PLAYING("游戏中"),
PREPARING("准备中");
}
因为每个玩家都有各自的出牌顺序,所以需要为每个玩家分配一个id
号,并可以通过id
获得下家出牌的玩家。在该应用的设计中,会将Player
玩家对象和User
用户对象相关联,目的是将它们的属性区分。
@Data
public class Player {
private Integer id; // 玩家在当前房间的座位顺序
private User user; // 玩家的用户对象
private List<Card> cards; // 玩家当前手中的牌
private boolean ready; // 玩家是否准备
private IdentityEnum identity; // 当前局的身份(地主、农民)
}
public enum IdentityEnum {
LANDLORD("地主"),
FARMER("农民");
}
牌的设计稍微复杂一些, 如下面一张牌所示:
我们通过三个标识属性来区分每一张牌:
@Data
public class Card implements Comparable<Card> {
private int id; // 牌的数字ID,用于分牌操作
private CardTypeEnum type; // 牌的类型
private CardNumberEnum number; // 牌的数值
private CardGradeEnum grade; // 牌的等级
}
对应着牌的花色,如黑桃、红桃、方块、梅花,以及特殊的大小王。枚举类为:
public enum CardTypeEnum {
SPADE("黑桃"),
HEART("红桃"),
CLUB("梅花"),
DIAMOND("方块"),
SMALL_JOKER("小王"),
BIG_JOKER("大王");
}
即牌的数字,从1 ~ 15
;枚举类的定义为:
public enum CardNumberEnum {
ONE(1),
TWO(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9),
TEN(10),
JACK(11), // J
LADY(12), // Q
KING(13), // K
SMALL_JOKER(14), // 小王
BIG_JOKER(15); // 大王
}
即牌的等级,也是从1 ~ 15
;枚举类的定义为:
public enum CardGradeEnum {
// 3 ~ K
FIRST(1), // 3
SECOND(2), // 4
THIRD(3), // 5
FOURTH(4), // 6
FIFTH(5), // 7
SIXTH(6), // 8
SEVENTH(7), // 9
EIGHTH(8), // 10
NINTH(9), // J
TENTH(10), // Q
ELEVENTH(11), // K
// A 和 2
TWELFTH(12),
THIRTEENTH(13),
// 大小王
FOURTEENTH(14),
FIFTEENTH(15);
}
看到这里你可能会纳闷,这个属性和cardNumber
有什么区别。的确,这是一个比较特殊的标识属性,我们都知道,虽然从数学意义上来说,A
和2
比3
小;但是,在斗地主的规则中却比3
大。
因此,cardNumber
只是用来显示牌的数值;而cardGrade
用来衡量牌的等级,可以用于比较牌的大小。