3.1 创建菜单与游戏界面(上)
发表于|更新于
|阅读量:
编写NavBar.vue
导入bootstrap
的css
js
文件
1 2
| import "bootstrap/dist/css/bootstrap.min.css" import "bootstrap/dist/js/bootstrap"
|
提示缺少@popperjs/core
就去安装对应依赖
NavBar.vue
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
| <template> <nav class="navbar navbar-expand-lg bg-body-tertiary"> <div class="container"> <a class="navbar-brand">King of Bots</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarText"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <a class="nav-link">对战</a> </li> <li class="nav-item"> <a class="nav-link">对局列表</a> </li> <li class="nav-item"> <a class="nav-link">排行榜</a> </li> </ul> <ul class="navbar-nav"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"> yanxuecan </a> <ul class="dropdown-menu"> <li><a class="dropdown-item" href="#">My Bot</a></li> <li> <hr class="dropdown-divider"> </li> <li><a class="dropdown-item" href="#">Log Out</a></li> </ul> </li> </ul> </div> </div> </nav> </template>
<script> export default { name: "NavBar", setup() {
} } </script>
<style scoped></style>
|
编写router/index.js
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
| import { createRouter, createWebHistory } from 'vue-router' import PkIndexView from '../views/pk/PkIndexView' import RankListIndexView from '../views/ranklist/RankListIndexView' import RecordIndexView from '../views/record/RecordIndexView' import UserBotIndexView from '../views/user/bot/UserBotIndexView' import NotFoundView from '../views/error/NotFoundView'
const routes = [ { path: '/', name: 'home', redirect: "/pk/", }, { path: '/pk/', name: 'pk_index', component: PkIndexView, }, { path: '/ranklist/', name: 'ranklist_index', component: RankListIndexView, }, { path: '/record/', name: 'record_index', component: RecordIndexView, }, { path: '/user/bot/', name: 'user_bot_index', component: UserBotIndexView, }, { path: '/404/', name: '404', component: NotFoundView, }, { path: "/:catchAll(.*)", redirect: "/404/" } ]
const router = createRouter({ history: createWebHistory(), routes })
export default router
|
修改导航栏中的a标签
- 将a标签改成
router-link
- 添加
:to="{name: 'home'}"
使得能够跳转在不刷新页面的情况下
编写ContentField.vue
公共组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div class="container"> <div class="card"> <div class="card-body"> <slot></slot> </div> </div> </div> </template>
<script> export default { name: "ContentField", } </script>
<style scoped> .card { margin-top: 20px; } </style>
|
在其他的views
中修改
其中一个示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <ContentField> 对战 </ContentField> </template>
<script> import ContentField from '../../components/ContentField'
export default { components: { ContentField, } } </script>
<style scoped>
</style>
|
实时聚焦
两个api
在标签中的class改为
1
| :class="route_name == 'pk_index' ? 'nav-link active' : 'nav-link'"
|
造游戏轮子AcGameObjects
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
| const AC_GAME_OBJECTS = [];
export class AcGameObjects { constructor() { AC_GAME_OBJECTS.push(this); this.timedelta = 0; this.has_called_start = false; }
start() {
}
update() {
}
on_destroy() {
}
destroy() { this.on_destroy();
for (i in AC_GAME_OBJECTS) { const obj = AC_GAME_OBJECTS[i]; if (this === obj) { AC_GAME_OBJECTS.splice(i); break; } } } }
let last_timestamp; const step = (timestamp) => { for (obj of AC_GAME_OBJECTS) { if (!obj.has_called_start) { obj.has_called_start = true; obj.start(); } else { obj.timedelta = timestamp - last_timestamp; obj.update(); } }
last_timestamp = timestamp; requestAnimationFrame(step); }
requestAnimationFrame();
|
1:08:00
编写GameMap.js
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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
| import { AcGameObjects } from "./AcGameObjects" import { Wall } from "./Wall";
export class GameMap extends AcGameObjects { constructor(ctx, parent) { super();
this.ctx = ctx; this.parent = parent; this.L = 0;
this.rows = 13; this.cols = 13;
this.walls = []; this.inner_walls_count = 20; }
check_conectivity(g, sx, sy, ex, ey) { if (sx == ex && sy == ey) return true;
g[sx][sy] = true;
let dx = [1, 0, -1, 0]; let dy = [0, 1, 0, -1];
for (let i = 0; i < 4; i++) { let x = dx[i] + sx, y = dy[i] + sy; if (!g[x][y] && this.check_conectivity(g, x, y, ex, ey)) { return true; } }
return false; }
create_walls() { let 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 / 2; i++) { for (let j = 0; j < 1000; j++) { let r = parseInt(Math.random() * this.rows); let c = parseInt(Math.random() * this.cols); if (g[r][c]) { continue; } if (r == 1 && c == this.cols - 2 || r == this.rows - 2 && c == 1) { continue; } g[r][c] = g[c][r] = true; break; } }
const copy_g = JSON.parse(JSON.stringify(g)); if (!this.check_conectivity(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]) { this.walls.push(new Wall(r, c, this)); } } }
return true; }
start() { for (let i = 0; i < 100; i++) { if (this.create_walls()) break; } }
update_size() { 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; }
update() { this.update_size(); this.render(); }
render() { let color_even = "#AAD781", color_odd = "#A2D149"; for (let r = 0; r < this.rows; r++) { for (let c = 0; c < this.cols; c++) { if ((c + r) % 2 == 0) { this.ctx.fillStyle = color_even; } else { this.ctx.fillStyle = color_odd; }
this.ctx.fillRect(c * this.L, r * this.L, this.L, this.L); } } } }
|
1:31:00
编写Wall.js
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
| import { AcGameObjects } from "./AcGameObjects";
export class Wall extends AcGameObjects { constructor(r, c, gamemap) { super();
this.r = r; this.c = c; this.color = "#b37226"; this.gamemap = gamemap; }
start() {
}
update() { 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); } }
|
提交代码
略