20260419

终于实现联机逻辑了,虽然代码很烂(非常烂)而且只有简单的移动逻辑并且bug也很多,但后续我还会修复和补充完整的。

第一次看到其他设备上的小方块会跟随本机上的小方块移动时真的太激动了,这一刻感觉自己无所不能,这是使用ai写得不到的成就感

下面依旧是代码环节:

这是前端vue中的一个组件:RectangleMove.vue

  1 <template>
  2   <div class="CanvasContainer">
  3     <canvas width="1000" height="800" ref="backgroundCanvas"></canvas>
  4   </div>
  5 </template>
  6 
  7 <script setup>
  8 import axios from "axios"
  9 import { onMounted, ref } from "vue"
 10 
 11 const backgroundCanvas = ref(null)
 12 let ctx = null
 13 let ws = null
 14 //我的名字
 15 let myName = Date.now()
 16 //玩家集合
 17 const players = []
 18 //子弹集合
 19 const bullets = []
 20 //按键字典
 21 const keys = {
 22   w: false,
 23   a: false,
 24   s: false,
 25   d: false,
 26   mouseX: 0,
 27   mouseY: 0,
 28   mouseDown: false,
 29   mouseLatestDown: 0
 30 }
 31 //按下按键
 32 function keyDown(e) {
 33   if (keys.hasOwnProperty(e.key)) {
 34     keys[e.key] = true
 35   }
 36 }
 37 //松开按键
 38 function keyUp(e) {
 39   if (keys.hasOwnProperty(e.key)) {
 40     keys[e.key] = false
 41   }
 42 }
 43 //鼠标移动
 44 function mouseMove(e) {
 45   keys.mouseX = e.clientX - backgroundCanvas.value.getBoundingClientRect().left;
 46   keys.mouseY = e.clientY - backgroundCanvas.value.getBoundingClientRect().top;
 47 }
 48 //鼠标按下
 49 function mouseDown(e) {
 50   const ts = Date.now()
 51   if (ts - keys.mouseLatestDown >= 1000) {
 52     //新增子弹
 53     const me = players.find(player => player.name == myName)
 54 
 55     //计算方向
 56     const dx = keys.mouseX - me.x
 57     const dy = keys.mouseY - me.y
 58     const dist = Math.sqrt(dx * dx + dy * dy)
 59     const speed = 5
 60 
 61     //保证所有方向速度一致
 62     const vx = (dx / dist) * speed
 63     const vy = (dy / dist) * speed
 64 
 65     bullets.push(new Bullet(me.x, me.y, 10, 10, "green", vx, vy, null, myName))
 66 
 67     keys.mouseDown = false
 68     keys.mouseLatestDown = Date.now()
 69   }
 70 
 71 }
 72 //画鼠标准心
 73 function drawMouse() {
 74   const cx = keys.mouseX
 75   const cy = keys.mouseY
 76   const len = 8
 77   const gap = 3
 78 
 79   ctx.strokeStyle = '#fff'
 80   ctx.lineWidth = 2
 81 
 82   ctx.beginPath()
 83   ctx.moveTo(cx, cy - gap - len)
 84   ctx.lineTo(cx, cy - gap)
 85   ctx.moveTo(cx, cy + gap)
 86   ctx.lineTo(cx, cy + gap + len)
 87 
 88   ctx.moveTo(cx - gap - len, cy)
 89   ctx.lineTo(cx - gap, cy)
 90   ctx.moveTo(cx + gap, cy)
 91   ctx.lineTo(cx + gap + len, cy)
 92   ctx.stroke()
 93 }
 94 
 95 //更新位置
 96 function updatedPosition() {
 97   //自己移动
 98   players.forEach(player => {
 99     if (player.name == myName) {
100       if (keys.w || keys.a || keys.s || keys.d) {
101         if (keys.w) player.y -= player.ySpeed
102         if (keys.s) player.y += player.ySpeed
103         if (keys.a) player.x -= player.xSpeed
104         if (keys.d) player.x += player.xSpeed
105         //发送自己新位置
106         ws.send(JSON.stringify({ type: "update", player: player }))
107       }
108     }
109   })
110   //子弹移动
111   bullets.forEach((bullet, index) => {
112     bullet.x += bullet.xSpeed
113     bullet.y += bullet.ySpeed
114     if (bullet.x < 0 || bullet.x > backgroundCanvas.value.width || bullet.y < 0 || bullet.y > backgroundCanvas.value.height) {
115       bullets.splice(index, 1)
116       console.log("已移除子弹")
117     }
118   })
119   //ws
120 }
121 //更新事件
122 function updateEvent() {
123 
124 }
125 //
126 function draw() {
127   //清空画布
128   ctx.clearRect(0, 0, backgroundCanvas.value.width, backgroundCanvas.value.height)
129 
130   players.forEach(player => {
131     player.draw()
132   })
133 
134   bullets.forEach(bullet => {
135     bullet.draw()
136   })
137   drawMouse()
138 }
139 //动画
140 function animate() {
141   updatedPosition()
142   updateEvent()
143   draw()
144   requestAnimationFrame(animate)
145 }
146 //初始化
147 onMounted(() => {
148   const canvas = backgroundCanvas.value
149   ctx = canvas.getContext("2d")
150 
151   ws = new WebSocket("ws://192.168.174.97:5000")
152 
153   ws.onopen = () => {
154     const player1 = new Player(0, 0, 60, 60, "red", 2, 2, myName)
155     players.push(player1)
156     ws.send(JSON.stringify({ type: "join", player: player1 }))
157     //绑定按键事件
158     window.addEventListener('keydown', keyDown)
159     window.addEventListener('keyup', keyUp)
160     window.addEventListener('mousemove', mouseMove)
161     window.addEventListener('mousedown', mouseDown)
162     //启动
163     animate()
164   }
165 
166   ws.onmessage = (res) =>{
167     const data = JSON.parse(res.data)
168     const type = data.type
169     const player = new Player(data.player.x,data.player.y,data.player.width,data.player.height,data.player.color,data.player.xSpeed,data.player.ySpeed,data.player.name)
170     if(type == "join"){
171       const index = players.findIndex(p => p.name == player.name )
172       if(index!=-1){
173         players[index] = player
174       }else{
175         players.push(player)
176       }
177     }else if(type == "update"){
178       const index = players.findIndex(p => p.name == player.name )
179       if(index!=-1){
180         players[index] = player
181       }else{
182         players.push(player)
183       }
184     }
185   }
186 
187 })
188 //玩家类
189 class Player {
190   constructor(x, y, width, height, color, xSpeed, ySpeed, name) {
191     this.x = x
192     this.y = y
193     this.width = width
194     this.height = height
195     this.color = color
196     this.xSpeed = xSpeed
197     this.ySpeed = ySpeed
198     this.name = name
199   }
200 
201   draw() {
202     ctx.fillStyle = this.color
203     ctx.fillRect(this.x - this.width / 2, this.y - this.height / 2, this.width, this.height)
204   }
205 
206 }
207 //子弹类
208 class Bullet {
209   constructor(x, y, width, height, color, xSpeed, ySpeed, angle, from) {
210     this.x = x
211     this.y = y
212     this.width = width
213     this.height = height
214     this.color = color
215     this.xSpeed = xSpeed
216     this.ySpeed = ySpeed
217     this.angle = angle
218     this.from = from
219   }
220 
221   draw() {
222     ctx.fillStyle = this.color
223     ctx.fillRect(this.x - this.width / 2, this.y - this.height / 2, this.width, this.height)
224   }
225 }
226 </script>
227 
228 <style scoped>
229 .CanvasContainer {
230   display: flex;
231   width: 100vw;
232   height: 100vh;
233   background-color: #000;
234   align-items: center;
235   justify-content: center;
236 }
237 
238 canvas {
239   background-color: #000333;
240   border: red solid 2px;
241   cursor: none;
242 }
243 </style>

这是node.js后端:app.js

 1 const express = require('express');
 2 const WebSocket = require('ws')
 3 const cors = require('cors');
 4 const app = express();
 5 
 6 app.use(express.json());
 7 app.use(cors());
 8 
 9 const server = app.listen(5000, () => {
10     console.log(`服务运行在 http://localhost:5000`);
11 });
12 
13 const wss = new WebSocket.Server({server})
14 
15 let players = []
16 let bullets = []
17 
18 wss.on('connection', ws => {
19     console.log("新玩家加入游戏")
20 
21     ws.on('message',res => {
22         const data = JSON.parse(res);
23         const player = data.player
24         const type = data.type
25         //判断类型后操作
26         if(type == "join"){
27             //新添玩家
28             players.push(player)
29         }else if(type == "update"){
30             //寻找符合条件的玩家
31             const index = players.findIndex(p => p.name == player.name)
32             if(index != -1) {
33                 //更新玩家
34                 players[index] = player
35             }
36         }
37         //广播玩家信息
38         if(type =="join"||type == "update"){
39             wss.clients.forEach(client => {
40                 if(client.readyState == WebSocket.OPEN) {
41                     if(type == "join"){
42                         client.send(JSON.stringify({type:"join",player:player}))
43                     }else if(type == "update"){
44                         client.send(JSON.stringify({type:"update",player:player}))
45                     }
46                 }
47             })
48         }
49     })
50 })

接下来的几天也再接再厉

posted @ 2026-04-19 23:07  Leeszz  阅读(16)  评论(0)    收藏  举报