如何根据另一物体的旋转角度和位置来旋转一个物体?

huangapple go评论89阅读模式
英文:

How do I rotate one thing in relation to the rotation angle and position of another thing?

问题

这是一个简单的Canvas JS游戏开发项目。你正在创建一个生物体,它将拥有多个身体部分。目前,你只有两个身体部分,它们都是圆形,可以将它们想象成头部和身体。当你生成这个生物体时,身体部分位于头部的后方。你正在尝试让每个生物体的身体部分正确旋转。目前,你已经让身体部分旋转以面向鼠标,但需要使身体部分在旋转时紧贴在头部后面。

这里是被创建的对象:

this.testCreature = new TestingRotation([new BodyTest(2000, 2000, 100, 100), new BodyTest(2000, 2100, 100, 100)])

这里是位于TestingRotation类中的旋转函数:

rotate(movement, cameraX, cameraY) {
    if (movement.mousedown && movement.mousemove) {
      const mouseX = movement.mouseX;
      const mouseY = movement.mouseY;

      this.bodyParts.forEach(bodypart => {
        console.log(bodypart.rotationAngle)
        if (bodypart === this.bodyParts[0]) {
          const centerX = bodypart.x + bodypart.width / 2;
          const centerY = bodypart.y + bodypart.height / 2;

          const deltaX = mouseX - centerX;
          const deltaY = mouseY - centerY;

          bodypart.targetRotationAngle = Math.atan2(deltaY, deltaX) - Math.PI / 2;  // 调整方向

          // 逐渐调整旋转角度以接近目标角度
          const diff = bodypart.targetRotationAngle - bodypart.rotationAngle;

          // 计算角度间的最短差异
          const shortestDiff = ((diff % (Math.PI * 2)) + (Math.PI * 2)) % (Math.PI * 2) - Math.PI;

          if (Math.abs(shortestDiff) > 0.01) {
            bodypart.rotationAngle += shortestDiff * this.rotationSpeed;
          }
        } else {
          const centerX = this.bodyParts[0].x + this.bodyParts[0].width / 2;
          const centerY = this.bodyParts[0].y + this.bodyParts[0].height / 2;

          const deltaX = mouseX - centerX;
          const deltaY = mouseY - centerY;

          bodypart.targetRotationAngle = Math.atan2(deltaY, deltaX) - Math.PI / 2;  // 调整方向

          // 逐渐调整旋转角度以接近目标角度
          const diff = bodypart.targetRotationAngle - bodypart.rotationAngle;

          // 计算角度间的最短差异
          const shortestDiff = ((diff % (Math.PI * 2)) + (Math.PI * 2)) % (Math.PI * 2) - Math.PI;

          if (Math.abs(shortestDiff) > 0.01) {
            bodypart.rotationAngle += shortestDiff * this.rotationSpeed;
          }
        }
      });
    }
  }
}

这是用于绘制身体部分的类:

export class BodyTest {
    constructor(x, y, width, height) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
      this.rotationAngle = 0; // 添加旋转属性
      this.targetRotationAngle = 0;
    }
  
    getBodyPos() {
      let x = this.x;
      let y = this.y;
      let radius = this.height / 2;
  
      return { x, y, radius };
    }
  
    draw(ctx) {
      const bodyPos = this.getBodyPos();
      const centerX = bodyPos.x;
      const centerY = bodyPos.y;
      const radius = bodyPos.radius;
  
      ctx.save(); // 保存当前绘图状态
      ctx.translate(centerX, centerY); // 平移到身体部分的中心
      ctx.rotate(this.rotationAngle); // 应用旋转
  
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.arc(0, 0, radius, 0, Math.PI * 2);
      ctx.closePath();
      ctx.fillStyle = 'purple';
      ctx.fill();

      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.arc(0, -30, 5, 0, Math.PI * 2);
      ctx.closePath();
      ctx.fillStyle = 'orange';
      ctx.fill();
  
      ctx.restore(); // 恢复之前的绘图状态
    }
  }
}
英文:

So I am working on a simple canvas js game. I have a creature that is going to have multiple bodyparts. Right now I just have two bodyparts and they are both circles, think of them as a head and body. When I spawn the creature the body is positioned directly behind the head. I am trying to make each bodypart of the creature rotate correctly. Currently I have the bodyparts rotating to face the mouse, but I need the body to stick to the back of the head as they rotate to face the mouse.

Here is the object being created:

this.testCreature = new TestingRotation([new BodyTest(2000, 2000, 100, 100), new BodyTest(2000, 2100, 100, 100)])

Here is the rotate function that lives in the TestingRotation class:


rotate(movement, cameraX, cameraY) {
if (movement.mousedown && movement.mousemove) {
const mouseX = movement.mouseX;
const mouseY = movement.mouseY;
this.bodyParts.forEach(bodypart => {
console.log(bodypart.rotationAngle)
if(bodypart == this.bodyParts[0]){
const centerX = bodypart.x + bodypart.width / 2
const centerY = bodypart.y + bodypart.height / 2
const deltaX = mouseX - centerX;
const deltaY = mouseY - centerY;
bodypart.targetRotationAngle = Math.atan2(deltaY, deltaX) - Math.PI / 2;  // Adjusted orientation
// Gradually adjust the rotation angle towards the target angle
const diff = bodypart.targetRotationAngle - bodypart.rotationAngle
// Calculate the shortest difference in angles
const shortestDiff = ((diff % (Math.PI * 2)) + (Math.PI * 2)) % (Math.PI * 2) - Math.PI;
if (Math.abs(shortestDiff) > 0.01) {
bodypart.rotationAngle += shortestDiff * this.rotationSpeed;
}
}
else{
const centerX = this.bodyParts[0].x + this.bodyParts[0].width / 2
const centerY = this.bodyParts[0].y + this.bodyParts[0].height / 2
const deltaX = mouseX - centerX;
const deltaY = mouseY - centerY;
bodypart.targetRotationAngle = Math.atan2(deltaY, deltaX) - Math.PI / 2;  // Adjusted orientation
// Gradually adjust the rotation angle towards the target angle
const diff = bodypart.targetRotationAngle - bodypart.rotationAngle
// Calculate the shortest difference in angles
const shortestDiff = ((diff % (Math.PI * 2)) + (Math.PI * 2)) % (Math.PI * 2) - Math.PI;
if (Math.abs(shortestDiff) > 0.01) {
bodypart.rotationAngle += shortestDiff * this.rotationSpeed;
}
}
});
}
}

And here is the class that draws the bodyparts:

export class BodyTest {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.rotationAngle = 0; // Add the rotation property
this.targetRotationAngle = 0;
}
getBodyPos() {
let x = this.x;
let y = this.y;
let radius = this.height / 2;
return { x, y, radius };
}
draw(ctx) {
const bodyPos = this.getBodyPos();
const centerX = bodyPos.x 
const centerY = bodyPos.y 
const radius = bodyPos.radius;
ctx.save(); // Save the current drawing state
ctx.translate(centerX, centerY); // Translate to the center of the body part
ctx.rotate(this.rotationAngle); // Apply the rotation
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fillStyle = 'purple';
ctx.fill();
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(0, -30, 5, 0, Math.PI * 2);
ctx.closePath();
ctx.fillStyle = 'orange';
ctx.fill();
ctx.restore(); // Restore the previous drawing state
}
}

答案1

得分: 0

我无法完全理解问题是什么,但是通过数学,相对于另一个对象进行旋转相当容易。

以下是一个示例,演示了几种执行此操作的选项。首先在演示中只是使用角度和相对于目标的距离来计算最终位置。接下来,我将描述如何仅根据先前的位置和目标计算新位置。

<canvas id="canvas"></canvas>

这是相对于先前位置的方法(可能是您想要的):

const processMain = () => {
  const phi = Math.atan2(main.y - target.y, main.x - target.x) + 0.01;
  const dist = Math.hypot(main.y - target.y, main.x - target.x);
  main.x = target.x + Math.cos(phi) * dist;
  main.y = target.y + Math.sin(phi) * dist;
  return main;
}

您还可以使main对象相对于目标进行旋转:

const processMain = () => {
  const phi = Math.atan2(main.y - target.y, main.x - target.x) + 0.01;
  const dist = Math.hypot(main.y - target.y, main.x - target.x);
  main.angle += 0.01; // 或者只需 `main.angle = phi;`
  main.x = target.x + Math.cos(phi) * dist;
  main.y = target.y + Math.sin(phi) * dist;
  return main;
}

您还可以使用 canv 这个小型库来处理所有这些问题。这允许您将画布视为带有对象的空间。您可以将一些对象设置为其他对象的子对象,等等。请查看它的 演示 页面,了解您可以做什么。

英文:

I can't fully understand what's the problem but rotating relative to another object is pretty easy with math.

Here is an example which demonstrates several options to do it. First in demo is just using angle and distance relative to target and calculating final position. Further I will describe calculating new position only from previous position and target.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const canvas = document.getElementById(&quot;canvas&quot;);
const ctx = canvas.getContext(&quot;2d&quot;);
const pr = window.devicePixelRatio;
canvas.width = canvas.clientWidth * pr;
canvas.height = canvas.clientHeight * pr;
const target = {
x: 100*pr, 
y: 100*pr, 
s: 8*pr,
angle: 1,
color: &quot;#f59&quot;
};
const main = {
x: 140 * pr,
y: 120 * pr,
angle: 0,
dist: 50,
phi: 0,
s: 10*pr,
color: &quot;#5fb&quot;
};
const drawObj = (ctx, o) =&gt; {
ctx.save();
ctx.translate(o.x, o.y);
ctx.rotate(o.angle);
ctx.fillStyle = o.color;
ctx.fillRect(-o.s, -o.s, o.s * 2, o.s * 2);
ctx.restore();
}
const processMain = () =&gt; {
main.phi = (Date.now() / 1000) % (Math.PI * 2);
main.x = target.x + Math.cos(main.phi) * main.dist;
main.y = target.y + Math.sin(main.phi) * main.dist;
return main;
}
const draw = () =&gt; {
ctx.fillStyle = &#39;#333&#39;;
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawObj(ctx, target);
drawObj(ctx, processMain());
requestAnimationFrame(draw);
}
draw();

<!-- language: lang-css -->

#canvas {
width: 200px;
height: 200px;
border: 1px #aaa solid;
}

<!-- language: lang-html -->

&lt;canvas id=&quot;canvas&quot;&gt;&lt;/canvas&gt;

<!-- end snippet -->

This is relative to previous position (probably what you want)

const processMain = () =&gt; {
  const phi = Math.atan2(main.y - target.y, main.x - target.x) + 0.01;
  const dist = Math.hypot(main.y - target.y, main.x - target.x);
  main.x = target.x + Math.cos(phi) * dist;
  main.y = target.y + Math.sin(phi) * dist;
  return main;
}

You also can make main object to be rotated with orientation to target.

const processMain = () =&gt; {
  const phi = Math.atan2(main.y - target.y, main.x - target.x) + 0.01;
  const dist = Math.hypot(main.y - target.y, main.x - target.x);
  main.angle += 0.01; // or just `main.angle = phi;`
  main.x = target.x + Math.cos(phi) * dist;
  main.y = target.y + Math.sin(phi) * dist;
  return main;
}

See this codepen

You also can use canv tiny library to work with all this problems. This allows you to control your canvas as space with objects. You can set some objects to be children of other and much more. See it's demo page to see what you can do.

huangapple
  • 本文由 发表于 2023年6月26日 10:28:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76553207.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定