微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何转换鼠标 X、Y 坐标以在容器旋转到某个角度的容器内移动 HTML 元素

如何解决如何转换鼠标 X、Y 坐标以在容器旋转到某个角度的容器内移动 HTML 元素

我正在开发一个 HTML 格式的纸牌游戏,向所有玩家显示实时视角和纸牌移动。

所有播放器都通过socket.io连接。

背景:

如果有 4 个玩家,则桌子是方形的,并且桌子 HTML 正文根据玩家在屏幕上的位置旋转。

结构是这样的:

<gaMetable style=”position: relative;”> 

<card style=”position: absolute; top: 1%,left: 1%;”></card> 

</gaMetable > 

现在为了移动卡片,玩家用鼠标选择一张卡片

1:保存该位置

2:基于移动,将卡片的移动(以px为单位)转换成相对相等的百分比,然后将桌面上的卡片移动那么多。

这样无论是大屏还是小屏,使用%作为上、左坐标,卡片移动对所有人都是一样的。

-- 方桌:

当玩家处于0度桌位时,鼠标和卡片的移动是直接联动的。

卡片顶部: --mouse y,卡片左侧:--mouse x

当玩家处于 180 度桌面位置时,鼠标移动反向:

卡片顶部: ++mouse y卡片左侧: ++mouse x

对于 90 度:

卡片顶部: ++mouse x卡片左侧: --mouse y

270 度旋转台的类似平移,坐标变化很小。

这和这个翻译一样完美,它完美地翻译了代码中所有方向的鼠标。

问题:

对于 6 人游戏,我想使用 六角形 表。现在在这个表中,玩家表旋转到:

0、60、120、180、240 和 300 度。

0180 度数很好,但我无法找出正确的公式来翻译鼠标基于旋转的坐标到卡片坐标。

-- 当前解决方(不好)

目前,我做了一些蛮力编程,是这样的:(60 度表)

如果(鼠标向上/向下移动){

卡片顶部:--mouse y/1.7,卡片左侧:--mouse y

}

如果(鼠标向左/向右移动){

卡片顶部:++mouse x,卡片左侧:--mouse x/1.7

}

hexa 表上其他位置的类似方法,但变化很小。

这是蛮力方法,它阻止我从上/下移动过渡到左/右状态,因为我必须离开鼠标然后重新开始。

简而言之,它不起作用,我想知道是否有可能有一个公式可以根据旋转将鼠标的鼠标坐标正确转换为卡片。

请查看以下图片以直观表达我的意思

Square Table

Hexa Table

解决方法

tl;dr 看到这个 JSFiddle

要从四名球员转变为六名球员,您必须了解构成四名球员情况的数学原理,然后将其应用于六名球员情况。

四人案例

您可以将每个玩家的位置视为原点在桌子中心的圆周围的给定度数(或弧度)。在四个玩家的情况下,第一个玩家(索引 0)将在 0 度,第二个玩家将在 90 度,依此类推。

要确定一个玩家的移动如何影响另一个人屏幕上不同角度的卡片的移动,您需要根据其基础分解卡片的移动。在这种情况下,基础由定义当前玩家移动空间的两个正交向量组成。第一个向量是使用角度生成的向量。可以通过获取当前角度并添加 90 度(Pi/2 弧度)来找到第二个向量。对于四个玩家的情况,第一个玩家的主基向量为 0 度,即 (1,0)。第一个玩家的辅助基向量将是 0+90=90 度,即 (0,1)。

要将鼠标移动(增量屏幕 x 和 y)转换为使用任意基的移动,您需要计算增量屏幕 x 和 y 以及基中每个向量的 x 和 y 的点积。在四人游戏的情况下,当第一个玩家移动一张牌时,主要和次要基础的点积分别导致 x delta 和 y delta。

为当前玩家计算此值后,您可以根据其基础移动其他玩家屏幕上的卡片。为此,将已转换为沿两个基地的运动的运动应用到其他玩家的基础上。在四人的情况下,第二个球员的主要基础是 90 度 = (1,0),次要基础是 90+90 度 = (-1,0)。因此,为了反映第二个玩家位置的移动,将原来的 x 移动转换为 y 移动,将原来的 y 移动转换为 -x 移动。

六个(或任意数量)的玩家

要将其更改为具有任意数量玩家且第 1 个玩家可能偏离 0 度的游戏,您需要遵循相同的数学计算。首先,计算每个玩家的基数。其次,使用点积来计算卡片在其基础上移动的增量。第三,将这个动作应用到其他玩家的基地。

以下示例可让您更改玩家数量和起始偏移角度。卡片是 div,并且有一个画布叠加在 div 上,以显示每个基础的主轴(红色)和辅助轴(蓝色)。

<div>
<div class="table-div">
</div>
<div>
  This example shows how the current players card (blue) can be shown moving on other players' (red "ghost" cards).
  Below you
  can change the number of players and the angle offset of the starting player.
</div>
<div>
  <p>Players</p>
  <input type="text" onchange="playerChange()" id="playerText" value="6">
</div>
<div>
  <p>Angle (Degrees)</p>
  <input type="text" onchange="angleChange()" id="angleText" value="45">
</div>
<canvas id="canv"></canvas>
body {
  margin: 0;
}

canvas {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 9;
}

.table-div {
  background-color: lightgreen;
  width: 400px;
  height: 400px;
}

.card {
  position: absolute;
  width: 50px;
  height: 70px;
}

.current {
  background-color: blue;
}

.ghost {
  background-color: red;
}
//A simple class to hold an x,y pair
class Vector2 {
  constructor(x,y) { [this.x,this.y] = [x,y] }
}

//Set up our parameters
let playerCount = 6; //Can be changed by the user
let offsetAngle = 45; //Can be changed by the user
let width = 400;
let height = width;
let radius = width / 2;
let cardWidth = 50;
let cardHeight = 50 * 1.4;//~70
let cards;

//Track the mouse
let lastMouse = null;
let currentMouse = null;
let mouseDown = false;

//The angle in radians between each player on the table
let angleDelta;

//Grab the table div
let tableElement = document.querySelector(".table-div");
let canvas = document.querySelector("canvas")
let ctx = canvas.getContext("2d");
canvas.style.width = width + "px";
canvas.style.height = height + "px"
canvas.width = width;
canvas.height = height;

function update() {
  ctx.clearRect(0,width,height);

  for (let i = 0; i < playerCount; i++) {
    //Draw the first axis
    ctx.strokeStyle = "red";
    ctx.beginPath();
    ctx.moveTo(radius,radius);
    ctx.lineTo(radius + Math.cos(angleDelta * i + offsetAngle) * radius,radius + Math.sin(angleDelta * i + offsetAngle) * radius)
    ctx.stroke();

    //Draw the second axis
    let secondAxisAngle = angleDelta * i + Math.PI / 2;
    let startX = radius + Math.cos(angleDelta * i + offsetAngle) * radius / 2;
    let startY = radius + Math.sin(angleDelta * i + offsetAngle) * radius / 2;
    let endX = Math.cos(secondAxisAngle + offsetAngle) * radius / 4;
    let endY = Math.sin(secondAxisAngle + offsetAngle) * radius / 4;

    ctx.strokeStyle = "green";
    ctx.beginPath();
    ctx.moveTo(startX,startY)
    ctx.lineTo(startX + endX,startY + endY)
    ctx.stroke();
  }
}

document.body.addEventListener("mousemove",e => {
  //Keep track of the last mouse position so we can calculate a delta
  lastMouse = currentMouse;
  currentMouse = new Vector2(e.clientX,e.clientY);
  if (lastMouse && mouseDown) {
    let mouseDelta = new Vector2(currentMouse.x - lastMouse.x,currentMouse.y - lastMouse.y);
    if (mouseDown) {
      //Determine the movement in the current player's basis
      let primaryAxisCurrent = new Vector2(Math.cos(angleDelta * 0 + offsetAngle),Math.sin(angleDelta * 0 + offsetAngle))
      let secondAxisCurrent = new Vector2(Math.cos(angleDelta * 0 + Math.PI / 2 + offsetAngle),Math.sin(angleDelta * 0 + Math.PI / 2 + offsetAngle))
      //Determine the movement in terms of the primary axes
      let primary = (primaryAxisCurrent.x * mouseDelta.x + primaryAxisCurrent.y * mouseDelta.y)// * mouseDelta.x;
      let second = (secondAxisCurrent.x * mouseDelta.x + secondAxisCurrent.y * mouseDelta.y)// * mouseDelta.y;

      //Update all the cards using the primary and secondary motion
      for (let i = 0; i < playerCount; i++) {
        //Get the axes for this card
        let primaryAxis = new Vector2(Math.cos(angleDelta * i + offsetAngle),Math.sin(angleDelta * i + offsetAngle))
        let secondAxis = new Vector2(Math.cos(angleDelta * i + Math.PI / 2 + offsetAngle),Math.sin(angleDelta * i + Math.PI / 2 + offsetAngle))
        //Translate the motion into this card's axes
        let primaryAxisMovement = new Vector2(primaryAxis.x * primary,primaryAxis.y * primary)
        let secondAxisMovement = new Vector2(secondAxis.x * second,secondAxis.y * second)

        //Get the current location (strip the 'px') and add the change in position.
        let div = cards[i];
        let location = new Vector2(parseFloat(div.style.left) + primaryAxisMovement.x + secondAxisMovement.x,parseFloat(div.style.top) + primaryAxisMovement.y + secondAxisMovement.y)
        //Reappend 'px'
        div.style.left = location.x + "px"
        div.style.top = location.y + "px"
      }
    }
  }
})

document.body.addEventListener("mousedown",() => mouseDown = true)
document.body.addEventListener("mouseup",() => mouseDown = false)

function initDivs() {
  //Create all the cards
  cards = [];
  tableElement.innerHTML = "";
  for (let i = 0; i < playerCount; i++) {
    let div = document.createElement("div");
    tableElement.appendChild(div);
    div.classList.add("card")
    if (i == 0) div.classList.add("current")
    else div.classList.add("ghost")

    let radians = angleDelta * i;
    div.style.left = (radius - cardWidth / 2 + Math.cos(radians + offsetAngle) * (radius - cardWidth / 2)) + "px";
    div.style.top = (radius - cardHeight / 2 + Math.sin(radians + offsetAngle) * (radius - cardHeight / 2)) + "px"
    cards.push(div);
  }
}
function playerChange() {
  playerCount = +document.querySelector("#playerText").value;
  angleDelta = Math.PI * 2 / playerCount;
  initDivs();
  angleChange();
}
function angleChange() {
  //Convert from degrees to radians
  offsetAngle = parseFloat(document.querySelector("#angleText").value) * Math.PI / 180;
  initDivs();
  update();
}

playerChange();

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?