改成大包传输消息了
RectangleMove.vue
<template>
<div class="CanvasContainer">
<canvas width="1000" height="800" ref="backgroundCanvas"></canvas>
<button @click="test">测试</button>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue"
import Player from "../entity/Player.js"
import Bullet from "../entity/Bullet.js"
import { playerJoin, playerMove, playerShoot, playerDelete } from "../api/api.js"
import { drawPlayer, drawBullet } from "../renderer/renderer.js"
function test() {
ws.send(JSON.stringify({ type: "test" }))
}
const backgroundCanvas = ref(null)
let ctx = null
let ws = null
//我的名字
let myName = null
//玩家集合
let players = []
//子弹集合
let bullets = []
//标准玩家对象
const standerdPlayer = {
name: myName,
id: Date.now(),
color: "red",
maxHp: 100,
hp: 100,
at: 10,
latestShoot: 0,
latestHurt: 0,
x: 0,
y: 0,
w: 60,
h: 60,
a: 0,
v: 5,
up: false,
down: false,
left: false,
right: false,
angle: 0
}
//按键字典
const keys = {
w: false,
a: false,
s: false,
d: false,
mouseX: 0,
mouseY: 0,
mouseDown: false,
mouseLatestDown: 0
}
//按下按键
function keyDown(e) {
const me = players.find(player => player.name === myName)
console.log(e.key)
switch (e.key) {
case "w":
me.up = true;
break;
case "s":
me.down = true;
break;
case "a":
me.left = true;
break;
case "d":
me.right = true;
break;
}
console.log(me)
playerMove(ws, me)
}
//松开按键
function keyUp(e) {
const me = players.find(player => player.name === myName)
switch (e.key) {
case "w":
me.up = false;
break;
case "s":
me.down = false;
break;
case "a":
me.left = false;
break;
case "d":
me.right = false;
break;
}
playerMove(ws, me)
}
//鼠标按下
function mouseDown(e) {
const me = players.find(player => player.name === myName)
me.angle = Math.atan2(keys.mouseY - me.y, keys.mouseX - me.x) / Math.PI * 180
console.log(me.angle)
}
//鼠标移动
function mouseMove(e) {
keys.mouseX = e.clientX - backgroundCanvas.value.getBoundingClientRect().left;
keys.mouseY = e.clientY - backgroundCanvas.value.getBoundingClientRect().top;
}
//画鼠标准心
function drawMouse() {
const cx = keys.mouseX
const cy = keys.mouseY
const len = 8
const gap = 3
ctx.strokeStyle = '#fff'
ctx.lineWidth = 2
ctx.beginPath()
ctx.moveTo(cx, cy - gap - len)
ctx.lineTo(cx, cy - gap)
ctx.moveTo(cx, cy + gap)
ctx.lineTo(cx, cy + gap + len)
ctx.moveTo(cx - gap - len, cy)
ctx.lineTo(cx - gap, cy)
ctx.moveTo(cx + gap, cy)
ctx.lineTo(cx + gap + len, cy)
ctx.stroke()
}
//画
function draw() {
//清空画布
ctx.clearRect(0, 0, backgroundCanvas.value.width, backgroundCanvas.value.height)
players.forEach(player => {
drawPlayer(ctx, player)
})
bullets.forEach(bullet => {
drawBullet(ctx, bullet)
})
drawMouse()
}
//动画
function animate() {
draw()
requestAnimationFrame(animate)
}
//初始化
onMounted(() => {
myName = prompt("输入你的昵称")
const canvas = backgroundCanvas.value
ctx = canvas.getContext("2d")
ws = new WebSocket("ws://10.99.121.4:5000")
ws.onopen = () => {
let x = Math.random() * canvas.width
let y = Math.random() * canvas.height
const me = new Player(standerdPlayer)
me.name = myName
me.x = x
me.y = y
playerJoin(ws, me)
//绑定按键事件
window.addEventListener('keydown', keyDown)
window.addEventListener('keyup', keyUp)
window.addEventListener('mousemove', mouseMove)
window.addEventListener('mousedown', mouseDown)
//启动
animate()
}
//同步服务器数据
ws.onmessage = (message) => {
const msg = JSON.parse(message.data)
const type = msg.type
const data = msg.data
switch (type) {
case "gameSync":
players = data.players
bullets = data.bullets
}
}
})
</script>
<style scoped>
.CanvasContainer {
display: flex;
width: 100vw;
height: 100vh;
background-color: #000;
align-items: center;
justify-content: center;
}
canvas {
background-color: #000333;
border: red solid 2px;
cursor: none;
}
</style>
api.js
function playerJoin(ws, player) {
ws.send(JSON.stringify({
type: "pJoin",
data: player
}))
}
function playerMove(ws, player) {
ws.send(JSON.stringify({
type: "pMove",
data: player
}))
}
function playerShoot(ws, player) {
ws.send(JSON.stringify({
type: "pShoot",
data: player
}))
}
function playerDelete(ws, player) {
ws.send(JSON.stringify({
type: "pDelete",
data: player
}))
}
export {
playerJoin,
playerMove,
playerShoot,
playerDelete
}
app.js
import Player from './entity/PLayer.js'
import Bullet from './entity/Bullet.js';
import express from 'express';
import {WebSocketServer} from 'ws';
import cors from 'cors';
const app = express();
app.use(express.json());
app.use(cors());
const server = app.listen(5000, () => {
console.log('服务器运行在 http://localhost:5000');
});
const wss = new WebSocketServer({server});
let players = []
let bullets = []
let config = {
FPS: 1000 / 60,
shootGap: 1000,
}
wss.on('connection', ws => {
console.log('有玩家连接服务器');
ws.on('message', message => {
const msg = JSON.parse(message);
const type = msg.type;
const data = msg.data;
const tsp = Date.now();
let index;
//接受玩家消息
switch (type) {
//玩家加入
case 'pJoin':
index = players.findIndex(player => player.id === data.id)
if(index === -1) {
players.push(new Player(data))
console.log(data.name + " 加入游戏")
}else{
console.log(data.name + "重新加入游戏")
}
break;
//玩家移动
case 'pMove':
index = players.findIndex(player => player.id === data.id)
if (index > -1) {
players[index].up = data.up;
players[index].down = data.down;
players[index].left = data.left;
players[index].right = data.right;
}
break;
//玩家射击
case 'pShoot':
index = players.findIndex(player => player.id === data.id)
if ((index > -1) && (tsp - players[index].latestShoot > config.shootGap)) {
//新建子弹
bullets.push(new Bullet({
id: bullets.length,
from: players[index].name,
color: players[index].color,
at: players[index].at,
x: players[index].x,
y: players[index].y,
w: 10,
h: 10,
a: 0,
v: 5,
angle: players[index].angle
}));
}
break;
//玩家死亡
case 'pDelete':
index = players.findIndex(player => player.id === data.id)
if (index > -1) {
players.splice(index, 1)
console.log(data.name + " 离开游戏")
}
break;
case 'test':
console.log(players,bullets);
}
})
})
//广播定时器
setInterval(() => {
//更新玩家位置
players.forEach(player => {
if(player.up)
player.y -= player.v;
if(player.down)
player.y += player.v;
if(player.left)
player.x -= player.v;
if(player.right)
player.x += player.v;
})
//所有客户端同步玩家和子弹
wss.clients.forEach((client) => {
client.send(JSON.stringify({type: "gameSync", data: {players: players, bullets: bullets}}))
})
//碰撞检测
}, config.FPS)