水果贪吃蛇web端和acapp端

master
barney 2 years ago
commit 330aedd28a
  1. 23
      acapp_snake/.gitignore
  2. 24
      acapp_snake/README.md
  3. 5
      acapp_snake/babel.config.js
  4. 19
      acapp_snake/jsconfig.json
  5. 19345
      acapp_snake/package-lock.json
  6. 46
      acapp_snake/package.json
  7. BIN
      acapp_snake/public/favicon.ico
  8. 17
      acapp_snake/public/index.html
  9. 21
      acapp_snake/src/App.vue
  10. 47
      acapp_snake/src/assets/scripts/AcGameObject.js
  11. 8
      acapp_snake/src/assets/scripts/Cell.js
  12. 171
      acapp_snake/src/assets/scripts/GameMap.js
  13. 290
      acapp_snake/src/assets/scripts/Snake.js
  14. 40
      acapp_snake/src/assets/scripts/init.js
  15. 117
      acapp_snake/src/components/GameMap.vue
  16. 30
      acapp_snake/src/components/PlayGround.vue
  17. 104
      acapp_snake/src/components/RankList.vue
  18. 125
      acapp_snake/src/components/ScoreBoard.vue
  19. BIN
      acapp_snake/src/components/static/apple.m4a
  20. BIN
      acapp_snake/src/components/static/apple_1.png
  21. BIN
      acapp_snake/src/components/static/apple_2.png
  22. BIN
      acapp_snake/src/components/static/apple_3.png
  23. BIN
      acapp_snake/src/components/static/closeMusic.png
  24. BIN
      acapp_snake/src/components/static/eat.mp3
  25. BIN
      acapp_snake/src/components/static/openMusic.png
  26. BIN
      acapp_snake/src/components/static/snake.mp3
  27. 5
      acapp_snake/src/main.js
  28. 63
      acapp_snake/src/store/index.js
  29. 10
      acapp_snake/vue.config.js
  30. 23
      web_snake/.gitignore
  31. 24
      web_snake/README.md
  32. 5
      web_snake/babel.config.js
  33. 19
      web_snake/jsconfig.json
  34. 19326
      web_snake/package-lock.json
  35. 46
      web_snake/package.json
  36. BIN
      web_snake/public/favicon.ico
  37. 19
      web_snake/public/index.html
  38. 23
      web_snake/src/App.vue
  39. 47
      web_snake/src/assets/scripts/AcGameObject.js
  40. 8
      web_snake/src/assets/scripts/Cell.js
  41. 130
      web_snake/src/assets/scripts/GameMap.js
  42. 187
      web_snake/src/assets/scripts/Snake.js
  43. 37
      web_snake/src/assets/scripts/init.js
  44. 82
      web_snake/src/components/GameMap.vue
  45. 32
      web_snake/src/components/PlayGround.vue
  46. 104
      web_snake/src/components/RankList.vue
  47. 65
      web_snake/src/components/ScoreBoard.vue
  48. 5
      web_snake/src/main.js
  49. 49
      web_snake/src/store/index.js
  50. 9
      web_snake/vue.config.js

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,24 @@
# acapp_snake
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,46 @@
{
"name": "acapp_snake",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.8.3",
"jquery": "^3.6.1",
"vue": "^3.2.13",
"vuex": "^4.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

@ -0,0 +1,21 @@
<template>
<PlayGround />
</template>
<script>
import PlayGround from '@/components/PlayGround'
export default {
name: 'App',
components: {
PlayGround,
}
}
</script>
<style scoped>
/* div.playground {
width: 80vw;
height: 80vh;
} */
</style>

@ -0,0 +1,47 @@
const AC_GAME_OBJECTS = [];
export class AcGameObject {
constructor() {
AC_GAME_OBJECTS.push(this);
this.timedelta = 0;
this.has_called_start = false;
}
start() {
}
update() {
}
on_destroy() {
}
destroy() {
this.on_destroy();
for (let i in AC_GAME_OBJECTS) {
const obj = AC_GAME_OBJECTS[i];
if (obj === this) {
AC_GAME_OBJECTS.splice(i, 1);
break;
}
}
}
}
let last_timestamp;
const step = timestamp => {
for (let obj of AC_GAME_OBJECTS) {
if (!obj.has_called_start) {
obj.start();
obj.has_called_start = true;
} else {
obj.timedelta = timestamp - last_timestamp;
obj.update();
}
}
last_timestamp = timestamp;
requestAnimationFrame(step);
};
requestAnimationFrame(step);

@ -0,0 +1,8 @@
export class Cell {
constructor(i, j) {
this.i = i;
this.j = j;
this.x = i + 0.5;
this.y = j + 0.5;
}
}

@ -0,0 +1,171 @@
import { AcGameObject } from "./AcGameObject";
import { Snake } from "./Snake";
import $ from 'jquery';
export class GameMap extends AcGameObject {
constructor(ctx, parent, store) {
super();
this.ctx = ctx;
this.parent = parent;
this.store = store;
this.L = 0;
this.snake = new Snake(this.ctx, this);
this.directions = [];
this.status = "waiting"; // waiting -> playing -> win/lose
}
start() {
this.ctx.canvas.focus();
this.ctx.canvas.addEventListener('keydown', e => {
if (this.store.state.restart) return false;
if (e.key === 'w' || e.key === 'ArrowUp') {
this.directions.push(0);
this.snake.eye_direction = 0;
e.preventDefault();
}
else if (e.key === 'd' || e.key == 'ArrowRight') {
this.directions.push(1);
this.snake.eye_direction = 1;
e.preventDefault();
}
else if (e.key === 's' || e.key === 'ArrowDown') {
this.directions.push(2);
this.snake.eye_direction = 2;
e.preventDefault();
}
else if (e.key === 'a' || e.key === 'ArrowLeft') {
this.directions.push(3);
this.snake.eye_direction = 3;
e.preventDefault();
}
else if (e.key === 'M' || e.key === 'm') {
if (this.store.state.music === true) {
this.store.state.music = false;
this.store.commit("updateMusic",false);
const audio = document.querySelector('#player')
audio.pause();
}else {
this.store.state.music = true;
this.store.commit("updateMusic",true);
const audio = document.querySelector('#player')
audio.currentTime = 0;
audio.play();
}
}
let k = this.directions.length;
if (k > 1 && this.directions[k - 1] === this.directions[k - 2]) {
this.directions.pop();
}
while (this.directions.length > 2)
this.directions.splice(0, 1);
if (this.status === "waiting" && this.directions.length && this.directions[0] !== 3) {
this.status = "playing";
this.snake.direction = this.directions[0];
}
});
}
update_size() {
this.L = Math.min(this.parent.clientWidth / 17, this.parent.clientHeight / 15);
this.ctx.canvas.width = this.L * 17;
this.ctx.canvas.height = this.L * 15;
}
update_score() {
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/update_score/",
type: "post",
data: {
score: this.store.state.score,
},
headers: {
'Authorization': "Bearer " + this.store.state.access,
},
})
}
win() {
this.snake.color = "white";
this.status = "win";
this.store.commit('updateRestart', true);
this.store.commit('updateNextStep',false);
this.store.commit('updateMusic',false);
this.store.state.audio.pause();
this.update_score();
}
lose() {
this.snake.color = "white";
this.status = "lose";
this.store.commit('updateRestart', true);
this.store.commit('updateNextStep',false);
this.store.commit("updateRecord",Math.max(this.store.state.score,this.store.state.record));
this.store.commit('updateMusic',false);
if (this.store.state.music === false) {
const audio = document.querySelector('#player')
audio.pause()
}
this.update_score();
}
restart() {
this.store.state.score = 0;
this.status = "waiting";
this.snake.destroy();
this.snake = new Snake(this.ctx, this);
this.store.commit('updateRestart', false);
this.store.commit('updateNextStep',false);
this.ctx.canvas.focus();
// console.log(this.store.state.music);
if (this.store.state.music === true) {
const audio = document.querySelector('#player')
audio.currentTime = 0;
audio.play()
this.store.commit('updateMusic',true);
}
}
upgrade() {
// this.status = "waiting";
// this.snake.destroy();
if (this.store.state.music === true) {
const audio = document.querySelector('#player')
audio.currentTime = 0;
audio.play()
}
this.snake = new Snake(this.ctx, this);
this.snake.color = this.store.state.color;
this.snake.speed = this.store.state.speed;
this.snake.number = this.store.state.number;
this.store.commit("updateRecord",Math.max(this.store.state.score,this.store.state.record));
}
update() {
this.update_size();
this.render();
}
render() {
let color_even = "#AAD751", color_odd = "#A2D149";
for (let i = 0; i < 17; i ++ ) {
for (let j = 0; j < 15; j ++ ) {
if ((i + j) % 2 == 0) {
this.ctx.fillStyle = color_even;
} else {
this.ctx.fillStyle = color_odd;
}
this.ctx.fillRect(i * this.L, j * this.L, this.L, this.L);
}
}
}
}

@ -0,0 +1,290 @@
import { AcGameObject } from './AcGameObject';
import { Cell } from './Cell';
export class Snake extends AcGameObject {
constructor(ctx, gamemap) {
super();
this.ctx = ctx;
this.gamemap = gamemap;
this.cells = [];
this.color = "#4876ec";
this.dirs = [
{x: 0, y: -1},
{x: 1, y: 0},
{x: 0, y: 1},
{x: -1, y: 0},
];
this.direction = 2;
this.eps = 1e-1;
this.speed = 5; // 每秒钟走几格
this.apple_cell = new Cell(-1, -1);
this.apple_img = new Image();
this.apple_img.src = "https://test.bnblogs.cc/acapp/images/apple/apple_00.png";
this.eating = false;
this.tail_cell = null;
this.number = 0;
this.head = null;
this.eye_direction = 1 // 初始的蛇眼睛朝右(0:上 1:右 2:下 3:左)
// 定义蛇左右眼的x和y坐标的偏移量
this.eyes_dx = [
[-1,1],
[1,1],
[-1,1],
[-1,-1]
];
this.eyes_dy = [
[-1,-1],
[-1,1],
[1,1],
[-1,1]
];
this.index = 0; // 当前的水果是哪个,来判断吃完之后的颜色
this.grades = 1; // 水果分值
}
start() {
this.cells.push(new Cell(4, 7));
for (let i = 4; i >= 1; i -- ) {
this.cells.push(new Cell(i, 7));
}
this.put_an_apple();
}
put_an_apple() {
const positions = new Set();
for (let i = 0; i < 17; i ++ ) {
for (let j = 0; j < 15; j ++ ) {
positions.add(`${i}-${j}`);
}
}
for (let cell of this.cells) {
positions.delete(`${cell.i}-${cell.j}`);
}
const items = Array.from(positions);
if (items.length === 0) this.gamemap.win();
else {
let [x, y] = items[Math.floor(Math.random() * items.length)].split('-');
x = parseInt(x), y = parseInt(y);
this.apple_cell = new Cell(x, y);
}
}
get_direction(a, b) {
if (Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps)
return -1;
if (Math.abs(a.x - b.x) < this.eps) {
if (b.y < a.y) return 0;
return 2;
}
if (b.x > a.x) return 1;
return 3;
}
check_die() {
const head = this.cells[0];
if (head.i < 0 || head.i >= 17 || head.j < 0 || head.j >= 15)
return true;
for (let i = 2; i < this.cells.length; i ++ ) {
if (head.i === this.cells[i].i && head.j === this.cells[i].j) {
return true;
}
}
return false;
}
update_body() {
const k = this.cells.length - 1;
const d = this.get_direction(this.cells[k], this.cells[k - 1]);
if (d >= 0) {
const distance = this.speed * this.timedelta / 1000;
this.cells[k].x += this.dirs[d].x * distance;
this.cells[k].y += this.dirs[d].y * distance;
this.cells[0].x += this.dirs[this.direction].x * distance;
this.cells[0].y += this.dirs[this.direction].y * distance;
} else {
const new_cells = [];
const headi = this.cells[1].i + this.dirs[this.direction].x;
const headj = this.cells[1].j + this.dirs[this.direction].y;
new_cells.push(new Cell(headi, headj));
new_cells.push(new Cell(headi, headj));
this.head = new Cell(headi,headj);
for (let i = 1; i < k; i ++ ) {
new_cells.push(this.cells[i]);
}
this.cells = new_cells;
if (this.eating) {
this.cells.push(this.tail_cell);
this.eating = false;
this.tail_cell = null;
}
const ds = this.gamemap.directions;
while (ds.length > 0 && (ds[0] === this.direction || ds[0] === (this.direction ^ 2)))
ds.splice(0, 1);
if (ds.length > 0) {
this.direction = ds[0];
ds.splice(0, 1);
}
if (this.check_die()) {
this.gamemap.lose();
}
if (headi === this.apple_cell.i && headj === this.apple_cell.j) {
if (this.gamemap.store.state.music === true) {
const audio = document.querySelector('#eat_apple');
audio.play();
audio.currentTime=0.4
audio.playbackRate = 3
}
this.eating = true;
if (this.index === 5) {
this.color = "#efefef";
this.grades = 5;
}
else if (this.index === 1) {
this.color = "#ffd201";
this.grades = 5;
}
else if (this.index === 17)
{
this.color = "#ff9999";
this.grades = 5;
}
else if (this.index === 7 || this.index === 0 || this.index === 8 || this.index === 12 || this.index === 20 || this.index === 19){
this.color= "#f2383b";
this.grades = 1;
}
else if (this.index === 11 || this.index === 13 || this.index === 14 || this.index === 15){
this.color= "#34b43d";
this.grades = 3;
}
else if (this.index === 3 || this.index === 6 || this.index === 10){
this.color = "#b445f1";
this.grades = 4;
}
else {
this.color = "#ea881c";
this.grades = 2;
}
const cell = this.cells[this.cells.length - 1];
this.tail_cell = new Cell(cell.i, cell.j);
this.put_an_apple();
// 换不同apple图片
const index_number = Math.round(this.randomNum(0,20));
this.index = index_number;
let src_head = "https://test.bnblogs.cc/acapp/images/apple/apple_0";
const src_tail = ".png";
if (index_number >= 0 && index_number <=9) {
this.apple_img.src = src_head + index_number + src_tail;
}else {
src_head = src_head.substring(0,src_head.length - 1);
this.apple_img.src = src_head + index_number + src_tail;
}
console.log(this.grades);
// console.log(this.apple_img.src,typeof this.apple_img.src);
const score = this.gamemap.store.state.score + this.grades;
this.gamemap.store.commit('updateScore', score);
this.gamemap.store.commit('updateRecord', Math.max(score,this.gamemap.store.state.record));
this.number++;
this.gamemap.store.commit('updateNumber',this.number);
if (this.number > 0 && this.number % 20 === 0) {
// 吃20个进入下一回合,依次奖励10-20-30
this.speed = this.speed + 1;
this.gamemap.store.commit("updateSpeed",this.speed);
this.gamemap.store.commit("updateScore",score + 10 * (parseInt(this.number / 20)));
this.gamemap.store.commit('updateRecord', Math.max(this.gamemap.store.state.score,this.gamemap.store.state.record));
this.gamemap.store.commit('updateColor',this.color);
this.gamemap.snake.destroy();
this.gamemap.store.commit('updateNextStep',true);
this.gamemap.status='waiting';
}
// console.log("num: ",this.number);
// console.log("speed: ",this.speed);
}
}
}
update() {
if (this.gamemap.status === "playing") {
this.update_body();
}
this.render();
}
randomNum (n,m) {
var result = Math.random()*(m+1-n)+n;
while(result>m) {
result = Math.random()*(m+1-n)+n;
}
return result;
}
render() {
const L = this.gamemap.L;
if (this.eating) {
this.cells.push(this.tail_cell);
}
this.ctx.drawImage(this.apple_img, this.apple_cell.i * L, this.apple_cell.j * L, L, L);
this.ctx.fillStyle = this.color;
for (let cell of this.cells) {
this.ctx.beginPath();
this.ctx.arc(cell.x * L, cell.y * L, L / 2 * 0.8, 0, Math.PI * 2);
this.ctx.fill();
}
for (let i = 1; i < this.cells.length; 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;
}
if (Math.abs(a.x - b.x) < this.eps) {
this.ctx.fillRect((a.x - 0.5 + 0.1) * L, Math.min(a.y, b.y) * L, L * 0.8, Math.abs(a.y - b.y) * L);
} else {
this.ctx.fillRect(Math.min(a.x, b.x) * L, (a.y - 0.5 + 0.1) * L, Math.abs(a.x - b.x) * L, L * 0.8);
}
}
if (this.eye_direction !== -1) {
// 画出蛇的眼睛
this.ctx.fillStyle = "black";
for (let i = 0; i < 2 ; i++) {
const eye_x = (this.cells[0].x + this.eyes_dx[this.eye_direction][i] * 0.2) * L;
const eye_y = (this.cells[0].y + this.eyes_dy[this.eye_direction][i] * 0.2) * L;
// 画眼睛
this.ctx.beginPath();
this.ctx.arc(eye_x,eye_y,L*0.05,0,Math.PI*2);
this.ctx.fill();
}
}
if (this.eating) {
this.cells.pop();
}
}
}

@ -0,0 +1,40 @@
import $ from 'jquery';
export const init = (store) => {
const AcWingOS = store.state.AcWingOS;
if (AcWingOS === "AcWingOS") return false;
const vw = window.innerWidth;
const vh = window.innerHeight;
AcWingOS.api.window.resize(59.5 * vh / vw, 64.5);
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/apply_code/",
type: "get",
success: resp => {
AcWingOS.api.oauth2.authorize(resp.appid, resp.redirect_uri, resp.scope, resp.state, resp => {
if (resp.result === "success") {
store.commit('updateAccess', resp.access);
store.commit('updateRefresh', resp.refresh);
setInterval(() => {
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/api/token/refresh/",
type: "post",
data: {
refresh: resp.refresh,
},
success: resp => {
store.commit('updateAccess', resp.access);
}
});
}, 4.5 * 60 * 1000);
}
else {
store.state.AcWingOS.api.window.close(); // 关闭acwing窗口
}
});
}
})
}

@ -0,0 +1,117 @@
<template>
<div class="gamemap" ref="div">
<canvas ref="canvas" tabindex="0"></canvas>
<div class="operation" v-if="$store.state.restart">
<button @click="restart" v-if="$store.state.access !== ''">开始游戏</button>
<button @click="show_ranklist" v-if="$store.state.access !== ''">排行榜</button>
<button v-else>您没有授权该应用</button>
</div>
<div class="operation" v-if="$store.state.upgrade">
<button @click="go_next_step">下一局</button>
<button @click="cancel">放弃</button>
</div>
<RankList v-if="$store.state.ranklist" />
</div>
</template>
<script>
import { ref, onMounted, onUpdated } from 'vue';
import { GameMap } from '@/assets/scripts/GameMap';
import { useStore } from 'vuex';
import { init } from '@/assets/scripts/init';
import RankList from './RankList';
import $ from 'jquery';
export default {
name: "GameMap",
components: {
RankList,
},
setup: () => {
let div = ref(null);
let canvas = ref(null);
const store = useStore();
let gamemap = null;
init(store);
onMounted(() => {
gamemap = new GameMap(canvas.value.getContext('2d'), div.value, store);
});
onUpdated(()=> {
//
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/get_user_score/",
type: "get",
headers: {
'Authorization': "Bearer " + store.state.access,
},
success: resp => {
store.commit("updateRecord",resp.me.score);
}
});
})
const restart = () => {
gamemap.restart();
}
const show_ranklist = () => {
store.commit('updateRanklist', true);
}
const go_next_step = () => {
gamemap.upgrade();
gamemap.ctx.canvas.focus();
store.commit('updateNextStep', false);
}
const cancel = () => {
store.commit('updateNextStep', false);
gamemap.lose();
}
return {
div,
canvas,
restart,
show_ranklist,
go_next_step,
cancel,
}
}
}
</script>
<style scoped>
div.gamemap {
height: calc(100% - 8vh);
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
canvas {
background-color: #AAD751;
}
div.operation {
position: absolute;
}
button {
background-color: #0d6efd;
border: solid 0;
border-radius: 5px;
font-size: 3vh;
color: white;
padding: 3vh;
cursor: pointer;
margin: 0 0.5vh;
}
</style>

@ -0,0 +1,30 @@
<template>
<div class="playground">
<ScoreBoard />
<GameMap />
</div>
</template>
<script>
import ScoreBoard from '@/components/ScoreBoard';
import GameMap from '@/components/GameMap';
export default {
name: "PlayGround",
components: {
ScoreBoard,
GameMap
}
}
</script>
<style scoped>
.playground {
width: 100%;
height: 100%;
background-color: #578A34;
}
</style>

@ -0,0 +1,104 @@
<template>
<div class="ranklist">
<span class="close-ranklist" @click="close_ranklist">x</span>
<div class="player" v-for="player in players" :key="player.id">
<div>#{{ player.rank }}</div>
<div>
<img :src="player.photo" alt="">
</div>
<div>{{ player.username }}</div>
<div>{{ player.score }}</div>
</div>
</div>
</template>
<script>
import { ref } from 'vue';
import $ from 'jquery';
import { useStore } from 'vuex';
export default {
name: 'RankList',
setup() {
const store = useStore();
let players = ref([]);
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/get_ranklist/",
type: "get",
headers: {
'Authorization': "Bearer " + store.state.access,
},
success: resp => {
const new_players = [resp.me, ...resp.all];
let id = 0;
for (let player of new_players)
player.id = id ++ ;
players.value = new_players;
}
});
const close_ranklist = () => {
store.commit("updateRanklist", false);
}
return {
players,
close_ranklist
}
}
}
</script>
<style scoped>
div.ranklist {
position: absolute;
width: 30vh;
height: 44vh;
background-color: lightblue;
}
span.close-ranklist {
float: right;
position: absolute;
right: 0.5vh;
font-size: 2vh;
cursor: pointer;
}
div.player:nth-child(2) {
background-color: #EECB07;
}
div.player {
width: 100%;
height: 4vh;
display: grid;
grid-template-columns: repeat(4, 7.5vh);
line-height: 4vh;
}
div.player > div {
text-align: center;
color: white;
}
div.player > div:nth-child(2) {
display: flex;
justify-content: center;
align-items: center;
}
div.player > div > img {
width: 3vh;
height: 3vh;
border-radius: 50%;
}
div.player > div:nth-child(3) {
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
text-align: left;
}
</style>

@ -0,0 +1,125 @@
<template>
<div class="score-board">
<div class="apple">
<img src="https://test.bnblogs.cc/acapp/images/apple/count.png" alt="">
<div>{{ $store.state.score }}</div>
</div>
<div class="Music" @click="handleMusic">
<img src='./static/openMusic.png' v-if="$store.state.music">
<img src='./static/closeMusic.png' v-else>
<audio id="player">
<source src="https://test.bnblogs.cc/acapp/audios/snake.mp3" type="audio/mpeg">
</audio>
<audio id="eat_apple">
<source src="https://test.bnblogs.cc/acapp/audios/eat_apple.m4a" type="audio/mpeg">
</audio>
</div>
<div class="cup">
<img src="https://app3359.acapp.acwing.com.cn/static/images/cup.png" alt="">
<div>{{ $store.state.record }}</div>
</div>
</div>
</template>
<script>
import { ref } from 'vue'
import { useStore } from 'vuex'
export default {
name: "ScoreBoard",
setup() {
let open = ref(false);
const store = useStore();
if (store.state.music === true) {
const audio_1 = document.querySelector('#player');
audio_1.play();
store.commit('updateAudio',audio_1);
}
const handleMusic = () => {
const audio = document.querySelector('#player')
store.commit('updateAudio',audio);
if (open.value === false) {
open.value = true;
audio.play();
}
else {
open.value= false;
audio.pause();
}
store.commit('updateMusic',open.value)
// console.log(store.state.music);
}
return {
open,
handleMusic,
}
}
}
</script>
<style scoped>
.score-board {
height: 8vh;
width: 100%;
background-color: #4A752C;
display: flex;
justify-content: space-around;
user-select: none;
}
.apple {
display: flex;
align-items: center;
}
.apple > img {
width: 7vh;
height: 7vh;
}
.apple > div {
color: white;
font-weight: bold;
font-size: 2.5vh;
}
.cup {
display: flex;
align-items: center;
}
.cup > img {
width: 4.5vh;
height: 5vh;
}
.cup > div {
color: white;
font-weight: bold;
font-size: 2.5vh;
margin-left: 1vh;
}
.Music {
display: flex;
align-items: center;
cursor: pointer;
}
.Music > img {
width: 5vh;
height: 5vh;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

@ -0,0 +1,5 @@
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')

@ -0,0 +1,63 @@
import { createStore } from 'vuex'
export default createStore({
state: {
score: 0,
record: 0,
restart: true,
AcWingOS: "AcWingOS",
access: "",
refresh: "",
ranklist: false,
upgrade: false,
music: false, // 默认无音乐
audio: null,
color: null, // 保存上一局的蛇体颜色
},
getters: {
},
mutations: {
updateScore: (state, score) => {
state.score = score;
},
updateRecord: (state, score) => {
if (state.record < score) {
state.record = score;
}
},
updateRestart: (state, restart) => {
state.restart = restart;
},
updateAccess: (state, access) => {
state.access = access;
},
updateRefresh: (state, refresh) => {
state.refresh = refresh;
},
updateRanklist: (state, ranklist) => {
state.ranklist = ranklist;
},
updateNumber: (state,number) => {
state.number = number;
},
updateSpeed: (state, speed) => {
state.speed = speed;
},
updateNextStep:(state,upgrade) => {
state.upgrade = upgrade;
},
updateMusic:(state,music) => {
state.music= music;
},
updateAudio:(state,audio) => {
state.audio = audio;
},
updateColor:(state,color) => {
state.color = color;
}
},
actions: {
},
modules: {
}
})

@ -0,0 +1,10 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
// No need for splitting
optimization: {
splitChunks: false
}
}
})

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,24 @@
# snake
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,46 @@
{
"name": "snake",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.8.3",
"jquery": "^3.6.1",
"vue": "^3.2.13",
"vuex": "^4.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body style="margin: 0;">
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app" style="width: 100vw; height: 100vh;display: flex;
justify-content: center;
align-items: center;"></div>
<!-- built files will be auto injected -->
</body>
</html>

@ -0,0 +1,23 @@
<template>
<div class="gameboard">
<PlayGround />
</div>
</template>
<script>
import PlayGround from '@/components/PlayGround'
export default {
name: 'App',
components: {
PlayGround,
}
}
</script>
<style scoped>
.gameboard {
width: 30%;
height: 80%;
}
</style>

@ -0,0 +1,47 @@
const AC_GAME_OBJECTS = [];
export class AcGameObject {
constructor() {
AC_GAME_OBJECTS.push(this);
this.timedelta = 0;
this.has_called_start = false;
}
start() {
}
update() {
}
on_destroy() {
}
destroy() {
this.on_destroy();
for (let i in AC_GAME_OBJECTS) {
const obj = AC_GAME_OBJECTS[i];
if (obj === this) {
AC_GAME_OBJECTS.splice(i, 1);
break;
}
}
}
}
let last_timestamp;
const step = timestamp => {
for (let obj of AC_GAME_OBJECTS) {
if (!obj.has_called_start) {
obj.start();
obj.has_called_start = true;
} else {
obj.timedelta = timestamp - last_timestamp;
obj.update();
}
}
last_timestamp = timestamp;
requestAnimationFrame(step);
};
requestAnimationFrame(step);

@ -0,0 +1,8 @@
export class Cell {
constructor(i, j) {
this.i = i;
this.j = j;
this.x = i + 0.5;
this.y = j + 0.5;
}
}

@ -0,0 +1,130 @@
import { AcGameObject } from "./AcGameObject";
import { Snake } from "./Snake";
import $ from 'jquery';
export class GameMap extends AcGameObject {
constructor(ctx, parent, store) {
super();
this.ctx = ctx;
this.parent = parent;
this.store = store;
this.L = 0;
this.snake = new Snake(this.ctx, this);
this.directions = [];
this.status = "waiting"; // waiting -> playing -> win/lose
}
start() {
this.ctx.canvas.focus();
this.ctx.canvas.addEventListener('keydown', e => {
if (this.store.state.restart) return false;
if (e.key === 'w' || e.key === 'ArrowUp') {
this.directions.push(0);
e.preventDefault();
}
else if (e.key === 'd' || e.key == 'ArrowRight') {
this.directions.push(1);
e.preventDefault();
}
else if (e.key === 's' || e.key === 'ArrowDown') {
this.directions.push(2);
e.preventDefault();
}
else if (e.key === 'a' || e.key === 'ArrowLeft') {
this.directions.push(3);
e.preventDefault();
}
let k = this.directions.length;
if (k > 1 && this.directions[k - 1] === this.directions[k - 2]) {
this.directions.pop();
}
while (this.directions.length > 2)
this.directions.splice(0, 1);
if (this.status === "waiting" && this.directions.length && this.directions[0] !== 3) {
this.status = "playing";
this.snake.direction = this.directions[0];
}
});
}
update_size() {
this.L = Math.min(this.parent.clientWidth / 17, this.parent.clientHeight / 15);
this.ctx.canvas.width = this.L * 17;
this.ctx.canvas.height = this.L * 15;
}
update_score() {
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/update_score/",
type: "post",
data: {
score: this.store.state.score,
},
headers: {
'Authorization': "Bearer " + this.store.state.access,
},
})
}
win() {
this.snake.color = "white";
this.status = "win";
this.store.commit('updateRestart', true);
this.update_score();
}
lose() {
this.snake.color = "white";
this.status = "lose";
this.store.commit('updateRestart', true);
this.update_score();
}
restart() {
this.store.state.score = 0;
this.status = "waiting";
this.snake.destroy();
this.snake = new Snake(this.ctx, this);
this.store.commit('updateRestart', false);
this.store.commit('updateNumber',0);
this.ctx.canvas.focus();
}
upgrade() {
this.status = "waiting";
this.snake.destroy();
this.snake = new Snake(this.ctx, this);
this.snake.speed = this.store.state.speed;
this.snake.number = this.store.state.number;
this.store.commit("updateRecord",Math.max(this.store.state.score,this.store.state.record));
this.ctx.canvas.focus();
}
update() {
this.update_size();
this.render();
}
render() {
let color_even = "#AAD751", color_odd = "#A2D149";
for (let i = 0; i < 17; i ++ ) {
for (let j = 0; j < 15; j ++ ) {
if ((i + j) % 2 == 0) {
this.ctx.fillStyle = color_even;
} else {
this.ctx.fillStyle = color_odd;
}
this.ctx.fillRect(i * this.L, j * this.L, this.L, this.L);
}
}
}
}

@ -0,0 +1,187 @@
import { AcGameObject } from './AcGameObject';
import { Cell } from './Cell';
export class Snake extends AcGameObject {
constructor(ctx, gamemap) {
super();
this.ctx = ctx;
this.gamemap = gamemap;
this.cells = [];
this.color = "#4876EC";
this.dirs = [
{x: 0, y: -1},
{x: 1, y: 0},
{x: 0, y: 1},
{x: -1, y: 0},
];
this.direction = 2;
this.eps = 1e-1;
this.speed = 5; // 每秒钟走几格,初始速度为5
this.apple_cell = new Cell(-1, -1);
this.apple_img = new Image();
this.apple_img.src = "https://app3359.acapp.acwing.com.cn/static/images/apple.png";
this.eating = false;
this.tail_cell = null;
this.number = 0;
}
start() {
this.cells.push(new Cell(4, 7));
for (let i = 4; i >= 1; i -- ) {
this.cells.push(new Cell(i, 7));
}
this.put_an_apple();
}
put_an_apple() {
const positions = new Set();
for (let i = 0; i < 17; i ++ ) {
for (let j = 0; j < 15; j ++ ) {
positions.add(`${i}-${j}`);
}
}
for (let cell of this.cells) {
positions.delete(`${cell.i}-${cell.j}`);
}
const items = Array.from(positions);
if (items.length === 0) this.gamemap.win();
else {
let [x, y] = items[Math.floor(Math.random() * items.length)].split('-');
x = parseInt(x), y = parseInt(y);
this.apple_cell = new Cell(x, y);
}
}
get_direction(a, b) {
if (Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps)
return -1;
if (Math.abs(a.x - b.x) < this.eps) {
if (b.y < a.y) return 0;
return 2;
}
if (b.x > a.x) return 1;
return 3;
}
check_die() {
const head = this.cells[0];
if (head.i < 0 || head.i >= 17 || head.j < 0 || head.j >= 15)
return true;
for (let i = 2; i < this.cells.length; i ++ ) {
if (head.i === this.cells[i].i && head.j === this.cells[i].j) {
return true;
}
}
return false;
}
update_body() {
const k = this.cells.length - 1;
const d = this.get_direction(this.cells[k], this.cells[k - 1]);
if (d >= 0) {
const distance = this.speed * this.timedelta / 1000;
this.cells[k].x += this.dirs[d].x * distance;
this.cells[k].y += this.dirs[d].y * distance;
this.cells[0].x += this.dirs[this.direction].x * distance;
this.cells[0].y += this.dirs[this.direction].y * distance;
} else {
const new_cells = [];
const headi = this.cells[1].i + this.dirs[this.direction].x;
const headj = this.cells[1].j + this.dirs[this.direction].y;
new_cells.push(new Cell(headi, headj));
new_cells.push(new Cell(headi, headj));
for (let i = 1; i < k; i ++ ) {
new_cells.push(this.cells[i]);
}
this.cells = new_cells;
if (this.eating) {
this.cells.push(this.tail_cell);
this.eating = false;
this.tail_cell = null;
}
const ds = this.gamemap.directions;
while (ds.length > 0 && (ds[0] === this.direction || ds[0] === (this.direction ^ 2)))
ds.splice(0, 1);
if (ds.length > 0) {
this.direction = ds[0];
ds.splice(0, 1);
}
if (this.check_die()) {
this.gamemap.lose();
}
if (headi === this.apple_cell.i && headj === this.apple_cell.j) {
this.eating = true;
const cell = this.cells[this.cells.length - 1];
this.tail_cell = new Cell(cell.i, cell.j);
this.put_an_apple();
const score = this.gamemap.store.state.score + 1;
this.gamemap.store.commit('updateScore', score);
this.gamemap.store.commit('updateRecord', Math.max(score,this.gamemap.store.state.record));
this.number++;
this.gamemap.store.commit('updateNumber',this.number);
if (this.number > 0 && this.number % 10 === 0) { // 每吃10个增加速度1
this.speed = this.speed + 1;
this.gamemap.store.commit("updateSpeed",this.speed);
}
if (this.number > 0 && this.number % 30 === 0) {
// 进入下一回合,先加10分
this.gamemap.store.commit("updateScore",score + 10);
this.gamemap.upgrade();
}
console.log("num: ",this.number);
}
}
}
update() {
if (this.gamemap.status === "playing") {
this.update_body();
}
this.render();
}
render() {
const L = this.gamemap.L;
if (this.eating) {
this.cells.push(this.tail_cell);
}
this.ctx.drawImage(this.apple_img, this.apple_cell.i * L, this.apple_cell.j * L, L, L);
this.ctx.fillStyle = this.color;
for (let cell of this.cells) {
this.ctx.beginPath();
this.ctx.arc(cell.x * L, cell.y * L, L / 2 * 0.8, 0, Math.PI * 2);
this.ctx.fill();
}
for (let i = 1; i < this.cells.length; 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;
}
if (Math.abs(a.x - b.x) < this.eps) {
this.ctx.fillRect((a.x - 0.5 + 0.1) * L, Math.min(a.y, b.y) * L, L * 0.8, Math.abs(a.y - b.y) * L);
} else {
this.ctx.fillRect(Math.min(a.x, b.x) * L, (a.y - 0.5 + 0.1) * L, Math.abs(a.x - b.x) * L, L * 0.8);
}
}
if (this.eating) {
this.cells.pop();
}
}
}

@ -0,0 +1,37 @@
import $ from 'jquery';
export const init = (store) => {
const AcWingOS = store.state.AcWingOS;
if (AcWingOS === "AcWingOS") return false;
const vw = window.innerWidth;
const vh = window.innerHeight;
AcWingOS.api.window.resize(59.5 * vh / vw, 64.5);
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/apply_code/",
type: "get",
success: resp => {
AcWingOS.api.oauth2.authorize(resp.appid, resp.redirect_uri, resp.scope, resp.state, resp => {
if (resp.result === "success") {
store.commit('updateAccess', resp.access);
store.commit('updateRefresh', resp.refresh);
setInterval(() => {
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/api/token/refresh/",
type: "post",
data: {
refresh: resp.refresh,
},
success: resp => {
store.commit('updateAccess', resp.access);
}
});
}, 4.5 * 60 * 1000);
}
});
}
})
}

@ -0,0 +1,82 @@
<template>
<div class="gamemap" ref="div">
<canvas ref="canvas" tabindex="0"></canvas>
<div class="operation" v-if="$store.state.restart">
<button @click="restart">开始游戏</button>
<button @click="show_ranklist">排行榜</button>
</div>
<RankList v-if="$store.state.ranklist" />
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { GameMap } from '@/assets/scripts/GameMap';
import { useStore } from 'vuex';
import { init } from '@/assets/scripts/init';
import RankList from './RankList'
export default {
name: "GameMap",
components: {
RankList,
},
setup: () => {
let div = ref(null);
let canvas = ref(null);
const store = useStore();
let gamemap = null;
init(store);
onMounted(() => {
gamemap = new GameMap(canvas.value.getContext('2d'), div.value, store);
});
const restart = () => {
gamemap.restart();
}
const show_ranklist = () => {
store.commit('updateRanklist', true);
}
return {
div,
canvas,
restart,
show_ranklist
}
}
}
</script>
<style scoped>
div.gamemap {
height: calc(100% - 8vh);
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
canvas {
background-color: #AAD751;
}
div.operation {
position: absolute;
}
button {
background-color: #0d6efd;
border: solid 0;
border-radius: 5px;
font-size: 3vh;
color: white;
padding: 3vh;
cursor: pointer;
margin: 0 0.5vh;
}
</style>

@ -0,0 +1,32 @@
<template>
<div class="playground">
<ScoreBoard />
<GameMap />
</div>
</template>
<script>
import ScoreBoard from '@/components/ScoreBoard';
import GameMap from '@/components/GameMap';
export default {
name: "PlayGround",
components: {
ScoreBoard,
GameMap
}
}
</script>
<style scoped>
.playground {
width: 100%;
height: 100%;
background-color: #578A34;
}
</style>

@ -0,0 +1,104 @@
<template>
<div class="ranklist">
<span class="close-ranklist" @click="close_ranklist">x</span>
<div class="player" v-for="player in players" :key="player.id">
<div>#{{ player.rank }}</div>
<div>
<img :src="player.photo" alt="">
</div>
<div>{{ player.username }}</div>
<div>{{ player.score }}</div>
</div>
</div>
</template>
<script>
import { ref } from 'vue';
import $ from 'jquery';
import { useStore } from 'vuex';
export default {
name: 'RankList',
setup() {
const store = useStore();
let players = ref([]);
$.ajax({
url: "https://app3359.acapp.acwing.com.cn/get_ranklist/",
type: "get",
headers: {
'Authorization': "Bearer " + store.state.access,
},
success: resp => {
const new_players = [resp.me, ...resp.all];
let id = 0;
for (let player of new_players)
player.id = id ++ ;
players.value = new_players;
}
});
const close_ranklist = () => {
store.commit("updateRanklist", false);
}
return {
players,
close_ranklist
}
}
}
</script>
<style scoped>
div.ranklist {
position: absolute;
width: 30vh;
height: 44vh;
background-color: lightblue;
}
span.close-ranklist {
float: right;
position: absolute;
right: 0.5vh;
font-size: 2vh;
cursor: pointer;
}
div.player:nth-child(2) {
background-color: #EECB07;
}
div.player {
width: 100%;
height: 4vh;
display: grid;
grid-template-columns: repeat(4, 7.5vh);
line-height: 4vh;
}
div.player > div {
text-align: center;
color: white;
}
div.player > div:nth-child(2) {
display: flex;
justify-content: center;
align-items: center;
}
div.player > div > img {
width: 3vh;
height: 3vh;
border-radius: 50%;
}
div.player > div:nth-child(3) {
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
text-align: left;
}
</style>

@ -0,0 +1,65 @@
<template>
<div class="score-board">
<div class="apple">
<img src="https://app3359.acapp.acwing.com.cn/static/images/apple.png" alt="">
<div>{{ $store.state.score }}</div>
</div>
<div class="cup">
<img src="https://app3359.acapp.acwing.com.cn/static/images/cup.png" alt="">
<div>{{ $store.state.record }}</div>
</div>
</div>
</template>
<script>
export default {
name: "ScoreBoard",
}
</script>
<style scoped>
.score-board {
height: 8vh;
width: 100%;
background-color: #4A752C;
display: flex;
justify-content: space-around;
user-select: none;
}
.apple {
display: flex;
align-items: center;
}
.apple > img {
width: 6vh;
height: 6vh;
}
.apple > div {
color: white;
font-weight: bold;
font-size: 2.5vh;
}
.cup {
display: flex;
align-items: center;
}
.cup > img {
width: 4.5vh;
height: 5vh;
}
.cup > div {
color: white;
font-weight: bold;
font-size: 2.5vh;
margin-left: 1vh;
}
</style>

@ -0,0 +1,5 @@
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')

@ -0,0 +1,49 @@
import { createStore } from 'vuex'
export default createStore({
state: {
score: 0,
record: 0,
restart: true,
AcWingOS: "AcWingOS",
access: "",
refresh: "",
ranklist: false,
speed: 5,
number: 0,
},
getters: {
},
mutations: {
updateSpeed: (state, speed) => {
state.speed = speed;
},
updateScore: (state, score) => {
state.score = score;
},
updateRecord: (state, score) => {
if (state.record < score) {
state.record = score;
}
},
updateRestart: (state, restart) => {
state.restart = restart;
},
updateAccess: (state, access) => {
state.access = access;
},
updateRefresh: (state, refresh) => {
state.refresh = refresh;
},
updateRanklist: (state, ranklist) => {
state.ranklist = ranklist;
},
updateNumber: (state,number) => {
state.number = number;
}
},
actions: {
},
modules: {
}
})

@ -0,0 +1,9 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack:{
optimization:{
splitChunks:false
}
}
})
Loading…
Cancel
Save