SpringBoot项目——创建菜单与游戏页面

发布于:2022-08-02 ⋅ 阅读:(384) ⋅ 点赞:(0)

SpringBoot项目——vue 实现游戏页面

回顾:

SpringBoot项目——配置git环境与项目创建


vue 实现前端页面——Web

1、导航栏功能+PK地图的实现

在这里插入图片描述
在这里插入图片描述

  • 导航栏组件及所路由跳转各组件代码如下:
// NavBar.vue
<template>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <router-link class="navbar-brand" :to="{name: 'home'}">King of Bots</router-link>
            <div class="collapse navbar-collapse" id="navbarText">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <!-- 加冒号使得属性可以赋值为一个表达式,实现点击active -->
                        <router-link :class="route_name == 'pk_index' ? 'nav-link active' : 'nav-link'" :to="{name: 'pk_index'}">对战</router-link>
                    </li>
                    <li class="nav-item">
                        <router-link :class="route_name == 'record_index' ? 'nav-link active' : 'nav-link'" :to="{name: 'record_index'}">对局列表</router-link>
                    </li>
                    <li class="nav-item">
                        <router-link :class="route_name == 'ranklist_index' ? 'nav-link active' : 'nav-link'" :to="{name: 'ranklist_index'}">排行榜</router-link>
                    </li>
                </ul>
                <ul class="navbar-nav">
                    <li class="nav-item dropdown">
                        <a class="nav-link dropdown-toggle active" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                            Lijiao
                        </a>
                        <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
                            <li><router-link class="dropdown-item" :to="{name: 'user_bot_index'}">我的Bot</router-link></li>
                            <li><a class="dropdown-item" href="#">退出</a></li>
                            <li><hr class="dropdown-divider"></li>
                            <li><a class="dropdown-item" href="#">Something else here</a></li>
                        </ul>
                    </li>
                </ul>
            </div>
        </div>
    </nav>

</template>

<script>
// 为了判断当前url在哪个页面
import { useRoute } from 'vue-router'
import { computed } from 'vue'

export default {
    name: 'NavBar',
    setup() {
        const route = useRoute();
        let route_name = computed(() => route.name);

        return{
            route_name,
        }
    },
}
</script>

<style scoped>
</style>

路由跳转到的组件PKIndexViewRecordIndexViewRanklistIndexViewUserBotIndexViewNotFound

// PKIndexView.vue
<template>
    <PKPlayGround/>
</template>

<script>
import PKPlayGround from '@/components/PKPlayGround.vue'

export default {
    name: 'PKIndexView',
    components: {
        PKPlayGround,
    },
    setup() {
        
    },
}
</script>

<style scoped>

</style>

路由操作:

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import PKIndexView from '../views/pk/PKIndexView.vue'
import RecordIndexView from '@/views/record/RecordIndexView'
import RanklistIndexView from '@/views/ranklist/RanklistIndexView'
import UserBotIndexView from '@/views/user/bot/UserBotIndexView'
import NotFound from '@/views/error/NotFound'

const routes = [  
  {
    path: "/",
    name: "home",
    redirect: "/pk/",
  },
  {
    path: "/pk/",
    name: "pk_index",
    component: PKIndexView,
  },
  {
    path: "/record/",
    name: "record_index",
    component: RecordIndexView,
  },
  {
    path: "/ranklist/",
    name: "ranklist_index",
    component: RanklistIndexView,
  },
  {
    path: "/user/bot/",
    name: "user_bot_index",
    component: UserBotIndexView,
  },
  {
    path: "/404/",
    name: "404",
    component: NotFound,
  },
  {
    path: "/:catchAll(.*)",
    name: "404",
    component: NotFound,
  },
  
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router
2、js 控制 html、css 实现 PK 地图
  • AcGameObject.js 作为总父类 js 控制 每秒60次 执行GameMap.jsWall.js 的 updata;

    注意:只要new了某个js类,就会执行其所在的整个js文件

  • js 控制GameMap.vue组件中地图canvas随PKPlayGround动态改变大小;

  • js 控制GameMap.vue组件中墙canvas的构建。

GameMap 组件代码

// GameMap.vue
<template>
    <div ref="parent" class="gamemap">
        <canvas ref="canvas">
        </canvas>
    </div>   
</template>

<script>
// 引入自己写的 js
import {GameMap} from "@/assets/scripts/GameMap.js"
import {ref} from 'vue'
// 组件挂载完以后需要执行的操作
import {onMounted} from 'vue'

export default {
    setup:() => {
        let parent = ref(null);
        let canvas = ref(null);

        // 组件挂载完以后需要执行的操作:这里是js控制canvas
        onMounted(() => {
            // 通过 js 控制 html 显示
            // 传入画布和父组件的值
            // getContext('2d') 获取这个元素的 context,由 CanvasRenderingContext2D 接口完成实际的绘制。
            // 用 js 求出动态长方形 PKPlayGround(w * L)的 最大网格(row*col)正方形,可求内部小正方形的边长
            new GameMap(canvas.value.getContext('2d'),parent.value);

        });

        return {
            parent,
            canvas
        }
    }
}
</script>

<style scoped>
div.gamemap{
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
}
</style>

GameMap.js

// GameMap.js
import { AcGameObject } from "./AcGameObject";
import { Wall } from "./Wall";

export class GameMap extends AcGameObject {
    // 构造函数传入画布和画布的父元素
    constructor(ctx, parent) {
        super();
        this.ctx = ctx;
        this.parent = parent;

        // 存画布格子的绝对距离
        this.L = 0;
        this.rows = 13;
        this.cols = 13;

        // 存内部障碍物数量
        this.inner_walls_count = 15;
        // 画墙
        this.walls = [];
    }
	
	// 检查左下和右上是否联通
    check_connectivity(g, sx, sy, ex, ey){
        if (sx == ex && sy == ey) return true;
        g[sx][sy] = true;

        // 上下左右四个方向
        let dx = [-1, 0, 1, 0], dy = [0, 1, 0, -1];
        for (let i = 0; i < 4; i++){
            let x = sx + dx[i], y = sy + dy[i];
            if (!g[x][y] && this.check_connectivity(g, x, y, ex, ey)) return true;
            
        }
        return false;
    }

    create_walls() {
        const g = [];
        for (let r = 0;r < this.rows; r++ ) {
            g[r] = [];
            for ( let c = 0; c < this.cols; c++) {
                g[r][c] = false;
            }
        }

        // 给四周加墙
        for (let r = 0; r < this.rows; r++) {
            // 左右两边加墙
            g[r][0] = g[r][this.cols - 1] = true;
        }
        for (let c = 0; c < this.cols; c++) {
            // 上下两边加墙
            g[0][c] = g[this.rows-1][c] = true;
        }

        // 创建随机障碍物
        for (let i = 0; i < this.inner_walls_count; i++){
            for (let j = 0; j<1000 ; j++){
                // js 如何产生随机数
                // Math.random: 产生[0,1)之间随机浮点数
                // 即产生0-行数之间的随机浮点值后取整。
                let r = parseInt(Math.random() * this.rows);
                let c = parseInt(Math.random() * this.cols);
                if (g[r][c] || g[c][r] ) continue;
                if (c == 1 && r == this.rows-2 || c == this.cols-2 && r == 1) continue;
                g[r][c] = g[c][r] = true;
                break;
            }
        }

        // js 实现深度复制一个对象
        // 先转化成JSON, 再把JSON解析出来
        const copy_g =JSON.parse(JSON.stringify(g));
        if (!this.check_connectivity(copy_g, this.rows - 2, 1, 1, this.cols - 2)) return false;


        // 真正加
        for (let r = 0; r < this.rows; r++) {
            for (let c = 0; c < this.cols; c++) {
                if (g[r][c] == true) { 
                    new Wall(r, c, this);
                }
            }
        }

        // 如果联通,返回true
        return true;
    }

    start() {
        for (let i = 0; i < 1000; i++){
            if (this.create_walls()){
                break;
            }
        }
    }

    updata_size() {
        // 用 js 求出动态长方形 PKPlayGround(w * L)的 最大网格(row*col)正方形,可求内部小正方形的边长
        // clientWidth/clientHeight:  API,求div的长宽
        // why parseInt()? 这里算得为浮点型,而canvas渲染为整型,渲染会有空隙
        this.L = parseInt(Math.min(this.parent.clientWidth / this.cols, this.parent.clientHeight / this.rows));
        this.ctx.canvas.width = this.L * this.cols;
        this.ctx.canvas.height = this.L * this.rows;
    }

    updata() {
        // 每帧都更新下边长
        this.updata_size();
        this.render();
    }

    render() {

        // 画基数偶数格颜色分离
        // #424242
        // fillStyle 属性赋值颜色。fillRect(坐标,宽,高)
        const color_even = "#D8D8D8", color_odd = "#E7E7E7";
        for (let r = 0; r < this.rows; r ++) {
            for ( let c = 0; c < this.cols; c ++) {
                if ((r+c) % 2 == 0) {
                    this.ctx.fillStyle = color_odd;
                } else {
                    this.ctx.fillStyle = color_even;
                }
                // canvas 往右是x正方向,往下是y正方向
                // 因此第 r 行 c 列坐标是(c,r)
                this.ctx.fillRect(c * this.L, r * this.L, this.L, this.L);
            }
        }
    }
}

Wall.js

import { AcGameObject } from "./AcGameObject";

export class Wall extends AcGameObject {
    // r,c 为画墙的起始坐标,gamemap 为canvas画布
    constructor(r, c, gamemap) {
        super();
        this.r = r;
        this.c = c;
        this.gamemap = gamemap;
        this.color = "#424242"
    }

    updata() {
        this.render();
    }

    render() {
        const L = this.gamemap.L;
        const ctx = this.gamemap.ctx;

        ctx.fillStyle = this.color;
        // 
        ctx.fillRect(this.c * L,this.r * L, L, L);
    }
}
3、js 控制 html、css 实现蛇各项操作

网站公告

今日签到

点亮在社区的每一天
去签到