最新要实现app答题对战的任务,准备用websocket去实现,查了百度也没参考,就自己写了写
实现 WebSocket 的抢答答题游戏可以按照以下步骤进行:
-
设计数据结构:为了记录每个玩家的得分和答题情况,可以定义一个玩家类(Player)来存储相关信息,例如玩家姓名、得分等。同时,需要设计题目数据的结构,可以使用题目类(Question)来表示每个问题,包括问题内容和正确答案。后面加了房间信息(room)
-
准备题目:在服务器端准备一系列的题目,并将其存储在列表或数组中。
-
1v1 模式答题流程:
- 等待两个玩家加入游戏并建立 WebSocket 连接。
- 随机选择一道题目发送给玩家。
- 如果有一个玩家回答问题,正确并将答案发送给服务器。错误,就让他等待,如果没人回答或者都答错了,就等待10s之后跳下一题
- 如果答案正确,则给第一个玩家加一分,并通知两个玩家当前得分情况。游戏结束。
- 如果答案错误,则将问题和答案传递给下一个玩家,并重复上述步骤,直到有玩家答对或所有玩家都答错。
-
2v2 或多对多模式答题流程:
- 等待足够数量的玩家加入并建立 WebSocket 连接。
- 根据玩家人数随机分组,每个小组内玩家互为队友。
- 随机选择一道题目发送给第一个小组的第一个玩家。
- 第一个玩家回答问题,并将答案发送给服务器。
- 如果答案正确,则给小组内所有玩家加一分,并通知所有玩家当前得分情况。游戏结束条件可根据实际需求设定。
- 如果答案错误,则将问题和答案传递给下一个小组的第一个玩家,并重复上述步骤,直到有玩家答对或所有玩家都答错。
先创建对象:player 玩家信息
import lombok.Data;
import javax.websocket.Session;
import java.io.IOException;
// Player 类表示参与游戏的玩家和相关信息
@Data
public class Player {
private Session session;
private String name;
private int score;
private GameQuestion currentQuestion;
private boolean playing;
//游戏类型
private String mode;
private String roomId;
//是否回答过问题
private boolean answered;
private int currentQuestionIndex;
public Player(Session session) {
this.session = session;
//this.name = "Player " + session.getId();
this.name = session.getRequestParameterMap().get("name").get(0);
this.score = 0;
this.playing = false;
this.mode = session.getRequestParameterMap().get("mode").get(0);
this.currentQuestionIndex = 0;
}
public Session getSession() {
return session;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public GameQuestion getCurrentQuestion() {
return currentQuestion;
}
public void setCurrentQuestion(GameQuestion currentQuestion) {
this.currentQuestion = currentQuestion;
}
public boolean isPlaying() {
return playing;
}
public void setPlaying(boolean playing) {
this.playing = playing;
}
public void send(String message) throws IOException {
session.getBasicRemote().sendText(message);
}
public void addScore() {
score++;
}
}
room 房间信息
import lombok.Data;
import javax.management.timer.Timer;
import java.util.ArrayList;
import java.util.List;
/// Room 类表示游戏房间,包括玩家、题目、得分等信息
@Data
public class Room {
private String roomName;
private List<Player> players;
private boolean started;
private String mode; // 新增游戏模式字段
private int currentQuestionIndex;
private List<Question> questions;
private Timer timer;
public Room(String roomName) {
this.roomName = roomName;
this.players = new ArrayList<>();
this.started = false;
this.currentQuestionIndex = 0;
this.questions = new ArrayList<>();
this.timer = new Timer();
}
}
问题信息 question
import lombok.Data;
// Question 类表示每个题目和对应答案
@Data
public class Question {
private String content;
private String answer;
public Question(String content, String answer) {
this.content = content;
this.answer = answer;
}
}
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/game")
public class Server {
// 存储每个房间的玩家列表
private static Map<String, List<Player>> rooms = new HashMap<>();
// 存储每个玩家的答题状态和得分
private static Map<Session, Player> players = new HashMap<>();
// 存储问题
private static List<Question> questions = new ArrayList<>();
static {
// 初始化一些题目
questions.add(new Question("2+2=?", "4"));
questions.add(new Question("3*7=?", "21"));
questions.add(new Question("中国首都是?", "北京"));
}
@OnOpen
public void onOpen(Session session) throws IOException {
// 处理新玩家加入游戏的请求
// 创建一个新的Player对象,并将其与session关联
Player player = new Player(session);
players.put(session, player);
System.out.println("New player joined: " + player.getName());
// 获取可加入的房间列表
List<String> availableRooms = getAvailableRooms();
if (availableRooms.isEmpty()) {
// 如果没有可加入的房间,则创建新房间
String roomId = createRoom();
player.setRoomId(roomId);
System.out.println("New room created: " + roomId);
player.send("You created a new room: " + roomId);
} else {
// 加入第一个可加入的房间
String roomId = availableRooms.get(0);
player.setRoomId(roomId);
System.out.println("Player joined room: " + roomId);
player.send("You joined room: " + roomId);
// 检查房间是否已满,如果已满则开始游戏
if (isRoomFull(roomId)) {
startGame(roomId);
}
}
}
@OnClose
public void onClose(Session session) throws IOException {
// 处理玩家离开游戏的请求
// 从players中移除离开的玩家,并检查房间是否需要解散
Player player = players.get(session);
players.remove(session);
if (player != null) {
leaveRoom(player);
}
System.out.println("Player left: " + player.getName());
}
@OnError
public void onError(Throwable throwable) {
// 处理WebSocket错误
System.err.println("WebSocket error: " + throwable.getMessage());
}
@OnMessage
public void onMessage(Session session, String message) throws IOException {
// 处理玩家答题的请求
Player player = players.get(session);
if (player != null && player.isPlaying() && !player.isAnswered()) {
Question currentQuestion = player.getCurrentQuestion();
if (message.equals(currentQuestion.getAnswer())) {
// 答案正确,增加玩家分数,并广播当前得分情况
player.addScore();
broadcastScores(player.getRoomId());
player.setAnswered(true);
player.send("Correct! Your score is now " + player.getScore());
// 检查是否所有玩家都已经答过题
if (areAllPlayersAnswered(player.getRoomId())) {
checkGameOver(player.getRoomId());
}
} else {
// 答案错误,提示下一个玩家答题
player.send("Wrong answer, please wait for the next question.");
passQuestion(player.getRoomId());
}
}
}
private List<String> getAvailableRooms() {
// 获取当前可加入的房间列表
List<String> availableRooms = new ArrayList<>();
for (String roomId : rooms.keySet()) {
if (!isRoomFull(roomId)) {
availableRooms.add(roomId);
}
}
return availableRooms;
}
private boolean isRoomFull(String roomId) {
// 检查房间是否已满
List<Player> roomPlayers = rooms.get(roomId);
return roomPlayers != null && roomPlayers.size() >= 2;
}
private String createRoom() {
// 创建新的房间
String roomId = generateRoomId();
rooms.put(roomId, new ArrayList<>());
return roomId;
}
private String generateRoomId() {
// 生成唯一的房间ID
String roomId;
do {
// 随机生成4位数的字符串作为房间ID
roomId = String.format("%04d", new Random().nextInt(10000));
} while (rooms.containsKey(roomId));
return roomId;
}
private void leaveRoom(Player player) throws IOException {
// 离开房间,并检查房间是否需要解散
String roomId = player.getRoomId();
List<Player> roomPlayers = rooms.get(roomId);
roomPlayers.remove(player);
System.out.println("Player left room: " + roomId);
// 如果离开的是最后一个玩家,则解散房间
if (roomPlayers.isEmpty()) {
rooms.remove(roomId);
System.out.println("Room dissolved: " + roomId);
} else {
if (player.isPlaying() && !player.isAnswered()) {
// 如果离开的玩家正在答题中且未回答,则传递问题给下一个玩家
passQuestion(roomId);
}
// 广播当前得分情况
broadcastScores(roomId);
}
}
private void startGame(String roomId) throws IOException {
// 开始游戏,发送第一个题目给每个玩家
List<Player> roomPlayers = rooms.get(roomId);
List<Question> gameQuestions = new ArrayList<>(questions);
Collections.shuffle(gameQuestions);
for (int i = 0; i < roomPlayers.size(); i++) {
Player player = roomPlayers.get(i);
player.setPlaying(true);
player.setScore(0);
player.setCurrentQuestion(gameQuestions.get(i));
player.setAnswered(false);
player.send("Game started! Answer this question: " + gameQuestions.get(i).getContent());
}
// 启动定时器,10秒内没有玩家答题则自动进入下一题
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if (areAllPlayersAnswered(roomId)) {
checkGameOver(roomId);
} else {
passQuestion(roomId);
}
}
}, 10000);
}
private void passQuestion(String roomId) throws IOException {
// 将问题传递给下一个玩家
List<Player> roomPlayers = rooms.get(roomId);
Player currentPlayer = getCurrentPlayer(roomPlayers);
currentPlayer.setAnswered(true);
int nextIndex = (roomPlayers.indexOf(currentPlayer) + 1) % roomPlayers.size();
Player nextPlayer = roomPlayers.get(nextIndex);
nextPlayer.setPlaying(true);
nextPlayer.setCurrentQuestion(currentPlayer.getCurrentQuestion());
nextPlayer.setAnswered(false);
nextPlayer.send("Answer this question: " + currentPlayer.getCurrentQuestion().getContent());
}
private void checkGameOver(String roomId) throws IOException {
// 检查游戏是否结束
List<Player> roomPlayers = rooms.get(roomId);
boolean allAnswered = true;
for (Player player : roomPlayers) {
if (!player.isAnswered()) {
allAnswered = false;
break;
}
}
if (allAnswered) {
// 所有玩家都已答题完毕,比较分数并广播结果
List<Player> winners = getWinners(roomPlayers);
String message;
if (winners.isEmpty()) {
message = "Game over! It's a tie.";
} else {
message = "Game over! Winners: ";
for (Player winner : winners) {
message += winner.getName() + "(" + winner.getScore() + " points) ";
}
}
for (Player player : roomPlayers) {
player.send(message);
}
}
}
private List<Player> getWinners(List<Player> players) {
// 获取分数最高的玩家
List<Player> winners = new ArrayList<>();
int maxScore = 0;
for (Player player : players) {
int score = player.getScore();
if (score > maxScore) {
maxScore = score;
winners.clear();
winners.add(player);
} else if (score == maxScore) {
winners.add(player);
}
}
return winners;
}
private boolean areAllPlayersAnswered(String roomId) {
// 检查是否所有玩家都已经答过题
List<Player> roomPlayers = rooms.get(roomId);
for (Player player : roomPlayers) {
if (!player.isAnswered()) {
return false;
}
}
return true;
}
private void broadcastScores(String roomId) throws IOException {
// 广播当前得分情况
List<Player> roomPlayers = rooms.get(roomId);
String scoreMessage = "Current scores: ";
for (Player player : roomPlayers) {
scoreMessage += player.getName() + "(" + player.getScore() + " points) ";
}
for (Player player : roomPlayers) {
player.send(scoreMessage);
}
}
private Player getCurrentPlayer(List<Player> players) {
// 获取当前回答问题的玩家
for (Player player : players) {
if (!player.isAnswered()) {
return player;
}
}
return players.get(0);
}
}
提供的这个demo发送问题是一个一个发送的,可以把player.send的地方修改一下,修改成全部人一起抢答一题,然后谁先答对就全部通知,然后刷新下一题。