用unity做了锄大地(单机,联机)
游戏界面
单人游戏
多人游戏-房间
各玩家画面
 
多人游戏-开始
难点
出牌判断
记录最后出的牌
用[将要出的牌]与[最后出的牌] 先进行数量
确保数量一致进行牌型判断
牌型一致再细分判断,比如3+2由3张同样牌的点数判断 [55544] < [66633] 因为 [555]<[666]
联机
协议选择
unity上没挑选到合适的联机方案,纯局域网或者限制多
摇摇脑袋决定自己写
一般联机主要有几种方案 Socket WebSocket之类
因为WebSocket支持双向发消息 所以服务端选择用JAVA 编写 WebSocket
选择JAVA的原因是相对其他语言比较熟悉JAVA
实现选择
unity WebSocket客户端可用js可用c#
因为原先编写单人模式就用了纯c#,不想客户端 js+c#,所以选择c#
不过找c# unity的WebSocket支持方案浪费了很多时间和精力
有比较出名的Mirror-NetWorking [https://mirror-networking.com/]
还有unity asset store上面一些其他的server 插件
不过觉得定制化有点重
然后选择了BestHTTP
传输数据
然后就是熟悉的套路:
传输用json
server用springboot jackson objectmapper
client用 JsonUtility(JsonUtility只支持简单的json) 和 LitJson.JsonMapper
client与server通过WebSocket协议进行握手
握手成功相当于进入大厅
client在大厅中能获得server传来房间列表刷新的信息
client进入房间后能获得server传来房间内部玩家的信息
client在房间的操作传给server ,server再传给房间所有玩家,再进行渲染
玩法
维基百科有介绍
这里以香港玩法
点数 2>A>K>Q>J>10>9>8>7>6>5>4>3
花色 黑桃>红桃>梅花>方块
https://zh.wikipedia.org/zh-hans/%E9%8B%A4%E5%A4%A7%E5%BC%9F
代码
这次的代码比较多又杂
稍微挑一些出来
server
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | @ServerEndpoint("/webSocket/room/{playerName}")@Component
 @Slf4j
 public class RoomEndpoint {
 private static final Map<String, Room> roomMap = new ConcurrentHashMap<>();
 public static final String LIST = "LIST";
 public static final String CREATE = "CREATE";
 public static final String JOIN = "JOIN";
 public static final String EXIT = "EXIT";
 public static final String READY = "READY";
 public static final String CANCEL_READY = "CANCEL_READY";
 public static final String SET_HANDCARD = "SET_HANDCARD";
 public static final String START_GAME = "START_GAME";
 public static final String GET_TURN = "GET_TURN";
 public static final String PLAY_CARD = "PLAY_CARD";
 public static final String PASS = "PASS";
 public static final String CLEAN_DROP_ZONE = "CLEAN_DROP_ZONE";
 public static final String WIN = "WIN";
 
 
 
 
 private static Map<Session, String> playerInHall = new ConcurrentHashMap<>();
 
 private ObjectMapper objectMapper = new ObjectMapper();
 
 
 @OnOpen
 public void onOpen(@PathParam("playerName") String playerName,
 Session session) throws IOException {
 
 log.info("{}连入大厅", playerName);
 if (playerInHall.values().contains(playerName) ||
 roomMap.values().stream().map(room -> room.getPlayerList()).map(players -> playerName)
 .collect(Collectors.toList()).equals(playerName)) {
 sendMessage(session, CommonResponse.buildFail(ResponseCodeEnum.已存在此用户名.code, ResponseCodeEnum.已存在此用户名.message));
 return;
 }
 playerInHall.put(session, playerName);
 }
 ......
 
 | 
client
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 
 | [Serializable]public class CommonResponse<T>
 {
 public int code;
 
 public string message;
 
 
 public T data;
 }
 
 [Serializable]
 public class Room
 {
 public string name;
 public int roomNumber;
 public int playerCount;
 public List<string> playerNameList;
 }
 
 [Serializable]
 public class Player
 {
 public int index;
 public String name;
 public List<PokerController.Poker> poker;
 }
 
 private void OnMessage(WebSocket websocket, string message)
 {
 Debug.Log("OnMessage" + message);
 var commonResponse = JsonUtility.FromJson<CommonResponse<string>>(message);
 switch (commonResponse.code)
 {
 case 200:
 case 201:
 
 var roomList = JsonUtility.FromJson<CommonResponse<List<Room>>>(message).data;
 if (roomList != null && roomList.Count > 0)
 RoomManager.RefreshRoomList(roomList);
 break;
 case 202:
 
 var room = JsonUtility.FromJson<CommonResponse<Room>>(message).data;
 GameManager.RefreshRoom(room, room.playerNameList.FindLastIndex(name => name.Equals(_username)));
 break;
 case 203:
 var handcardList = JsonMapper.ToObject<CommonResponse<List<PokerController.Poker>>>(message).data;
 GameManager.SetHandCard(handcardList);
 break;
 case 204:
 
 var player = JsonMapper.ToObject<CommonResponse<Player>>(message).data;
 GameManager.SetLastPlay(player.index, player.poker);
 break;
 case 205:
 var turn = JsonMapper.ToObject<CommonResponse<int>>(message).data;
 GameManager.SetTurn(turn);
 break;
 case 206:
 GameManager.CleanDropZone();
 break;
 case 207:
 var passIndex = JsonMapper.ToObject<CommonResponse<int>>(message).data;
 GameManager.SetPass(passIndex);
 break;
 case 208:
 var playerList = JsonMapper.ToObject<CommonResponse<List<Player>>>(message).data;
 GameManager.RefreshPlayer(playerList);
 break;
 case 209:
 var winMessage = JsonMapper.ToObject<CommonResponse<string>>(message).data;
 GameManager.AnnounceWin(winMessage);
 break;
 }
 }
 
 |