规格化 js 文件
This commit is contained in:
parent
0badc0f83d
commit
f1101db237
|
@ -17,19 +17,13 @@ export class AcGameObject {
|
|||
}
|
||||
|
||||
// start 函数只执行一次
|
||||
start(){
|
||||
|
||||
}
|
||||
start() {}
|
||||
|
||||
// 除第一帧之外,每一帧执行一遍
|
||||
update(){
|
||||
|
||||
}
|
||||
update() {}
|
||||
|
||||
// 删除之前执行
|
||||
on_destroy(){
|
||||
|
||||
}
|
||||
on_destroy() {}
|
||||
|
||||
// 删除
|
||||
destroy() {
|
||||
|
@ -46,11 +40,9 @@ export class AcGameObject {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 上一帧执行的时刻
|
||||
let last_timestamp;
|
||||
// step 函数需要传入当前帧执行的时刻 timestamp
|
||||
|
@ -75,9 +67,8 @@ const step = (timestamp) => {
|
|||
// 更新 last_timestamp ,作为下一次更新的“上一帧执行的时刻”
|
||||
last_timestamp = timestamp;
|
||||
// 递归调用
|
||||
requestAnimationFrame(step)
|
||||
|
||||
}
|
||||
requestAnimationFrame(step);
|
||||
};
|
||||
|
||||
// 定义需要的刷新次数,传入的函数step会在下一帧浏览器渲染之前执行一遍。
|
||||
requestAnimationFrame(step)
|
||||
requestAnimationFrame(step);
|
||||
|
|
|
@ -45,10 +45,12 @@ export class GameMap extends AcGameObject{
|
|||
g[sx][sy] = true;
|
||||
|
||||
// 定义四方向偏移量
|
||||
let dx = [-1, 0, 1, 0], dy = [0, 1, 0 ,-1];
|
||||
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];
|
||||
let x = sx + dx[i],
|
||||
y = sy + dy[i];
|
||||
// 判断是否撞墙,如果没有撞墙,且可以搜到终点的话,返回 true ,否则返回 false
|
||||
if (!g[x][y] == true && this.check_connectivity(g, x, y, tx, ty))
|
||||
return true;
|
||||
|
@ -115,7 +117,8 @@ export class GameMap extends AcGameObject{
|
|||
// 深度复制方法:先转换数据为 JSON ,再把 JSON 解析出来
|
||||
const copy_g = JSON.parse(JSON.stringify(g));
|
||||
// 检测到不连通,则直接在生成对象之前 return false 退出函数
|
||||
if(!this.check_connectivity(copy_g, this.rows-2, 1, 1, this.cols-2)) return false;
|
||||
if (!this.check_connectivity(copy_g, this.rows - 2, 1, 1, this.cols - 2))
|
||||
return false;
|
||||
|
||||
// 枚举数组,将 g[r][c] == true 的部分绘制出来
|
||||
// 如果上一步连通性检测失败,则退出 this.create_wall() 函数,本步骤不再执行生成新对象的操作
|
||||
|
@ -141,27 +144,24 @@ export class GameMap extends AcGameObject{
|
|||
const [snake0, snake1] = this.snakes;
|
||||
|
||||
// 获取用户信息:绑定 keydown 事件
|
||||
this.ctx.canvas.addEventListener("keydown", e => {
|
||||
this.ctx.canvas.addEventListener("keydown", (e) => {
|
||||
// 定义 snake0 的键盘绑定事件
|
||||
if (e.key === 'w') snake0.set_direction(0);
|
||||
else if (e.key === 'd') snake0.set_direction(1);
|
||||
else if (e.key === 's') snake0.set_direction(2);
|
||||
else if (e.key === 'a') snake0.set_direction(3);
|
||||
|
||||
if (e.key === "w") snake0.set_direction(0);
|
||||
else if (e.key === "d") snake0.set_direction(1);
|
||||
else if (e.key === "s") snake0.set_direction(2);
|
||||
else if (e.key === "a") snake0.set_direction(3);
|
||||
// 定义 snake1 的键盘绑定事件
|
||||
else if (e.key === 'ArrowUp') snake1.set_direction(0);
|
||||
else if (e.key === 'ArrowRight') snake1.set_direction(1);
|
||||
else if (e.key === 'ArrowDown') snake1.set_direction(2);
|
||||
else if (e.key === 'ArrowLeft') snake1.set_direction(3);
|
||||
else if (e.key === "ArrowUp") snake1.set_direction(0);
|
||||
else if (e.key === "ArrowRight") snake1.set_direction(1);
|
||||
else if (e.key === "ArrowDown") snake1.set_direction(2);
|
||||
else if (e.key === "ArrowLeft") snake1.set_direction(3);
|
||||
});
|
||||
}
|
||||
|
||||
start() {
|
||||
// 开始时调用一次创建墙的函数
|
||||
// 循环 1000 次,如果成功创建则 break ,否则继续循环创建
|
||||
for(let i = 0; i < 1000; i ++)
|
||||
if(this.create_wall())
|
||||
break;
|
||||
for (let i = 0; i < 1000; i++) if (this.create_wall()) break;
|
||||
|
||||
// 开始时启动监听方法
|
||||
this.add_listening_events();
|
||||
|
@ -170,7 +170,12 @@ export class GameMap extends AcGameObject{
|
|||
// 每一帧都更新一下小正方格的边长
|
||||
update_size() {
|
||||
// 计算当前帧每个格子的宽度, parseInt 取整是为了避免渲染出的格子之间出现小空隙
|
||||
this.L = parseInt(Math.min(this.parent.clientWidth / this.cols, this.parent.clientHeight / this.rows));
|
||||
this.L = parseInt(
|
||||
Math.min(
|
||||
this.parent.clientWidth / this.cols,
|
||||
this.parent.clientHeight / this.rows
|
||||
)
|
||||
);
|
||||
// 计算当前画布的宽度
|
||||
this.ctx.canvas.width = this.L * this.cols;
|
||||
// 计算当前画布的高度
|
||||
|
@ -201,8 +206,7 @@ export class GameMap extends AcGameObject{
|
|||
check_valid(cell) {
|
||||
// 碰墙检测
|
||||
for (const wall of this.walls) {
|
||||
if (wall.r === cell.r && wall.c === cell.c)
|
||||
return false;
|
||||
if (wall.r === cell.r && wall.c === cell.c) return false;
|
||||
}
|
||||
|
||||
// 蛇身碰撞检测
|
||||
|
@ -216,7 +220,7 @@ export class GameMap extends AcGameObject{
|
|||
// 判断蛇身现有结点是否碰撞
|
||||
for (let i = 0; i < k; i++) {
|
||||
if (snake.cells[i].r === cell.r && snake.cells[i].c === cell.c)
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,7 +245,8 @@ export class GameMap extends AcGameObject{
|
|||
// this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
|
||||
|
||||
// 定义偶数格even、奇数格odd的颜色
|
||||
const color_even = "#aad751", color_odd = "#a2d048";
|
||||
const color_even = "#aad751",
|
||||
color_odd = "#a2d048";
|
||||
|
||||
for (let r = 0; r < this.rows; r++) {
|
||||
for (let c = 0; c < this.cols; c++) {
|
||||
|
|
|
@ -16,7 +16,7 @@ export class Snake extends AcGameObject {
|
|||
|
||||
// 蛇初始只有一个点(蛇头),初始时只需要定义出蛇头即可。初始坐标为每条蛇的起始位置
|
||||
// cells[] 存放蛇的身体, cells[0] 存放蛇头
|
||||
this.cells = [new Cell(info.r, info.c)]
|
||||
this.cells = [new Cell(info.r, info.c)];
|
||||
this.next_cell = null; // 下一步的目标位置
|
||||
|
||||
this.speed = 5; // 蛇的速度:每秒走五个格子
|
||||
|
@ -57,12 +57,9 @@ export class Snake extends AcGameObject {
|
|||
[1, 1],
|
||||
[1, -1],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
start() {
|
||||
|
||||
}
|
||||
start() {}
|
||||
|
||||
// 定义方向设置接口
|
||||
set_direction(d) {
|
||||
|
@ -84,7 +81,10 @@ export class Snake extends AcGameObject {
|
|||
// 当前的蛇头方向
|
||||
const d = this.direction;
|
||||
// 下一节蛇身体的坐标计算
|
||||
this.next_cell = new Cell(this.cells[0].r + this.dr[d], this.cells[0].c + this.dc[d]);
|
||||
this.next_cell = new Cell(
|
||||
this.cells[0].r + this.dr[d],
|
||||
this.cells[0].c + this.dc[d]
|
||||
);
|
||||
|
||||
// 更新蛇眼睛的方向:就是下一步的蛇头方向
|
||||
this.eye_direction = d;
|
||||
|
@ -111,7 +111,6 @@ export class Snake extends AcGameObject {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
update_move() {
|
||||
// 计算目标方向 dx , dy : 使用目标点的坐标减去当前蛇头的坐标
|
||||
const dx = this.next_cell.x - this.cells[0].x;
|
||||
|
@ -137,9 +136,9 @@ export class Snake extends AcGameObject {
|
|||
// 不重合表示尚未移动到下一步,还可以继续移动
|
||||
else {
|
||||
// 按时间(second)定义移动距离: 每一帧走过的距离 = 速度 * 两帧时间间隔 / 1000(ms)
|
||||
const move_distance = this.speed * this.timedelta / 1000; // 处以 1000 ,将毫秒单位转换成秒单位
|
||||
this.cells[0].x += move_distance * dx / distance;
|
||||
this.cells[0].y += move_distance * dy / distance;
|
||||
const move_distance = (this.speed * this.timedelta) / 1000; // 处以 1000 ,将毫秒单位转换成秒单位
|
||||
this.cells[0].x += (move_distance * dx) / distance;
|
||||
this.cells[0].y += (move_distance * dy) / distance;
|
||||
|
||||
// 更新蛇尾位置
|
||||
if (!this.check_tail_increasing()) {
|
||||
|
@ -155,8 +154,8 @@ export class Snake extends AcGameObject {
|
|||
const tail_dy = tail_target.y - tail.y;
|
||||
|
||||
// 移动蛇尾
|
||||
tail.x += move_distance * tail_dx / distance;
|
||||
tail.y += move_distance * tail_dy / distance;
|
||||
tail.x += (move_distance * tail_dx) / distance;
|
||||
tail.y += (move_distance * tail_dy) / distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +199,8 @@ export class Snake extends AcGameObject {
|
|||
|
||||
// 使得蛇身体丰满一点
|
||||
for (let i = 1; i < this.cells.length; i++) {
|
||||
const a = this.cells[i - 1], b = this.cells[i];
|
||||
const a = this.cells[i - 1],
|
||||
b = this.cells[i];
|
||||
// 当两个目标点重合时,不用在绘制矩形填充
|
||||
if (Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps)
|
||||
continue;
|
||||
|
@ -209,11 +209,21 @@ export class Snake extends AcGameObject {
|
|||
const snake_node_width = 0.7;
|
||||
// 如果两个目标点在竖方向重合(横坐标一致,纵坐标不重合)时的画法
|
||||
if (Math.abs(a.x - b.x) < this.eps) {
|
||||
ctx.fillRect((a.x - snake_node_width / 2) * L, Math.min(a.y, b.y) * L, L * snake_node_width, Math.abs(a.y - b.y) * L);
|
||||
ctx.fillRect(
|
||||
(a.x - snake_node_width / 2) * L,
|
||||
Math.min(a.y, b.y) * L,
|
||||
L * snake_node_width,
|
||||
Math.abs(a.y - b.y) * L
|
||||
);
|
||||
}
|
||||
// 横方向的画法
|
||||
else {
|
||||
ctx.fillRect(Math.min(a.x, b.x) * L, (a.y - snake_node_width / 2) * L, Math.abs(a.x - b.x) * L, L * snake_node_width);
|
||||
ctx.fillRect(
|
||||
Math.min(a.x, b.x) * L,
|
||||
(a.y - snake_node_width / 2) * L,
|
||||
Math.abs(a.x - b.x) * L,
|
||||
L * snake_node_width
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,10 +235,12 @@ export class Snake extends AcGameObject {
|
|||
// 画眼睛
|
||||
for (let i = 0; i < 2; i++) {
|
||||
// 眼睛的横纵坐标(乘以 L 是绝对距离)
|
||||
const eye_x = (this.cells[0].x + this.eye_dx[this.eye_direction][i] * 0.15) * L;
|
||||
const eye_y = (this.cells[0].y + this.eye_dy[this.eye_direction][i] * 0.15) * L;
|
||||
const eye_x =
|
||||
(this.cells[0].x + this.eye_dx[this.eye_direction][i] * 0.15) * L;
|
||||
const eye_y =
|
||||
(this.cells[0].y + this.eye_dy[this.eye_direction][i] * 0.15) * L;
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.beginPath();
|
||||
ctx.arc(eye_x, eye_y, snake_eye_size, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,5 @@ export class Wall extends AcGameObject {
|
|||
this.ctx.fillStyle = this.color;
|
||||
// 绘制矩形
|
||||
this.ctx.fillRect(this.c * L, this.r * L, L, L);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,67 +1,105 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
// 导入所有 view 页面
|
||||
import PkIndexView from '../views/pk/PkIndexView.vue'
|
||||
import RanklistIndexView from '../views/ranklist/RanklistIndexView.vue'
|
||||
import RecordIndexView from '../views/record/RecordIndexView.vue'
|
||||
import UserBotIndexView from '../views/user/bot/UserBotIndexView.vue'
|
||||
import NotFound from '../views/error/NotFound.vue'
|
||||
import UserAccountLoginView from '@/views/user/account/UserAccountLoginView.vue'
|
||||
import UserAccountRegisterView from '@/views/user/account/UserAccountRegisterView.vue'
|
||||
|
||||
import PkIndexView from "../views/pk/PkIndexView.vue";
|
||||
import RanklistIndexView from "../views/ranklist/RanklistIndexView.vue";
|
||||
import RecordIndexView from "../views/record/RecordIndexView.vue";
|
||||
import UserBotIndexView from "../views/user/bot/UserBotIndexView.vue";
|
||||
import NotFound from "../views/error/NotFound.vue";
|
||||
import UserAccountLoginView from "@/views/user/account/UserAccountLoginView.vue";
|
||||
import UserAccountRegisterView from "@/views/user/account/UserAccountRegisterView.vue";
|
||||
// 读入 store 信息
|
||||
import store from "../store/index";
|
||||
|
||||
// 定义所有页面的 URL 路由
|
||||
const routes = [
|
||||
{
|
||||
path:'/',
|
||||
name:'home',
|
||||
path: "/",
|
||||
name: "home",
|
||||
// 重定向:将 home 重定向到 pk 页面
|
||||
redirect:'/pk/'
|
||||
redirect: "/pk/",
|
||||
// meta 存其他信息
|
||||
meta: {
|
||||
// 页面是否需要授权
|
||||
requestAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path:'/pk/',
|
||||
name:'pk_index',
|
||||
component:PkIndexView
|
||||
path: "/pk/",
|
||||
name: "pk_index",
|
||||
component: PkIndexView,
|
||||
meta: {
|
||||
requestAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path:'/ranklist/',
|
||||
name:'ranklist_index',
|
||||
component:RanklistIndexView
|
||||
path: "/ranklist/",
|
||||
name: "ranklist_index",
|
||||
component: RanklistIndexView,
|
||||
meta: {
|
||||
requestAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path:'/record/',
|
||||
name:'record_index',
|
||||
component:RecordIndexView
|
||||
path: "/record/",
|
||||
name: "record_index",
|
||||
component: RecordIndexView,
|
||||
meta: {
|
||||
requestAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path:'/user/bot/',
|
||||
name:'user_bot_index',
|
||||
component:UserBotIndexView
|
||||
path: "/user/bot/",
|
||||
name: "user_bot_index",
|
||||
component: UserBotIndexView,
|
||||
meta: {
|
||||
requestAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path:'/user/account/login/',
|
||||
name:'user_account_login',
|
||||
component:UserAccountLoginView
|
||||
path: "/user/account/login/",
|
||||
name: "user_account_login",
|
||||
component: UserAccountLoginView,
|
||||
meta: {
|
||||
requestAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path:'/user/account/register/',
|
||||
name:'user_account_register',
|
||||
component:UserAccountRegisterView
|
||||
path: "/user/account/register/",
|
||||
name: "user_account_register",
|
||||
component: UserAccountRegisterView,
|
||||
meta: {
|
||||
requestAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path:'/404/',
|
||||
name:'404',
|
||||
component:NotFound
|
||||
path: "/404/",
|
||||
name: "404",
|
||||
component: NotFound,
|
||||
meta: {
|
||||
requestAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
// 正则匹配所有其他非法页面到 404
|
||||
path:'/:catchAll(.*)',
|
||||
redirect:'/404/'
|
||||
}
|
||||
]
|
||||
path: "/:catchAll(.*)",
|
||||
redirect: "/404/",
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
routes,
|
||||
});
|
||||
|
||||
export default router
|
||||
// to 表示从那个页面跳转, from 表示从哪个页面跳转出去, next 表示页面要不要执行下一步操作
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 如果页面需要授权而且未登录,则跳转到用户登录页面
|
||||
if (to.meta.requestAuth && !store.state.user.is_login) {
|
||||
next({ name: "user_account_login" });
|
||||
} else {
|
||||
// next() 跳转到默认页面
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
import { createStore } from 'vuex'
|
||||
import ModuleUser from './user'
|
||||
import { createStore } from "vuex";
|
||||
import ModuleUser from "./user";
|
||||
|
||||
export default createStore({
|
||||
state: {
|
||||
},
|
||||
getters: {
|
||||
},
|
||||
mutations: {
|
||||
},
|
||||
actions: {
|
||||
},
|
||||
state: {},
|
||||
getters: {},
|
||||
mutations: {},
|
||||
actions: {},
|
||||
modules: {
|
||||
user: ModuleUser,
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import $ from 'jquery'
|
||||
import $ from "jquery";
|
||||
|
||||
export default {
|
||||
state: {
|
||||
|
@ -8,9 +8,7 @@ export default {
|
|||
token: "",
|
||||
is_login: false,
|
||||
},
|
||||
getters: {
|
||||
|
||||
},
|
||||
getters: {},
|
||||
// 同步事件
|
||||
mutations: {
|
||||
// 更新用户信息
|
||||
|
@ -31,7 +29,7 @@ export default {
|
|||
state.photo = "";
|
||||
state.token = "";
|
||||
state.is_login = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
// 异步事件
|
||||
actions: {
|
||||
|
@ -56,7 +54,6 @@ export default {
|
|||
} else {
|
||||
data.error(resp);
|
||||
}
|
||||
|
||||
},
|
||||
error(resp) {
|
||||
data.error(resp);
|
||||
|
@ -69,8 +66,7 @@ export default {
|
|||
url: "http://localhost:3000/user/account/info/",
|
||||
type: "GET",
|
||||
headers: {
|
||||
Authorization:
|
||||
"Bearer " + context.state.token,
|
||||
Authorization: "Bearer " + context.state.token,
|
||||
},
|
||||
success(resp) {
|
||||
if (resp.error_message === "success") {
|
||||
|
@ -91,10 +87,7 @@ export default {
|
|||
},
|
||||
logout(context) {
|
||||
context.commit("logout");
|
||||
}
|
||||
|
||||
},
|
||||
modules: {
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
modules: {},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue