五子棋PVP项目总结

本文介绍了使用Java、Spring Boot、MyBatis等技术实现一个五子棋对战项目的全过程,涵盖了用户注册、登录、匹配机制、对战功能的前后端实现,以及使用WebSocket进行实时通信。项目包括用户模块、匹配模块和对战模块,通过WebSocket进行数据传输,确保游戏的实时性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

五子棋PVP

项目链接:链接
(id:zhangsan key:123)
(id:lisi key:123)

项目背景

实现一个网页版五子棋对战程序.

支持以下核心功能:

  • 用户模块: 用户注册, 用户登录, 用户天梯分数记录, 用户比赛场次记录.
  • 匹配模块: 按照用户的天梯分数实现匹配机制.
  • 对战模块: 实现两个玩家在网页端进行五子棋对战的功能.

核心技术

  • Spring/SpringBoot/SpringMVC
  • WebSocket
  • MySQL
  • MyBatis
  • HTML/CSS/JS/AJAX

需求分析和概要设计

整个项目分成以下模块

  • 用户模块
  • 匹配模块
  • 对战模块

用户模块

用户模块主要负责用户的注册, 登录, 分数记录功能.

使用 MySQL 数据库存储数据.

客户端提供一个登录页面+注册页面.

服务器端基于 Spring + MyBatis 来实现数据库的增删改查.

匹配模块

用户登录成功, 则进入游戏大厅页面.

游戏大厅中, 能够显示用户的名字, 天梯分数, 比赛场数和获胜场数.

同时显示一个 “匹配按钮”.

点击匹配按钮则用户进入匹配队列, 并且界面上显示为 “取消匹配” .

再次点击则把用户从匹配队列中删除.

如果匹配成功, 则跳转进入到游戏房间页面.

页面加载时和服务器建立 websocket 连接. 双方通过 websocket 来传输 “开始匹配”, “取消匹配”, “匹配成功” 这样的信息.

对战模块

玩家匹配成功, 则进入游戏房间页面.

每两个玩家在同一个游戏房间中.

在游戏房间页面中, 能够显示五子棋棋盘. 玩家点击棋盘上的位置实现落子功能.

并且五子连珠则触发胜负判定, 显示 “你赢了” “你输了”.

页面加载时和服务器建立 websocket 连接. 双方通过 websocket 来传输 “准备就绪”, “落子位置”, “胜负” 这样的信息.

  • 准备就绪: 两个玩家均连上游戏房间的 websocket 时, 则认为双方准备就绪.
  • 落子位置: 有一方玩家落子时, 会通过 websocket 给服务器发送落子的用户信息和落子位置, 同时服务器再将这样的信息返回给房间内的双方客户端. 然后客户端根据服务器的响应来绘制棋子位置.
  • 胜负: 服务器判定这一局游戏的胜负关系. 如果某一方玩家落子, 产生了五子连珠, 则判定胜负并返回胜负信息. 或者如果某一方玩家掉线(比如关闭页面), 也会判定对方获胜.

项目创建

使用 IDEA 创建 SpringBoot 项目. 具体过程不再详细展开.

引入依赖如下:

依赖都是常规的 SpringBoot / Spring MVC / MyBatis 等, 没啥特别的依赖.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gobang</name>
    <description>联机对战五子棋</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

实现用户模块

编写数据库代码

数据库设计

创建 user 表, 表示用户信息和分数信息.

create database if not exists java_gobang;

use java_gobang;

drop table if exists user;
create table user(
    userId int primary key auto_increment,
    username varchar(50) unique,
    password varchar(50),
    score int, -- 天梯分数
    totalCount int, -- 比赛总场次
    winCount int -- 获胜场次
);

insert into user values(null, '张三', '123', 1000, 0, 0);
insert into user values(null, '李四', '123', 1000, 0, 0);
insert into user values(null, '王五', '123', 1000, 0, 0);
配置 MyBatis

编辑 application.yml

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/java_gobang?characterEncoding=utf8&useSSL=false
    username: root
    password: 2222
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml
创建实体类

创建 model.User

public class User {
   
    private int userId;
    private String username;
    private String password;
    private int score;
    private int totalCount;
    private int winCount;
}
创建 UserMapper

创建 model.UserMapper 接口.

此处主要提供四个方法:

  • selectByName: 根据用户名查找用户信息. 用于实现登录.
  • insert: 新增用户. 用户实现注册.
  • userWin: 用于给获胜玩家修改分数.
  • userLose: 用户给失败玩家修改分数.
@Mapper
public interface UserMapper {
   
    User selectByName(String username);

    int insert(User user);
    void userWin(User user);
    void userLose(User user);
}
实现 UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.model.UserMapper">
    <select id="selectByName" resultType="com.example.demo.model.User">
        select * from user where username = #{username}
    </select>

    <select id="selectById" resultType="com.example.demo.model.User">
        select * from user where userId = #{userId}
    </select>

    <insert id="insert">
        insert into user values(null, #{username}, #{password}, 1000, 0, 0)
    </insert>

    <update id="userWin">
        update user set score = score + 25, totalCount = totalCount + 1, winCount = winCount + 1 where userId = #{userId}
    </update>
    <update id="userLose">
        update user set score = score - 25, totalCount = totalCount + 1 where userId = #{userId}
    </update>
</mapper>

前后端交互接口

需要明确用户模块的前后端交互接口. 这里主要涉及到三个部分.

登录接口

请求:

POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=zhangsan&password=123

响应:

HTTP/1.1 200 OK
Content-Type: application/json

{
   
    userId: 1,
    username: 'zhangsan',
    score: 1000,
    totalCount: 10,
    winCount: 5
}    

如果登录失败, 返回的是一个 userId 为 0 的对象.

注册接口

请求:

POST /register HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=zhangsan&password=123

响应:

HTTP/1.1 200 OK
Content-Type: application/json

{
   
    userId: 1,
    username: 'zhangsan',
    score: 1000,
    totalCount: 10,
    winCount: 5
}    

如果注册失败(比如用户名重复), 返回的是一个 userId 为 0 的对象.

获取用户信息

请求:

GET /userInfo HTTP/1.1

响应:

HTTP/1.1 200 OK
Content-Type: application/json

{
   
    userId: 1,
    username: 'zhangsan',
    score: 1000,
    totalCount: 10,
    winCount: 5
}    

服务器开发

创建 api.UserAPI

主要实现三个方法:

  • login: 用来实现登录逻辑.
  • register: 用来实现注册逻辑.
  • getUserInfo: 用来实现登录成功后显示用户分数的信息.
@RestController
public class UserAPI {
   
    @Resource
    private UserMapper userMapper;

    @PostMapping("/login")
    @ResponseBody
    public Object login(String username, String password, HttpServletRequest req) {
   
        User user = userMapper.selectByName(username);
        System.out.println("login! user=" + user);
        if (user == null || !user.getPassword().equals(password)) {
   
            return new User();
        }
        HttpSession session = req.getSession(true);
        session.setAttribute("user", user);
        return user;
    }

    @PostMapping("/register")
    @ResponseBody
    public Object register(String username, String password) {
   
        User user = null;
        try {
   
            user = new User();
            user.setUsername(username);
            user.setPassword(password);
            System.out.println("register! user=" + user);
            int ret = userMapper.insert(user);
            System.out.println("ret: " + ret);
        } catch (org.springframework.dao.DuplicateKeyException e) {
   
            user = new User();
        }
        return user;
    }

    @GetMapping("/userInfo")
    @ResponseBody
    public Object getUserInfo(HttpServletRequest req) {
   
        // 从 session 中拿到用户信息
        HttpSession session = req.getSession(false);
        if (session == null) {
   
            return new User();
        }
        User user = (User) session.getAttribute("user");
        if (user == null) {
   
            return new User();
        }
        return user;
    }
}

客户端开发

登录页面

创建 login.html

<div class="nav">
    联机五子棋
</div>
<div class="login-container">
    <div class="login-dialog">
        <!-- 标题 -->
        <h3>登录</h3>
        <!-- 输入用户名 -->
        <div class="row">
            <span>用户名</span>
            <input type="text" id="username" name="username">
        </div>
        <!-- 输入密码 -->
        <div class="row">
            <span>密码</span>
            <input type="password" id="password" name="password">
        </div>
        <!-- 提交按钮 -->
        <div class="row submit-row">
            <button id="submit">提交</button> 
        </div>
    </div>  
</div>

创建 css/common.css

* {
   
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html, body {
   
    height: 100%;
    background-image: url(../image/back.png);
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
}

.nav {
   
    width: 100%;
    height: 50px;
    background-color: rgb(51, 51, 51);
    color: white;

    display: flex;
    align-items: center;
    padding-left: 20px;
}

.container {
   
    height: calc(100% - 50px);
    width: 100%;

    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(255, 255, 255, 0.7);
}

创建 css/login.css

.login-container {
   
    width: 100%;
    height: calc(100% - 50px);
    display: flex;
    justify-content: center;
    align-items: center;
}

.login-dialog {
   
    width: 400px;
    height: 320px;
    background-color: rgba(255, 255, 255, 0.8);
    border-radius: 10px;
}

.login-dialog h3 {
   
    text-align: center;
    padding: 50px 0;
}

.login-dialog .row {
   
    width: 100%;
    height: 50px;
    display: flex;
    justify-content: center;
    align-items: center;
}

.login-dialog .row span {
   
    display: block;
    /* 设置固定宽度, 能让文字和后面的输入框之间有间隙 */
    width: 100px;
    font-weight: 700;
}

.login-dialog #username,
.login-dialog #password {
   
    width: 200px;
    height: 40px;
    font-size: 20px;
    text-indent: 10px;
    border-radius: 10px;
    border: none;
    outline: none;
}

.login-dialog .submit-row {
   
    margin-top: 10px;
}

.login-dialog #submit {
   
    width: 300px;
    height: 50px;
    color: white;
    background-color: rgb(0, 128, 0);
    border: none;
    border-radius: 10px;
    font-size: 20px;
}

.login-dialog #submit:active {
   
    background-color: #666;
}

在 login.html 中编写 js 代码

  • 通过 jQuery 中的 AJAX 和服务器进行交互.
<script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
<script>
    // 通
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值