如何解决Javascript画布将图像附加到其他图像
我正在使用Node JS和Socket io制作2D多人剑术。 我有后端工作,但在前端我无法将剑固定在播放器上。 我希望它像 Sword is attached to player
但是问题是,当我移动鼠标时,剑会发生变化并且移到播放器外面。 Sword is not attached to player。因此,如果您想知道我的游戏的工作原理,基本上笑脸(玩家)总是指向鼠标(是的,它可能会颠倒过来),并且您可以使用箭头键移动玩家并使用剑杀死其他玩家。
这是我绘制玩家和剑的代码。
function drawImageLookat(img,x,y,lookx,looky){
ctx.setTransform(1,1,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); // 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.looky)
}
};
socket.on('state',(gameState) => {
ctx.clearRect(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',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',1000 / 60);
http.listen(3000,() => {
console.log('listening on *:3000');
});
//Client/Index.html
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,() => {
console.log('listening on *:3000');
});
//Client/Assets/Js/script.js
var socket = io();
var canvas = document.getElementById("game");
const ctx = canvas.getContext("2d")
document.getElementById("game").width =1200;
document.getElementById("game").height = 700;
socket.emit('newPlayer');
//mouse stuff
function drawImageLookat(img,700)
for (let player in gameState.players) {
drawPlayer(gameState.players[player])
}
})
//Client/assets/js/Controller.js
//v1
var canvas = document.getElementById("game")
const playerMovement = {
up: false,down: false,left: false,right: false
};
const keyDownHandler = (e) => {
if (e.keyCode == 39 || e.keyCode == 68) {
playerMovement.right = true;
} else if (e.keyCode == 37 || e.keyCode == 65) {
playerMovement.left = true;
} else if (e.keyCode == 38 || e.keyCode == 87) {
playerMovement.up = true;
} else if (e.keyCode == 40 || e.keyCode == 83) {
playerMovement.down = true;
}
};
const keyUpHandler = (e) => {
if (e.keyCode == 39 || e.keyCode == 68) {
playerMovement.right = false;
} else if (e.keyCode == 37 || e.keyCode == 65) {
playerMovement.left = false;
} else if (e.keyCode == 38 || e.keyCode == 87) {
playerMovement.up = false;
} else if (e.keyCode == 40 || e.keyCode == 83) {
playerMovement.down = false;
}
};
document.addEventListener('keydown',keyDownHandler,false);
document.addEventListener('keyup',keyUpHandler,false);
//mouse stuf
var pos = 0;
document.addEventListener("mousemove",1000 / 60);
如果您能帮助我,谢谢!
解决方法
有很多方法可以做到这一点。标准方法是使用第二个转换并将其与当前上下文转换相乘。
2D矩阵乘法
2d API具有两个用于输入矩阵以更改当前变换的函数。
-
ctx.setTransform
用新的替换当前的转换 -
ctx.transform
将当前变换乘以新设置,将当前变换乘以结果矩阵。
这使您可以将图像元素附加到分层转换结构中。 (树状结构)
ctx.setTransform
用于设置根变换,而您使用ctx.transform
附加一个子对象,该子对象也继承了先前的变换,并且已经获得了辅助变换。
假设您有一个可以像处理一样变换的图像
ctx.setTransform(1,1,x,y);
ctx.rotate(Math.atan2(looky - y,lookx - x));
ctx.drawImage(img,-img.width / 2,-img.height / 2);
原点位于图像的中心
要附加其他图像,例如,第二个图像位于现有图像的右下角中心,并将与现有图像一起旋转(缩放,平移,倾斜,镜像等)。
只需创建相对于当前变换(上一个图像)的第二个变换,然后使用ctx.transform
进行矩阵乘法,然后渲染第二个图像
ctx.transform(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,-img.height / 2);
ctx.save();
// draw second image
ctx.transform(1,img.height / 2);
ctx.drawImage(img2,-img2.height / 2);
ctx.restore(); // get the parent transform
// draw 3rd image at top right
ctx.transform(1,-img.height / 2);
ctx.drawImage(img3,-img3.width / 2,-img3.height / 2);
对于简单的渲染来说还可以,但是对于更复杂的渲染可能会很慢或不方便。
DOMMatrix
您可以使用DOMMatrix
而不是使用内置的转换,因为它提供了执行所有标准矩阵数学的功能。
例如,前面的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,y];
const child1Matrix = new DOMMatrix([1,img.height / 2]);
const child2Matrix = new DOMMatrix([1,-img.height / 2]);
// draw first image with root transform
ctx.setTransform(...parentMatrix);
ctx.drawImage(img,-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.height / 2);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。