0%

Unity 做扑克游戏-锄大地

用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

1
2
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";

/**
* 大厅玩家 进房间后remove
*/
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

1
2
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 List<Room> data;
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:
//roomList
var roomList = JsonUtility.FromJson<CommonResponse<List<Room>>>(message).data;
if (roomList != null && roomList.Count > 0)
RoomManager.RefreshRoomList(roomList);
break;
case 202:
//room
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: //有玩家PASS
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;
}
}