20260510

改成大包传输消息了

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)

posted @ 2026-05-10 20:57  Leeszz  阅读(12)  评论(0)    收藏  举报