You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让多图形组成的火鸡围绕自身中心旋转?(p5.js)

让组合图形围绕统一中心点旋转的解决方案

问题背景

需求:通过左右箭头键触发旋转,让由多个形状组成的火鸡围绕自身中心点旋转,位置保持不变,仅做纯粹旋转。
当前问题:火鸡围绕随机点旋转,无法统一旋转原点。

核心解决方案

要实现统一中心旋转,必须将整个火鸡的所有绘制操作纳入同一个绘图上下文,避免每个形状单独平移旋转。具体步骤:

  • 给火鸡实例添加rotation属性,记录当前旋转角度
  • 绘制火鸡时,先平移到火鸡的中心点(这里选用身体椭圆的位置作为中心),再统一应用旋转,所有形状都以原点(0,0)为基准绘制
  • 通过键盘事件修改rotation值,控制旋转方向和速度

修改后的完整代码

let bubbles = [];

function setup() {
  createCanvas(windowWidth, windowHeight);
  angleMode(DEGREES);
}

function mouseDragged() {
  bubbles.pop();
}

function mousePressed() {
  let d = random(0.5, 1.5);
  let w = random(50, 180);
  let b = new Bubble(mouseX, mouseY, d, w);
  bubbles.push(b);
}

function draw() {
  background(255);
  for (let bubble of bubbles) {
    bubble.move();
    bubble.show();
  }
}

function keyPressed() {
  // 控制所有火鸡旋转
  for (let bubble of bubbles) {
    if (keyCode === LEFT_ARROW) {
      bubble.rotation -= 2;
    } else if (keyCode === RIGHT_ARROW) {
      bubble.rotation += 2;
    }
  }
}

class Bubble {
  constructor(x, y, d, w) {
    this.x = x;
    this.y = y;
    this.d = d;
    this.w = w;
    this.speedX = random(-15, 15);
    this.speedY = random(-15, 15);
    this.rotation = 0; // 新增旋转角度属性
  }

  move() {
    if (this.x > width - this.w/1.08/2 || this.x < 0 + this.w/1.08/2) {
      this.speedX = -this.speedX;
      this.speedX *= 1.1;
    }

    if (this.y > height - this.w/1.05 || this.y < 0 + this.w/2/2) {
      this.speedY = -this.speedY;
      this.speedY *= 1.1;
    }

    this.x += this.speedX;
    this.y += this.speedY;
  }

  show() {
    push();
    // 平移到火鸡的中心点(身体椭圆的位置)
    translate(this.x, this.y + this.w/2.11);
    // 应用统一旋转
    rotate(this.rotation);
    
    // 所有形状都以(0,0)为基准绘制
    // 左橙色羽毛
    push();
    translate(this.w/5, -this.w/2.11 + this.w/8);
    rotate(25);
    fill(255,153,51);
    ellipseMode(CENTER);
    ellipse(0, 0, this.w/1.67, this.w/0.67);
    pop(); 

    // 右橙色羽毛
    push();
    translate(-this.w/5, -this.w/2.11 + this.w/8);
    rotate(-25);
    fill(255,153,51);
    ellipseMode(CENTER);
    ellipse(0, 0, this.w/1.67, this.w/0.67);
    pop(); 

    // 右红色羽毛
    push();
    translate(this.w/2, -this.w/2.11 + this.w/5);
    rotate(60);
    fill(255,0,0);
    ellipseMode(CENTER);
    ellipse(0, 0, this.w/1.67, this.w/0.67);
    pop();

    // 左红色羽毛
    push();
    translate(-this.w/2, -this.w/2.11 + this.w/5);
    rotate(-60);
    fill(255,0,0);
    ellipseMode(CENTER);
    ellipse(0, 0, this.w/1.67, this.w/0.67);
    pop();

    // 黄色羽毛
    fill(255,204,0);   
    ellipse(0, -this.w/2.11 + this.w/20, this.w/1.67, this.w/0.67);

    // 左棕色羽毛
    push();
    translate(-this.w/2, -this.w/2.11 + this.w/1.67);
    rotate(10);
    fill(78,39,0);
    ellipse(0, 0, this.w/0.8, this.w/1.67);
    pop();

    // 右棕色羽毛
    push();
    translate(this.w/2, -this.w/2.11 + this.w/1.67);
    rotate(-10);
    fill(78,39,0);
    ellipse(0, 0, this.w/0.8, this.w/1.67);
    pop();

    // 身体
    fill(153, 102, 51, 255);
    ellipse(0, 0, this.w/1.08, this.w/1.08);
    // 头部
    ellipse(0, -this.w/2.11, this.w/2, this.w/2);

    // 眼睛
    fill(255);
    ellipse(-this.w/10, -this.w/2.11 - this.w/20, this.w/6.67*this.d, this.w/6.67*this.d);
    ellipse(this.w/10, -this.w/2.11 - this.w/20, this.w/6.67*this.d, this.w/6.67*this.d);

    // 瞳孔
    fill(0);
    ellipse(-this.w/11.77, -this.w/2.11 - this.w/28.57, this.w/13.33*this.d, this.w/13.33*this.d);
    ellipse(this.w/8.7, -this.w/2.11 - this.w/28.57, this.w/13.33*this.d, this.w/13.33*this.d);

    // 肉垂
    fill(255, 0, 0);
    ellipse(-this.w/20, -this.w/2.11 + this.w/5, this.w/10, this.w/5);
    // 喙
    fill(255,153,51);
    triangle(0, -this.w/2.11 + this.w/3.33, -this.w/10, -this.w/2.11 + this.w/10, this.w/10, -this.w/2.11 + this.w/10);

    // 左脚
    triangle(-this.w/13.33, -this.w/2.11 + this.w/1.05, -this.w/3.08, -this.w/2.11 + this.w/1.05, -this.w/13.33, -this.w/2.11 + this.w/1.29);
    // 右脚
    triangle(this.w/13.33, -this.w/2.11 + this.w/1.05, this.w/3.08, -this.w/2.11 + this.w/1.05, this.w/13.33, -this.w/2.11 + this.w/1.29);

    // 左翅膀
    push();
    translate(-this.w/2.22, -this.w/2.11 + this.w/2.22);
    rotate(30);
    fill(218,180,142);
    ellipse(0, 0, this.w/3.64, this.w/1.67);
    pop(); 

    // 右翅膀
    push();
    translate(this.w/2.22, -this.w/2.11 + this.w/2.22);
    rotate(-30);
    fill(218,180,142);
    ellipse(0,0, this.w/3.64, this.w/1.67);
    pop();

    pop();
  }
}

关键修改说明

  1. 统一旋转上下文:将火鸡所有绘制代码放入外层push()/pop(),先平移到身体中心,再统一旋转
  2. 坐标基准调整:所有形状的坐标从基于this.x/this.y改为基于(0,0),通过相对偏移实现原位置布局
  3. 旋转控制:新增rotation属性和keyPressed()函数,通过左右箭头调整旋转角度
  4. 修复原代码小问题:修正mouseDragged()的错误写法,调整speedX/speedY的随机范围(原代码是固定15)

内容的提问来源于stack exchange,提问作者user21270064

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 20:24:53