对齐圆圈和球不反弹

问题描述 投票:1回答:1

我正在尝试在屏幕中央放置一个大圆圈,在右侧放置另外四个圆圈。我该如何实现?另外,右侧的小圆圈内应该有球反弹,每个圆圈内只有一个球,而不是几个。警报应该由较大的主要圈子触发。从小圈子来说,应该没有警报。我怎么解决这个问题?感谢您的帮助。预先感谢。

var noop = function() {
  return this;
};

function UserCanceledError() {
  this.name = 'UserCanceledError';
  this.message = 'User canceled dialog';
}
UserCanceledError.prototype = Object.create(Error.prototype);

function Dialog() {
  this.setCallbacks(noop, noop);
}
Dialog.prototype.setCallbacks = function(okCallback, cancelCallback) {
  this._okCallback     = okCallback;
  return this;
};
Dialog.prototype.waitForUser = function() {
  var _this = this;
  return new Promise(function(resolve, reject) {
    _this.setCallbacks(resolve, reject);
  });
};

Dialog.prototype.show = noop;
Dialog.prototype.hide = noop;

function PromptDialog() {
  Dialog.call(this);
  this.el           = document.getElementById('dialog');
  this.messageEl    = this.el.querySelector('.message');
  this.okButton     = this.el.querySelector('button.ok');
  this.attachDomEvents();
}
PromptDialog.prototype = Object.create(Dialog.prototype);
PromptDialog.prototype.attachDomEvents = function() {
  var _this = this;
  this.okButton.addEventListener('click', function() {
    _this.hide();
    console.log('Ok clicked!!');
  });
  
};
PromptDialog.prototype.show = function(message) {
  this.messageEl.innerHTML = '' + message;
  this.el.className = '';
  return this;
};
PromptDialog.prototype.hide = function() {
  this.el.className = 'hidden';
  return this;
};
const ctx = document.getElementById("Canvas").getContext("2d");
const containerR = 150;
const size = containerR * 2
ctx.canvas.width = ctx.canvas.height = size;
ctx.globalAlpha = 0.8;

//Adding fourcircles to the right
const ctx1 = document.getElementById("Canvas1").getContext("2d");
const ctx2 = document.getElementById("Canvas2").getContext("2d");
const ctx3 = document.getElementById("Canvas3").getContext("2d");
const ctx4 = document.getElementById("Canvas4").getContext("2d");
const containerR2 = 80;
const size2 = containerR2 * 2
ctx1.canvas.width = ctx1.canvas.height = size2;
ctx2.canvas.width = ctx2.canvas.height = size2;
ctx3.canvas.width = ctx3.canvas.height = size2;
ctx4.canvas.width = ctx4.canvas.height = size2;
ctx1.globalAlpha = 0.8;
ctx2.globalAlpha = 0.8;
ctx3.globalAlpha = 0.8;
ctx4.globalAlpha = 0.8;


var prompt = new PromptDialog();

const getBall = (x, y, dx, dy, r, color) => ({x, y, dx, dy, r, color});

const balls = [
  getBall(size / 2, size - 30, 0.1, 0.1, 8, "Green"),
  getBall(size / 3, size - 50, 0.1, 0.1, 8, "Green"),
  getBall(size / 4, size - 60, 0.1, 0.1, 8, "Green"),
  getBall(size / 2, size / 5,  0.1, 0.1, 8,  "Green"),
];

const drawBall = (ball) => {
  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
  ctx.fillStyle = ball.collider ? "red" : ball.color;
  ctx.fill();
  ctx.closePath();
  ctx1.beginPath();
  ctx1.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
  ctx1.fillStyle = ball.collider ? "red" : ball.color;
  ctx1.fill();
  ctx1.closePath();
  ctx2.beginPath();
  ctx2.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
  ctx2.fillStyle = ball.collider ? "red" : ball.color;
  ctx2.fill();
  ctx2.closePath();
  ctx3.beginPath();
  ctx3.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
  ctx3.fillStyle = ball.collider ? "red" : ball.color;
  ctx3.fill();
  ctx3.closePath();
  ctx4.beginPath();
  ctx4.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
  ctx4.fillStyle = ball.collider ? "red" : ball.color;
  ctx4.fill();
  ctx4.closePath();
}

const updatePos = (ball) => {

  ball.x += ball.dx;
  ball.y += ball.dy;
  const dx = ball.x - containerR;
  const dy = ball.y - containerR;

  if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
    const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
    const angleToCollisionPoint = Math.atan2(-dy, dx);
    const oldAngle = Math.atan2(-ball.dy, ball.dx);
    const newAngle = 2 * angleToCollisionPoint - oldAngle;
    ball.dx = -v * Math.cos(newAngle);
    ball.dy = v * Math.sin(newAngle);
  }
}


const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));

function engine() {
  //console.clear(); // Clear console test messages
  mydiv.textContent =" ";
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx1.clearRect(0, 0, ctx1.canvas.width, ctx1.canvas.height);
  ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);
  ctx3.clearRect(0, 0, ctx3.canvas.width, ctx3.canvas.height);
  ctx4.clearRect(0, 0, ctx4.canvas.width, ctx4.canvas.height);

  balls.forEach((a, ai) => {
    a.collider = undefined;
    
    balls.forEach((b, bi) => {
      if (bi === ai) return; // Don't look at self
      if (collides(a, b)) a.collider = b; // Store the colliding B ball
    });
    
    if (a.collider) { // If ball has a collider:
     //mydiv.textContent = ("Alert");
     beep();
     prompt.show('ALERT!!!!! Not Maintaining Distance')
      .waitForUser()
      .then(function(name) {
        output.innerHTML = '' + name;
      })
      .catch(function(e) {
        console.log('Unknown error', e);
      })
      .finally(function() {
        prompt.hide();
      });
      
      //console.log(`${a.color[0]} → ← ${a.collider.color[0]}`);
    }
    updatePos(a);
    drawBall(a);

  });

  requestAnimationFrame(engine);
}

engine();
canvas {
  background: #eee;
  margin: 0 auto;
  border-radius: 50%;
  box-shadow: 0 0 0 4px #000;
}
.row {
  display: flex;
}

.container1 {
  display: flex;
  flex-direction: column;
  margin-left: 70%;
  margin-top: 8%;
  float: right;
}

#Canvas1, #Canvas2, #Canvas3, #Canvas4 {
    background: #eee;
    border-radius: 50%;
    border: solid 1px #000;
    margin: 4px;
}
<div class="column">
    <canvas id="Canvas"></canvas>
  </div>
<div class="container1">
  <div class="row">
    <canvas id="Canvas1"></canvas>
    <div><p>abc</p></div>
    <canvas id="Canvas2"></canvas>
    <div><p>def</p></div>
  </div>
  <div class="row">
    <canvas id="Canvas3"></canvas>
    <div><p>hij</p></div>
    <canvas id="Canvas4"></canvas>
    <div><p>klm</p></div>
  </div>
</div>
<div id="mydiv"></div>
<div id="y"></div>
<div id="dx"></div>
<div id="dy"></div>
<div id="dialog" class="hidden">
  <div class="message"></div>
  <div>
    <button class="ok">OK</button>
  </div>
</div>
javascript html css canvas
1个回答
1
投票

提供的代码中有很多错误:

  • beep()功能未定义,它阻止警报系统工作。
  • 5个画布中只有相同的4个球的一个列表,因此您在所有画布中都看到相同的4个球。
  • [updatePos使用作为全局变量(大圆的半径)的containerR,只能对大圆进行计算。
  • [drawBall在5个上下文中绘制相同的单个球

固定代码,球的初始位置随机:

function PromptDialog(dialog) {
  this.el           = document.getElementById(dialog);
  this.messageEl    = this.el.querySelector('.message');
  this.okButton     = this.el.querySelector('button.ok');
  this.attachDomEvents();
}
	PromptDialog.prototype.attachDomEvents = function() {
  this.okButton.addEventListener('click', () => {
    this.hide();
    //console.log('Ok clicked!!');
  });
};
PromptDialog.prototype.show = function(message) {
  this.messageEl.innerHTML = '' + message;
  this.el.className = '';
};
PromptDialog.prototype.hide = function() {
  this.el.className = 'hidden';
};


var prompt = new PromptDialog('dialog');

const getBall = (x, y, dx, dy, r, color) => ({x, y, dx, dy, r, color});

const drawBall = (ball, ctx) => {
  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
  ctx.fillStyle = ball.collider ? "red" : ball.color;
  ctx.fill();
  ctx.closePath();
}

const updatePos = (ball, containerR) => {

  ball.x += ball.dx;
  ball.y += ball.dy;
  const dx = ball.x - containerR;
  const dy = ball.y - containerR;

  if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
    const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
    const angleToCollisionPoint = Math.atan2(-dy, dx);
    const oldAngle = Math.atan2(-ball.dy, ball.dx);
    const newAngle = 2 * angleToCollisionPoint - oldAngle;
    ball.dx = -v * Math.cos(newAngle);
    ball.dy = v * Math.sin(newAngle);
  }
}

function makeArea(domid, radius, ballsNumber, alerts) {
  const ctx = document.getElementById(domid).getContext("2d");
  const containerR = radius;
  const size = radius * 2
  ctx.canvas.width = ctx.canvas.height = size;
  ctx.globalAlpha = 0.8;
  
  const balls = [];
  const speed = 0.1;
  
  for(var i=0 ; i<ballsNumber ; ++i) {
    const r = Math.random()*radius*0.5;
    const t = Math.random()*Math.PI*2;
    const t2 = Math.random()*Math.PI*2;
    
    balls.push(
    	getBall(
      	radius + Math.cos(t)*r,
        radius + Math.sin(t)*r,
        Math.cos(t2)*speed,
        Math.sin(t2)*speed,
        8,
        "Green")
    );
  }
  
  return {
    ctx: ctx,
    radius: radius,
    balls: balls,
    alerts:alerts
  }
}

const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));

const areas = [
  makeArea("Canvas", 150, 4, true),
  makeArea("Canvas1", 80, 4, false),
  makeArea("Canvas2", 80, 4, false),
  makeArea("Canvas3", 80, 4, false),
  makeArea("Canvas4", 80, 4, false)
];

function engine() {
  //console.clear(); // Clear console test messages
  areas.forEach((area) =>{
    const ctx = area.ctx;
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    area.balls.forEach((a, ai) => {
      a.collider = undefined;

      area.balls.forEach((b, bi) => {
        if (bi === ai) return; // Don't look at self
        if (collides(a, b)) a.collider = b; // Store the colliding B ball
      });

      if (a.collider && area.alerts) { // If ball has a collider:
       //beep();
       prompt.show('ALERT!!!!! Not Maintaining Distance');

        //console.log(`${a.color[0]} → ← ${a.collider.color[0]}`);
      }
      updatePos(a, area.radius);
      drawBall(a, ctx);
    });
  });
  requestAnimationFrame(engine);
}

engine();
canvas {
  background: #eee;
  margin: 0 auto;
  border-radius: 50%;
  box-shadow: 0 0 0 4px #000;
}
.row {
  display: flex;
}

.hidden {
  display:none;
}

#Canvas1, #Canvas2, #Canvas3, #Canvas4 {
  background: #eee;
  border-radius: 50%;
  border: solid 1px #000;
  margin: 4px;
}
<div class="row">
    <div>
        <canvas id="Canvas"></canvas>
    </div>
    <div>
        <div class="row">
            <canvas id="Canvas1"></canvas>
            <div><p>abc</p></div>
            <canvas id="Canvas2"></canvas>
            <div><p>def</p></div>
        </div>
        <div class="row">
            <canvas id="Canvas3"></canvas>
            <div><p>hij</p></div>
            <canvas id="Canvas4"></canvas>
            <div><p>klm</p></div>
        </div>
    </div>
</div>

<div id="dialog" class="hidden">
    <div class="message"></div>
    <div>
        <button class="ok">OK</button>
    </div>
</div>
© www.soinside.com 2019 - 2024. All rights reserved.