蛇的控制逻辑,增长逻辑,碰撞检测改为后端实现 + 结果计分板实现

This commit is contained in:
2023-03-03 16:51:58 +08:00
parent 4b3ebf9d77
commit ae4d8ef42d
10 changed files with 475 additions and 23 deletions
+22 -7
View File
@@ -33,7 +33,7 @@ export class GameMap extends AcGameObject {
// 上面的 super() 会先将 AcGameObject 先绘制, walls 的绘制在后面执行,因此墙最后会覆盖原棋盘格进行绘制
this.walls = [];
// 创建蛇对象数组
// 创建蛇对象数组(可以通过 store.state.pk.game_object.snakes 全局变量调取)
this.snakes = [
// 注意这里的对象生成方式和传参方式
new Snake({ id: 0, color: "#4876ec", r: this.rows - 2, c: 1 }, this),
@@ -167,20 +167,35 @@ export class GameMap extends AcGameObject {
this.ctx.canvas.focus();
// 先取出两条蛇对象
const [snake0, snake1] = this.snakes;
// const [snake0, snake1] = this.snakes;
// 获取用户信息:绑定 keydown 事件
this.ctx.canvas.addEventListener("keydown", (e) => {
// 取出移动的方向,需要将方向传给后端
let d = -1; // -1 表示没有方向, 0-上, 1-右, 2-下, 3-左
// 定义 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);
// 定义 snake1 的键盘绑定事件
if (e.key === "w") d = 0;
else if (e.key === "d") d = 1;
else if (e.key === "s") d = 2;
else if (e.key === "a") d = 3;
// 如果进行了合法的移动操作:向后端发送方向
if(d>=0){
// 使用 socket.send() 传递信息给后端,使用 JSON.stringify() 将一个 JSON 封装成一字符串
this.store.state.pk.socket.send(JSON.stringify({
event: "move", // 事件类型: move
direction : d, // 方向: d
}))
}
/*
// 定义 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);
*/
});
}
+3 -2
View File
@@ -104,11 +104,12 @@ export class Snake extends AcGameObject {
// 这里需要使用 JSON 方法进行深度复制,以产生新的对象避免数据出错
this.cells[i] = JSON.parse(JSON.stringify(this.cells[i - 1]));
}
/* //(改为后端实现)
// 如果下一步操作的目标位置碰撞检测不合法,则蛇直接去世
if (!this.gamemap.check_valid(this.next_cell)) {
this.status = "die";
}
}
*/
}
update_move() {
+4 -2
View File
@@ -24,8 +24,10 @@ export default {
// 定义挂载函数,挂载完成后执行
onMounted(() => {
// new GameMap(canvas.value.getContext("2d"), parent.value);
// 改为后端(服务器)获取生成地图
new GameMap(canvas.value.getContext("2d"), parent.value, store);
// 改为后端(服务器)获取生成地图:并将游戏信息存入 store
store.commit("updateGameObject",
new GameMap(canvas.value.getContext("2d"), parent.value, store),
);
});
return {
+78
View File
@@ -0,0 +1,78 @@
// 计分板
<template>
<div class="result-borad">
<div class="result-board-text" v-if="$store.state.pk.loser === 'all'">
平局
</div>
<div class="result-board-text"
v-else-if="$store.state.pk.loser === 'A' && $store.state.pk.a_id === parseInt($store.state.user.id)">
你输了!
</div>
<div class="result-board-text"
v-else-if="$store.state.pk.loser === 'B' && $store.state.pk.b_id == $store.state.user.id">
你输了!
</div>
<div class="result-board-text"
v-else-if="$store.state.pk.loser === 'A' && $store.state.pk.b_id == $store.state.user.id">
你赢了!
</div>
<div class="result-board-text"
v-else-if="$store.state.pk.loser === 'B' && $store.state.pk.a_id == $store.state.user.id">
你赢了!
</div>
<div class="result-board-btn">
<button type="button" class="btn btn-dark" @click="restart">再来一次</button>
</div>
</div>
</template>
<script>
import { useStore } from "vuex";
export default {
setup() {
const store = useStore();
// 重来,需要恢复全局变量
const restart = () => {
store.commit("updateStatus", "matching");
store.commit("updateLoser", "none");
}
return {
restart,
};
}
}
</script>
<style scoped>
div.result-borad {
height: 30vh;
width: 30vw;
background-color: rgba(194, 194, 195, 0.504);
/* 位置 */
position: absolute;
top: 30vh;
left: 35vw;
}
.result-board-text {
text-align: center;
color: rgb(234, 234, 234);
font-size: 50px;
font-weight: 600;
font-style: italic;
padding-top: 5vh;
}
.result-board-btn {
padding-top: 3vh;
text-align: center;
}
</style>
+23
View File
@@ -7,10 +7,20 @@ export default {
// 对手信息
opponent_username: "",
opponent_photo: "",
// 地图信息(后端传入)
game_map: null,
rows: 0,
cols: 0,
inner_walls_count: 0,
a_id: 0,
a_sx: 0,
a_sy: 0,
b_id: 0,
b_sx: 0,
b_sy: 0,
// 游戏全局
game_object: null,
loser:"none", // all, A, B 三种结果
},
getters: {},
mutations: {
@@ -33,7 +43,20 @@ export default {
state.rows = game_data.rows;
state.cols = game_data.cols;
state.inner_walls_count = game_data.inner_walls_count;
state.a_id = game_data.a_id;
state.a_sx = game_data.a_sx;
state.a_sy = game_data.a_sy;
state.b_id = game_data.b_id;
state.b_sx = game_data.b_sx;
state.b_sy = game_data.b_sy;
},
updateGameObject(state, game_object){
// 在 GameMap.vue 中使用
state.game_object = game_object;
},
updateLoser(state,loser){
state.loser = loser;
}
},
actions: {},
module: {},
+38 -2
View File
@@ -1,11 +1,14 @@
<template>
<PlayGround v-if="$store.state.pk.status === 'playing'" />
<MatchGround v-else-if="$store.state.pk.status === 'matching'" />
<ResultBoard v-if="$store.state.pk.loser !== 'none'" />
</template>
<script>
import PlayGround from "../../components/PlayGround.vue";
import MatchGround from "../../components/MatchGround.vue"
import MatchGround from "../../components/MatchGround.vue";
import ResultBoard from "../../components/ResultBoard.vue";
// onMounted 用于组件被挂载时, onUnmounted 用于组件被解除挂载时
import { onMounted, onUnmounted } from "vue";
// 取出全局变量
@@ -14,7 +17,8 @@ import { useStore } from "vuex";
export default {
components: {
PlayGround,
MatchGround
MatchGround,
ResultBoard
},
// 创建前后端连接:当当前页面组件被加载时,建立连接,故使用 onMounted 函数
setup() {
@@ -23,6 +27,7 @@ export default {
const socketUrl = `ws://127.0.0.1:3000/websocket/${store.state.user.token}/`;
let socket = null;
// 当前组件被挂载的时候,需要创建后端连接,并且需要将连接信息存储到 store 全局变量里
onMounted(() => {
// 定义默认匹配页面对手信息(匹配等待过程中使用)
@@ -61,6 +66,37 @@ export default {
store.commit("updateGameMap", data.game_data);
console.log(data.game_data);
}
else if (data.event === "move") {
// console.log(data);
// 调取 store 中存入的地图全局信息
const game = store.state.pk.game_object;
// 从地图全局信息中解构出 GameMap.js 中定义的 snakes
const [snake0, snake1] = game.snakes;
// 设置两条蛇的移动:后端 sendMove 中的参数
snake0.set_direction(data.a_direction);
snake1.set_direction(data.b_direction);
}
else if (data.event === "result") {
console.log(data);
const game = store.state.pk.game_object;
const [snake0, snake1] = game.snakes;
// 修改最后一步(检测到碰撞后)蛇的眼睛方向
snake0.eye_direction = data.a_eyes_finally_direction;
snake1.eye_direction = data.b_eyes_finally_direction;
// 更新 loser 信息,存储到全局 store 中
store.commit("updateLoser",data.loser);
// 更新 loser 的 snake 对象 status 状态
if (data.loser === "all" || data.loser === "A") {
snake0.status = "die";
}
if (data.loser === "all" || data.loser === "B") {
snake1.status = "die";
}
}
}
socket.onclose = () => {