Javascript画布将图像附加到其他图像

Javascript画布将图像附加到其他图像,javascript,html,node.js,socket.io,html5-canvas,Javascript,Html,Node.js,Socket.io,Html5 Canvas,我正在使用NodeJS和Socket io制作一个2d多人剑术游戏。 我有后端工作,但在前端,我不能得到剑是附加在球员。 我希望它是这样的 但问题是,当我移动鼠标时,剑会发生变化并离开玩家。 . 所以,如果你想知道我的游戏是如何运作的,它基本上是微笑(玩家)总是指向鼠标(是的,它可能是颠倒的),你可以用箭头键移动玩家,用剑杀死其他玩家 这是我画玩家和剑的代码 function drawImageLookat(img, x, y, lookx, looky){ ctx.setTransfo

我正在使用NodeJS和Socket io制作一个2d多人剑术游戏。 我有后端工作,但在前端,我不能得到剑是附加在球员。 我希望它是这样的

但问题是,当我移动鼠标时,剑会发生变化并离开玩家。 . 所以,如果你想知道我的游戏是如何运作的,它基本上是微笑(玩家)总是指向鼠标(是的,它可能是颠倒的),你可以用箭头键移动玩家,用剑杀死其他玩家

这是我画玩家和剑的代码

function drawImageLookat(img, x, y, lookx, looky){
   ctx.setTransform(1, 0, 0, 1, x, y);  // set scale and origin
   ctx.rotate(Math.atan2(looky - y, lookx - x)); // set angle
   ctx.drawImage(img,-img.width / 2, -img.height / 2); // draw image
   ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default not needed if you use setTransform for other rendering operations
}

const drawPlayer = (player) => {
    const img = new Image()
    const img2 = new Image()

img.src = "./assets/images/player.png"
img2.src = "./assets/images/sword.png"
img.onload = () => {
drawImageLookat(img, player.x, player.y, player.lookx, player.looky)
drawImageLookat(img2, player.x+50, player.y, player.lookx, player.looky)
}

  };

  socket.on('state', (gameState) => {
      ctx.clearRect(0,0, 1200, 700)
    for (let player in gameState.players) {
      drawPlayer(gameState.players[player])
    }
  })
基本上,这种“状态”在游戏状态下每秒会发出60次。在游戏状态中,我们有玩家对象,它包含LookX(鼠标X位置)、LookY(鼠标Y位置)以及玩家的X和Y。下面的代码位于服务器端

const gameState = {
  players: {}
}

io.on('connection', (socket) => {
  socket.on('newPlayer', () => {
    gameState.players[socket.id] = {
      x: 250,
      y: 250,
      lookx: 0,
      looky: 0,
      width: 25,
      height: 25
    }
  })
//More stuff below here which is skipped
setInterval(() => {
  io.sockets.emit('state', gameState);
}, 1000 / 60);
同样在客户端,这里是我如何获得鼠标位置的

  //mouse stuf
  var pos = 0;
  document.addEventListener("mousemove", (e) => {
      pos = getMousePos(e)
  })
  
  function getMousePos(evt) {
      var rect = canvas.getBoundingClientRect();
      return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
      };
    }

//send 2 server
setInterval(() => {
    socket.emit('mouseAngle', pos);
    socket.emit('playerMovement', playerMovement);
  }, 1000 / 60);
所以基本上我想要的是,当我旋转鼠标时,玩家应该始终指向鼠标,剑附在玩家的侧面并随着它旋转。。。。 这是我的完整代码,如果你需要它

//SERVER.JS
var app = require('express')();
var express = require('express');
var path = require('path');
var http = require('http').createServer(app);
var io = require('socket.io')(http)

var htmlPath = path.join(__dirname, 'client');

app.use(express.static(htmlPath));

const gameState = {
  players: {}
}

io.on('connection', (socket) => {
  socket.on('newPlayer', () => {
    gameState.players[socket.id] = {
      x: 250,
      y: 250,
      lookx: 0,
      looky: 0,
      width: 25,
      height: 25
    }
  })

  socket.on('playerMovement', (playerMovement) => {
    const player = gameState.players[socket.id]
    const canvasWidth = 1200
    const canvasHeight = 700
    
    if (playerMovement.left && player.x > 0) {
      player.x -= 4
    }
    if (playerMovement.right && player.x < canvasWidth - player.width) {
    player.x += 4
  }
    
    if (playerMovement.up && player.y > 0) {
      player.y -= 4
    }
    if (playerMovement.down && player.y < canvasHeight - player.height) {
      player.y += 4
    }
  })

  socket.on("mouseAngle", (pos) => {
    const player = gameState.players[socket.id]
    player.lookx = pos.x;
    player.looky = pos.y;
  })

  socket.on("disconnect", () => {
    delete gameState.players[socket.id]
  })
})

setInterval(() => {
  io.sockets.emit('state', gameState);
}, 1000 / 60);




http.listen(3000, () => {
  console.log('listening on *:3000');
});

如果你能帮我,谢谢

有很多方法可以做到这一点。标准方法是使用第二个变换并将其与当前上下文变换相乘

二维矩阵乘法 2d API有两个函数用于输入矩阵以更改当前变换

  • 将当前变换替换为新变换
  • 将当前变换与新变换相乘,将当前变换设置为结果矩阵
  • 这使您可以在层次变换结构中附加图像元素。(树状结构)

    用于设置根变换,并用于附加继承上一个变换以及获取次变换的子级

    假设你有一个图像,你用它变换

       ctx.setTransform(1, 0, 0, 1, x, y);  
       ctx.rotate(Math.atan2(looky - y, lookx - x));
       ctx.drawImage(img,-img.width / 2, -img.height / 2);
    
    原点位于图像的中心

    要附加另一个图像,例如,第二个图像位于现有图像右下角的中心,并将与现有图像一起旋转(缩放、平移、倾斜、镜像等)

    只需创建第二个相对于当前变换(前一个图像)的变换,并使用它进行矩阵乘法,然后渲染第二个图像

       ctx.transform(1, 0, 0, 1, img.width / 2, img.height / 2);  // bottom right of prev image
       ctx.drawImage(img2, -img2.width / 2, -img2.height / 2);
    
    保存并恢复转换。 如果需要获取父变换,则需要保存并恢复2D API状态

       ctx.setTransform(1, 0, 0, 1, x, y);  
       ctx.rotate(Math.atan2(looky - y, lookx - x));
       ctx.drawImage(img,-img.width / 2, -img.height / 2);
       ctx.save();
    
       // draw second image
       ctx.transform(1, 0, 0, 1, img.width / 2, img.height / 2); 
       ctx.drawImage(img2, -img2.width / 2, -img2.height / 2);
    
       ctx.restore();  // get the parent transform
    
       // draw 3rd image at top right
       ctx.transform(1, 0, 0, 1, img.width / 2, -img.height / 2); 
       ctx.drawImage(img3, -img3.width / 2, -img3.height / 2);
    
    对于简单的渲染来说可以,但对于更复杂的渲染来说可能会很慢或不方便

    您可以使用
    dommatric
    而不是使用内置转换,因为它提供了执行所有标准矩阵数学的函数

    例如,前面的3个图像可以按如下方式完成

       const ang = Math.atan2(looky - y, lookx - x);
       const ax = Math.cos(ang);
       const ay = Math.sin(ang);
       const parentMatrix = [ax, ay, -ay, ax, x, y];
       const child1Matrix = new DOMMatrix([1, 0, 0, 1, img.width / 2, img.height / 2]);
       const child2Matrix = new DOMMatrix([1, 0, 0, 1, img.width / 2, -img.height / 2]);
    
    
       // draw first image with root transform
       ctx.setTransform(...parentMatrix);  
       ctx.drawImage(img,-img.width / 2, -img.height / 2);
    
       // draw second image at bottom right
       const mat1 = new DOMMatrix(...parentMatrix);
       matrix.multiplySelf(child1Matrix);
       ctx.setTransform(mat1.a, mat1.b, mat1.c, mat1.d, mat1.e, mat1.f);  
       ctx.drawImage(img1,-img1.width / 2, -img1.height / 2);
    
       // draw third image at top right
       const mat2 = new DOMMatrix(...parentMatrix);
       matrix.multiplySelf(child2Matrix);
       ctx.setTransform(mat2.a, mat2.b, mat2.c, mat2.d, mat2.e, mat2.f);  
       ctx.drawImage(img2,-img2.width / 2, -img2.height / 2);
    

    有很多方法可以做到这一点。标准方法是使用第二个变换并将其与当前上下文变换相乘

    二维矩阵乘法 2d API有两个函数用于输入矩阵以更改当前变换

  • 将当前变换替换为新变换
  • 将当前变换与新变换相乘,将当前变换设置为结果矩阵
  • 这使您可以在层次变换结构中附加图像元素。(树状结构)

    用于设置根变换,并用于附加继承上一个变换以及获取次变换的子级

    假设你有一个图像,你用它变换

       ctx.setTransform(1, 0, 0, 1, x, y);  
       ctx.rotate(Math.atan2(looky - y, lookx - x));
       ctx.drawImage(img,-img.width / 2, -img.height / 2);
    
    原点位于图像的中心

    要附加另一个图像,例如,第二个图像位于现有图像右下角的中心,并将与现有图像一起旋转(缩放、平移、倾斜、镜像等)

    只需创建第二个相对于当前变换(前一个图像)的变换,并使用它进行矩阵乘法,然后渲染第二个图像

       ctx.transform(1, 0, 0, 1, img.width / 2, img.height / 2);  // bottom right of prev image
       ctx.drawImage(img2, -img2.width / 2, -img2.height / 2);
    
    保存并恢复转换。 如果需要获取父变换,则需要保存并恢复2D API状态

       ctx.setTransform(1, 0, 0, 1, x, y);  
       ctx.rotate(Math.atan2(looky - y, lookx - x));
       ctx.drawImage(img,-img.width / 2, -img.height / 2);
       ctx.save();
    
       // draw second image
       ctx.transform(1, 0, 0, 1, img.width / 2, img.height / 2); 
       ctx.drawImage(img2, -img2.width / 2, -img2.height / 2);
    
       ctx.restore();  // get the parent transform
    
       // draw 3rd image at top right
       ctx.transform(1, 0, 0, 1, img.width / 2, -img.height / 2); 
       ctx.drawImage(img3, -img3.width / 2, -img3.height / 2);
    
    对于简单的渲染来说可以,但对于更复杂的渲染来说可能会很慢或不方便

    您可以使用
    dommatric
    而不是使用内置转换,因为它提供了执行所有标准矩阵数学的函数

    例如,前面的3个图像可以按如下方式完成

       const ang = Math.atan2(looky - y, lookx - x);
       const ax = Math.cos(ang);
       const ay = Math.sin(ang);
       const parentMatrix = [ax, ay, -ay, ax, x, y];
       const child1Matrix = new DOMMatrix([1, 0, 0, 1, img.width / 2, img.height / 2]);
       const child2Matrix = new DOMMatrix([1, 0, 0, 1, img.width / 2, -img.height / 2]);
    
    
       // draw first image with root transform
       ctx.setTransform(...parentMatrix);  
       ctx.drawImage(img,-img.width / 2, -img.height / 2);
    
       // draw second image at bottom right
       const mat1 = new DOMMatrix(...parentMatrix);
       matrix.multiplySelf(child1Matrix);
       ctx.setTransform(mat1.a, mat1.b, mat1.c, mat1.d, mat1.e, mat1.f);  
       ctx.drawImage(img1,-img1.width / 2, -img1.height / 2);
    
       // draw third image at top right
       const mat2 = new DOMMatrix(...parentMatrix);
       matrix.multiplySelf(child2Matrix);
       ctx.setTransform(mat2.a, mat2.b, mat2.c, mat2.d, mat2.e, mat2.f);  
       ctx.drawImage(img2,-img2.width / 2, -img2.height / 2);
    

    @CoderGataMyt抱歉,我刚刚注意到回答示例中有一个错误,前几个示例中的第二个和第三个
    drawImage
    调用使用了错误的图像大小来定位图像。我已经更新了答案来修正错误我如何得到剑的x和y?给科利森detection@CoderGautamYT剑心将第二个变换原点(如ctx.transform(1,0,0,1,img.width/2,img.height/2)的最后两个)乘以父(根)变换的逆变换。使用
    dommatric
    Answer的最后一段代码最简单,在底部添加
    parentMatrix.invertSelf();const pos=parentMatrix.transformPoint(新的DOMPoint(img.width/2,-img.height/2))
    新的
    `将画布x、y
    pos
    固定在剑的中央。。继续下一个评论。。。若要获得第二个img上的点坐标,请反转第二个变换并变换第二个图像上的点,从同一片段中,使用第二个矩阵<代码>mat2.invertSelf();常量位置=mat2.转换点(新点(-img2.width/2,-img2.height/2)将给出第二幅图像左上角的画布位置我没有使用DOMMARX,如何处理普通画布。感谢您的时间…这是我的回复…@codergautamy抱歉,我刚刚注意到答案示例中有一个错误,前几个示例中的第二个和第三个
    drawImage
    调用使用了错误的图像大小来定位im很久了。我已经更新了答案来修正错误。我如何得到剑的x和y?给科利森detection@CoderGautamYT剑心乘以第二个变换原点