【宇宙回响】从Canvas到MySQL:飞机大战的全栈交响曲【附演示视频与源码】

🌟 这是星际大战系列的第三篇送福利文章,感谢一路以来支持和关注这个项目的每一位朋友!

💡 文章力求严谨,但难免有疏漏之处,欢迎各位朋友指出,让我们一起在交流中进步。

🎁 项目代码、文档和相关资源都可以免费获取,希望能帮助到更多对游戏开发感兴趣的朋友。

💌 如果您有任何想法、建议或疑问,都欢迎在评论区留言或通过私信与我交流。您的每一个反馈都是项目进步的动力!

文章目录

  • [【福利分享】星际大战飞机大战升级版 - 前后端完整版本](#【福利分享】星际大战飞机大战升级版 - 前后端完整版本)

【福利分享】星际大战飞机大战升级版 - 前后端完整版本

繁星点点,太空浩瀚。让我们再次启程,在代码中探索无尽的可能。

前言

大家好,我是程序员果冻~。首先要特别感谢之前纯前端版本的广大读者们的支持和鼓励!你们的点赞、收藏、评论和私信建议给了我极大的动力。应大家的要求,这次我为大家带来了全新升级的前后端完整版本,适合正在学习JAVA的新手朋友学习练习。

源码附文章末尾。

演示视频

前后端进阶版飞机大战

如果上面的视频无法观看,可能是因为还在审核中,可以先看下面的视频。

前后端进阶版飞机大战

项目概述

本次升级版本在保留了原有炫酷游戏玩法的基础上,新增了用户系统、排行榜、游戏记录等功能,让游戏体验更加完整和社交化。项目采用前后端分离架构,是一个非常适合学习全栈开发的示例项目。

技术栈

前端技术栈
  • HTML5 + CSS3
  • 原生JavaScript (ES6+)
  • Canvas游戏渲染
  • JWT前端认证
  • 响应式设计
后端技术栈
  • Spring Boot 2.x
  • Spring Security
  • JWT认证
  • MySQL数据库
  • Maven项目管理

新增功能模块

1. 用户系统
  • 用户注册登录
  • JWT token认证
  • 角色权限管理(普通用户/管理员)
  • 个人信息管理
2. 排行榜系统
  • 多维度排行(得分/击杀/收集/时长)
  • 难度分类(简单/普通/困难模式)
  • 实时更新
  • 分页展示
3. 游戏记录系统
  • 详细游戏数据记录
  • 个人游戏历史查询
  • 数据统计分析
  • 游戏进度追踪
4. 管理员功能
  • 用户管理
  • 数据监控
  • 系统维护

项目特点

  1. 完整的用户体验

    • 炫酷的游戏界面
    • 流畅的操作体验
    • 清晰的游戏反馈
  2. 安全性保障

    • JWT认证
    • 密码加密存储
    • 权限精细控制
  3. 数据统计分析

    • 个人游戏数据追踪
    • 排行榜实时更新
    • 游戏记录详细保存
  4. 优秀的代码结构

    • 模块化设计
    • 代码注释完善
    • 便于学习和二次开发

前端详细介绍

游戏核心功能

1. 游戏引擎设计

本项目使用原生Canvas API构建了一个轻量级的2D游戏引擎,主要包括以下核心组件:

  • Game类:游戏主控制器,负责游戏循环、状态管理和场景切换
  • Player类:玩家飞船控制,包括移动、射击和碰撞检测
  • Enemy类:敌人AI系统,支持多种敌人类型和行为模式
  • Bullet类:子弹系统,支持不同弹道和伤害效果
  • Item类:道具系统,提供多种游戏增益效果
  • Background类:动态星空背景,创造沉浸式太空体验

每个组件都采用面向对象设计,具有高内聚低耦合的特点,便于扩展和维护。

2. 视觉效果系统
  • 粒子系统:实现爆炸、引擎尾焰等特效
  • 动态光效:飞船引擎光效、武器发射光效
  • 视差背景:多层次星空背景,增强深度感
  • 屏幕震动:爆炸和碰撞时的震动效果
  • 动画过渡:平滑的游戏状态过渡动画
3. 音频系统
  • AudioManager类:统一管理游戏音效和背景音乐
  • 动态音效:根据游戏状态切换不同背景音乐
  • 空间音效:根据事件发生位置调整音量和平衡
  • 音频池:优化同时播放多个音效的性能

用户界面设计

1. 响应式布局
  • 自适应不同屏幕尺寸,从手机到桌面设备
  • 基于CSS Grid和Flexbox的灵活布局
  • 媒体查询优化不同设备的游戏体验
2. 主题设计
  • 深空科幻主题,暗色调背景配合霓虹色元素
  • 半透明玻璃态UI面板,现代感十足
  • 动态光效和渐变色,增强视觉冲击力
  • 像素风格与现代UI的融合,独特的视觉风格
3. 交互设计
  • 流畅的菜单导航系统
  • 动态反馈的按钮和控件
  • 直观的游戏控制方式
  • 清晰的游戏状态指示器

前后端交互

1. JWT认证流程
  • 登录/注册请求发送用户凭据
  • 服务器验证并返回JWT令牌
  • 前端存储令牌并在后续请求中使用
  • 令牌过期处理和自动登出机制
2. 游戏数据同步
  • 游戏结束时自动保存游戏记录
  • 异步提交游戏数据,不阻塞用户体验
  • 错误重试机制,确保数据不丢失
  • 本地缓存,应对网络不稳定情况
3. 排行榜实现
  • 分页加载排行数据,优化性能
  • 多维度排序和筛选
  • 实时更新机制
  • 高亮显示当前用户排名
排行榜核心代码实现

排行榜管理器设计采用了单例模式,集中处理排行榜相关的所有逻辑:

javascript 复制代码
// 排行榜管理器
const LeaderboardManager = {
    currentPage: 0,
    pageSize: 10,
    currentDifficulty: 'EASY',  // 默认简单模式
    currentType: 'score',       // 默认得分排行

    init() {
        // 初始化排行榜UI和事件监听
        this.addLeaderboardButton();
        this.setupEventListeners();
        
        // 设置难度选择器
        const difficultySelect = document.getElementById('difficultySelect');
        if (difficultySelect) {
            difficultySelect.innerHTML = `
                <option value="EASY">简单模式</option>
                <option value="NORMAL">普通模式</option>
                <option value="HELL">困难模式</option>
            `;
            difficultySelect.value = this.currentDifficulty;
        }
    },

    fetchLeaderboard() {
        // 构建API请求URL,包含分页、难度和类型参数
        const url = `${API_BASE_URL}/api/records/leaderboard?difficulty=${this.currentDifficulty}&type=${this.currentType}&page=${this.currentPage}&size=${this.pageSize}`;
        
        // 发送请求获取排行榜数据
        fetch(url)
            .then(response => response.json())
            .then(data => {
                this.renderLeaderboard(data);
                this.updatePagination(data);
            })
            .catch(error => console.error('获取排行榜失败:', error));
    }
}

排行榜渲染采用了模板化设计,支持不同类型数据的高亮显示:

javascript 复制代码
renderLeaderboard(data) {
    const tbody = document.getElementById('leaderboardList');
    tbody.innerHTML = '';
    
    if (data.content.length === 0) {
        tbody.innerHTML = '<tr><td colspan="7" class="no-data">暂无数据</td></tr>';
        return;
    }
    
    // 根据排行类型决定高亮显示的列
    const highlightColumn = this.getHighlightColumn();
    
    data.content.forEach((record, index) => {
        const row = document.createElement('tr');
        
        // 为前三名添加特殊样式
        if (index < 3) {
            row.classList.add(`rank-${index + 1}`);
        }
        
        // 检测是否为当前用户,添加高亮
        if (record.user.username === currentUser) {
            row.classList.add('current-user');
        }
        
        // 构建行数据
        row.innerHTML = `
            <td>${this.currentPage * this.pageSize + index + 1}</td>
            <td>${record.user.username}</td>
            <td class="${highlightColumn === 'score' ? 'highlight' : ''}">${record.score}</td>
            <td class="${highlightColumn === 'kills' ? 'highlight' : ''}">${record.enemiesKilled}</td>
            <td class="${highlightColumn === 'items' ? 'highlight' : ''}">${record.itemsCollected}</td>
            <td class="${highlightColumn === 'time' ? 'highlight' : ''}">${formatTime(record.playTime)}</td>
            <td>${formatDate(record.createdAt)}</td>
        `;
        
        tbody.appendChild(row);
    });
}

分页控件实现,支持首页、上一页、下一页、末页导航:

javascript 复制代码
updatePagination(data) {
    const paginationDiv = document.getElementById('leaderboardPagination');
    const totalPages = data.totalPages;
    
    paginationDiv.innerHTML = `
        <button class="page-btn" ${this.currentPage === 0 ? 'disabled' : ''} 
                onclick="LeaderboardManager.goToPage(0)">首页</button>
        <button class="page-btn" ${this.currentPage === 0 ? 'disabled' : ''} 
                onclick="LeaderboardManager.goToPage(${this.currentPage - 1})">上一页</button>
        <span class="page-info">第 ${this.currentPage + 1}/${totalPages} 页</span>
        <button class="page-btn" ${this.currentPage >= totalPages - 1 ? 'disabled' : ''} 
                onclick="LeaderboardManager.goToPage(${this.currentPage + 1})">下一页</button>
        <button class="page-btn" ${this.currentPage >= totalPages - 1 ? 'disabled' : ''} 
                onclick="LeaderboardManager.goToPage(${totalPages - 1})">末页</button>
    `;
}

难度和排行类型切换的实现:

javascript 复制代码
setupEventListeners() {
    // 难度选择器事件监听
    const difficultySelect = document.getElementById('difficultySelect');
    if (difficultySelect) {
        difficultySelect.addEventListener('change', () => {
            this.currentDifficulty = difficultySelect.value;
            this.currentPage = 0;  // 切换难度时重置页码
            this.fetchLeaderboard();
        });
    }
    
    // 排行类型选择器事件监听
    const typeSelect = document.getElementById('typeSelect');
    if (typeSelect) {
        typeSelect.addEventListener('change', () => {
            this.currentType = typeSelect.value;
            this.currentPage = 0;  // 切换类型时重置页码
            this.fetchLeaderboard();
        });
    }
}

性能优化

1. 渲染优化
  • 使用requestAnimationFrame实现平滑动画
  • 对象池技术减少垃圾回收
  • 图层分离和缓存渲染
  • 视口裁剪,只渲染可见区域
2. 资源管理
  • 图像精灵表(Sprite Sheet)减少HTTP请求
  • 资源预加载和懒加载策略
  • 音频和图像压缩优化
  • 资源版本控制和缓存策略
3. 代码优化
  • 事件委托减少事件监听器数量
  • 防抖和节流处理密集型事件
  • Web Worker处理复杂计算
  • 模块化设计,按需加载

开发亮点

1. 模块化架构

游戏核心逻辑被拆分为多个独立模块:

  • game.js: 游戏主循环和状态管理
  • player.js: 玩家控制和属性
  • enemy.js: 敌人生成和AI
  • bullet.js: 子弹系统
  • item.js: 道具系统
  • background.js: 背景渲染
  • audioManager.js: 音频管理
  • main.js: 应用入口和UI控制
2. 自定义游戏引擎

不依赖第三方游戏引擎,从零构建了轻量级2D游戏引擎,包括:

  • 碰撞检测系统
  • 粒子系统
  • 对象池管理
  • 场景管理
  • 输入处理系统
3. 创新玩法设计
  • 多种武器系统和升级路径
  • 动态难度调整
  • 多样化的敌人类型和行为模式
  • Boss战特殊机制
  • 成就系统激励长期游戏

后端详细介绍

系统架构设计

1. 分层架构

后端采用经典的多层架构设计,确保代码的可维护性和可扩展性:

  • 控制层(Controller): 处理HTTP请求,参数验证和响应封装
  • 服务层(Service): 实现核心业务逻辑,事务管理
  • 数据访问层(Repository): 与数据库交互,实现数据持久化
  • 实体层(Entity): 映射数据库表结构
  • DTO层: 数据传输对象,优化前后端数据交互
  • 配置层(Config): 系统配置,如安全、缓存等
2. 安全架构

系统采用Spring Security + JWT的安全架构:

java 复制代码
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final JwtAuthenticationFilter jwtAuthFilter;
    private final UserDetailsService userDetailsService;
    private final PasswordEncoder passwordEncoder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()
            .antMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder);
    }
}
3. 缓存架构

系统使用Spring Cache实现多级缓存策略,提高查询性能:

不过本文为了能够减少外部服务依赖,并没有引入其他第三方缓存中间件。

直接存在JVM内存中

java 复制代码
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        List<Cache> caches = new ArrayList<>();
        caches.add(new ConcurrentMapCache("leaderboard"));
        caches.add(new ConcurrentMapCache("userRecords"));
        cacheManager.setCaches(caches);
        return cacheManager;
    }
}

核心功能实现

1. 用户认证与授权

用户认证流程采用JWT令牌机制,确保API安全:

java 复制代码
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {

    private final AuthService authService;

    @PostMapping("/register")
    public ResponseEntity<AuthResponse> register(@RequestBody RegisterRequest request) {
        return ResponseEntity.ok(authService.register(request));
    }

    @PostMapping("/login")
    public ResponseEntity<AuthResponse> login(@RequestBody LoginRequest request) {
        return ResponseEntity.ok(authService.login(request));
    }
}

JWT过滤器实现:

java 复制代码
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtService jwtService;
    private final UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain) throws ServletException, IOException {
        
        final String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }
        
        final String jwt = authHeader.substring(7);
        final String username = jwtService.extractUsername(jwt);
        
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            if (jwtService.isTokenValid(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}
2. 游戏记录管理

游戏记录服务实现了高效的数据存储和查询功能,并集成了缓存优化:

java 复制代码
@Service
@RequiredArgsConstructor
public class GameRecordService {
    
    private final GameRecordRepository gameRecordRepository;
    private final UserRepository userRepository;

    @CacheEvict(value = "leaderboard", allEntries = true)
    public GameRecord saveRecord(String username, GameRecordRequest request) {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found"));

        GameRecord record = convertToEntity(request, user);

        return gameRecordRepository.save(record);
    }

    @Cacheable(value = "leaderboard", key = "'leaderboard_' + #difficulty + '_' + #type + '_page_' + #page + '_size_' + #size")
    public Page<GameRecord> getLeaderboard(String difficulty, String type, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        
        switch (type.toLowerCase()) {
            case "score":
                return gameRecordRepository.findTopScoresByDifficulty(difficulty, pageable);
            case "kills":
                return gameRecordRepository.findTopKillsByDifficulty(difficulty, pageable);
            case "items":
                return gameRecordRepository.findTopItemsByDifficulty(difficulty, pageable);
            case "time":
                return gameRecordRepository.findTopPlayTimeByDifficulty(difficulty, pageable);
            case "escapes":
                return gameRecordRepository.findTopEscapesByDifficulty(difficulty, pageable);
            default:
                return gameRecordRepository.findTopScoresByDifficulty(difficulty, pageable);
        }
    }
}
3. 排行榜查询优化

排行榜查询使用了高效的SQL查询,通过窗口函数实现复杂的排名逻辑:

java 复制代码
@Repository
public interface GameRecordRepository extends JpaRepository<GameRecord, Long> {
    
    @Query(nativeQuery = true, value = 
        "WITH RankedScores AS ( " +
        "   SELECT *, " +
        "   ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY score DESC, id DESC) as rn " +
        "   FROM game_records " +
        "   WHERE difficulty = :difficulty " +
        ") " +
        "SELECT * FROM RankedScores WHERE rn = 1 ORDER BY score DESC")
    Page<GameRecord> findTopScoresByDifficulty(String difficulty, Pageable pageable);
    
    @Query(nativeQuery = true, value = 
        "WITH RankedKills AS ( " +
        "   SELECT *, " +
        "   ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY enemies_killed DESC, score DESC, id DESC) as rn " +
        "   FROM game_records " +
        "   WHERE difficulty = :difficulty " +
        ") " +
        "SELECT * FROM RankedKills WHERE rn = 1 ORDER BY enemies_killed DESC, score DESC")
    Page<GameRecord> findTopKillsByDifficulty(String difficulty, Pageable pageable);
}

性能优化技术

1. 数据库优化
  • 索引优化: 为频繁查询的字段添加索引
  • 分页查询: 避免大数据量全表扫描
  • 连接池配置: 优化数据库连接管理
  • SQL监控: 使用P6Spy实现SQL性能监控

P6Spy配置示例:

properties 复制代码
# 指定日志输出模块
modulelist=com.p6spy.engine.logging.P6LogFactory

# 自定义日志格式
logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat
customLogMessageFormat=执行SQL:%(sqlSingleLine) | 耗时:%(executionTime)ms

# 设置P6Spy输出到控制台
appender=com.p6spy.engine.spy.appender.StdoutLogger

# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准,单位秒
outagedetectioninterval=2
2. 缓存优化
  • 多级缓存: 实现本地缓存和分布式缓存
  • 缓存策略: 针对不同数据类型采用不同缓存策略
  • 缓存一致性: 通过@CacheEvict确保数据更新时缓存同步
3. API响应优化
  • 数据压缩: 启用GZIP压缩减少传输数据量
  • DTO优化: 按需返回数据,减少冗余字段
  • 异步处理: 非关键操作采用异步处理提高响应速度

安全性设计

1. 密码安全

使用BCrypt加密算法保护用户密码:

java 复制代码
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
2. API安全
  • CORS配置: 限制跨域请求来源
  • CSRF防护: 关键操作添加CSRF令牌
  • 请求限流: 防止暴力攻击和DoS攻击
3. 数据安全
  • 参数验证: 所有输入参数严格验证
  • SQL注入防护: 使用参数化查询
  • 敏感数据脱敏: 日志和响应中隐藏敏感信息

可扩展性设计

1. 模块化设计

系统按功能划分为多个独立模块,便于扩展:

  • 用户认证模块
  • 游戏记录模块
  • 排行榜模块
  • 管理员模块
2. 接口设计

采用RESTful API设计原则,便于集成和扩展:

  • 资源明确的URL设计
  • 合理使用HTTP方法
  • 统一的响应格式
  • 版本控制机制
3. 配置外部化

关键配置通过配置文件外部化,便于环境切换:

yaml 复制代码
spring:
  datasource:
    url: jdbc:p6spy:mysql://localhost:3306/aircraftwar?useSSL=false&serverTimezone=UTC
    username: root
    password: ******
  jpa:
    hibernate:
      ddl-auto: update

jwt:
  secret: 5367566B59703373367639792F423F4528482B4D6251655468576D5A71347437
  expiration: 86400000  # 24小时

部署说明

mysql版本需要8.0以上版本

前端需要安装好nodejs

  1. 前端部署(端口3000)
bash 复制代码
# 安装依赖
npm install
# 启动服务
npm start
  1. 后端部署(端口8880)
bash 复制代码
# 导入数据库脚本
source init.sql
# 修改数据库配置
vim application.yml
# 启动Spring Boot应用
mvn spring-boot:run

源码获取

https://download.csdn.net/download/Pte_moon/90491980?spm=1001.2014.3001.5503

致谢

再次感谢所有支持和关注本项目的朋友们!你们的支持是我持续更新的动力。也欢迎大家在评论区留言,分享你的想法和建议。让我们一起把这个项目做得更好!

结语

精心打造,只为分享。若这个全栈项目对你有所启发或帮助,请赐予一个赞👍与收藏⭐。每一次支持都是对创作者最好的鼓励,也是促使我不断优化迭代的关键动力。

也欢迎大家关注我,后续会持续分享更多有趣的项目!🌹🌹🌹

相关推荐
江沉晚呤时7 分钟前
深入解析 .NET 中的依赖项加载机制:原理、实现与最佳实践
前端·数据库·c#·.netcore
哟哟耶耶7 分钟前
knowledge-微前端(多个前端应用聚合的一个应用架构体系,每个小的应用可独立运行,独立开发,独立部署上线)
前端
Enjoy_zhuo9 分钟前
xss-labs第八、九关卡以及XSS GAME的Ok,Boomer关卡
前端·安全·xss
高锰酸钾_11 分钟前
Redis如何实现持久化
数据库·redis·缓存
运维自动化&云计算11 分钟前
使用Aspera高速上传文件到ncbi
数据库·ncbi上传·aspera
zyxzyx6661 小时前
Canal 解析与 Spring Boot 整合实战
java·spring boot·后端
hikktn1 小时前
【开源宝藏】30天学会CSS - DAY2 第二课 Loader Ring Demo
前端·css·开源
Studying_swz2 小时前
Spring WebFlux之流式输出
java·后端·spring
计算机学长felix3 小时前
基于SpringBoot的“酒店管理系统”的设计与实现(源码+数据库+文档+PPT)
spring boot·毕业设计
糖心何包蛋爱编程3 小时前
(二)Reactor核心-前置知识1
java·响应式编程·lambda表达式·干货分享