使画布文本对象彼此反弹,并由数组创建



我最近开始在网站上工作并学习html/ccs/js,并遇到并想到我不确定如何执行。基本上,我希望目前四处移动并从窗户边界弹起的浮动文本也相互反弹。我还认为,能够设置我要产生多少个文本对象可能会很好。这是我的网站,用于引用文本如何围绕http://gmtrash.ga/

弹跳

这是控制文本对象和颜色的JavaScript

setInterval(function() {
	myContainer = document.getElementById("colortext");
	displayRandomColor();
	function getRandomColor() {
		r = Math.floor(Math.random() * 256);
		g = Math.floor(Math.random() * 256);
		b = Math.floor(Math.random() * 256);
		hexR = r.toString(16);
		hexG = g.toString(16);
		hexB = b.toString(16);
		if (hexR.length == 1) {
			hexR = "0" + hexR;
		}
		if (hexG.length == 1) {
			hexG = "0" + hexG;
		}
		if (hexB.length == 1) {
			hexB = "0" + hexB;
		}
		hexColor = "#" + hexR + hexG + hexB;
		return hexColor.toUpperCase();
	}
	function displayRandomColor() {
		myRandomColor = getRandomColor();
	}
}, 450);
myRandomColor = 000000;
var context;
var x = Math.floor(Math.random() * window.outerWidth);
var y = Math.floor(Math.random() * window.outerHeight);
var x1 = Math.floor(Math.random() * window.outerWidth);
var y1 = Math.floor(Math.random() * window.outerHeight);
var x2 = Math.floor(Math.random() * window.outerWidth);
var y2 = Math.floor(Math.random() * window.outerHeight);
var x3 = Math.floor(Math.random() * window.outerWidth);
var y3 = Math.floor(Math.random() * window.outerHeight);
var x4 = Math.floor(Math.random() * window.outerWidth);
var y4 = Math.floor(Math.random() * window.outerHeight);
var x5 = Math.floor(Math.random() * window.outerWidth);
var y5 = Math.floor(Math.random() * window.outerHeight);
var x6 = Math.floor(Math.random() * window.outerWidth);
var y6 = Math.floor(Math.random() * window.outerHeight);
var x7 = Math.floor(Math.random() * window.outerWidth);
var y7 = Math.floor(Math.random() * window.outerHeight);
var x8 = Math.floor(Math.random() * window.outerWidth);
var y8 = Math.floor(Math.random() * window.outerHeight);
var x9 = Math.floor(Math.random() * window.outerWidth);
var y9 = Math.floor(Math.random() * window.outerHeight);
var dx = Math.floor(Math.random() * 15);
var dy = Math.floor(Math.random() * 15);
var dx1 = Math.floor(Math.random() * 15);
var dy1 = Math.floor(Math.random() * 15);
var dx2 = Math.floor(Math.random() * 15);
var dy2 = Math.floor(Math.random() * 15);
var dx3 = Math.floor(Math.random() * 15);
var dy3 = Math.floor(Math.random() * 15);
var dx4 = Math.floor(Math.random() * 15);
var dy4 = Math.floor(Math.random() * 15);
var dx5 = Math.floor(Math.random() * 15);
var dy5 = Math.floor(Math.random() * 15);
var dx6 = Math.floor(Math.random() * 15);
var dy6 = Math.floor(Math.random() * 15);
var dx7 = Math.floor(Math.random() * 15);
var dy7 = Math.floor(Math.random() * 15);
var dx8 = Math.floor(Math.random() * 15);
var dy8 = Math.floor(Math.random() * 15);
var dx9 = Math.floor(Math.random() * 15);
var dy9 = Math.floor(Math.random() * 15);
function init() {
	context = myCanvas.getContext('2d');
	setInterval(draw, 10);
}
function draw() {
	context.clearRect(0, 0, window.outerWidth, window.outerHeight);
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x, y);
	context.closePath();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x1, y1);
	context.closePath();
	context.fill();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x2, y2);
	context.closePath();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x3, y3);
	context.closePath();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x4, y4);
	context.closePath();
	context.fill();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x5, y5);
	context.closePath();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x6, y6);
	context.closePath();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x7, y7);
	context.closePath();
	context.fill();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x8, y8);
	context.closePath();
	context.beginPath();
	context.fillStyle = myRandomColor;
	context.font = "64px fixedsys";
	context.fillText("nerd", x9, y9);
	context.closePath();
	if (x < 0 || x > window.outerWidth) dx = -dx;
	if (y < 0 || y > window.outerHeight) dy = -dy;
	x += dx;
	y += dy;
	if (x1 < 0 || x1 > window.outerWidth) dx1 = -dx1;
	if (y1 < 0 || y1 > window.outerHeight) dy1 = -dy1;
	x1 += dx1;
	y1 += dy1;
	if (x2 < 0 || x2 > window.outerWidth) dx2 = -dx2;
	if (y2 < 0 || y2 > window.outerHeight) dy2 = -dy2;
	x2 += dx2;
	y2 += dy2;
	if (x3 < 0 || x3 > window.outerWidth) dx3 = -dx3;
	if (y3 < 0 || y3 > window.outerHeight) dy3 = -dy3;
	x3 += dx3;
	y3 += dy3;
	if (x4 < 0 || x4 > window.outerWidth) dx4 = -dx4;
	if (y4 < 0 || y4 > window.outerHeight) dy4 = -dy4;
	x4 += dx4;
	y4 += dy4;
	if (x5 < 0 || x5 > window.outerWidth) dx5 = -dx5;
	if (y5 < 0 || y5 > window.outerHeight) dy5 = -dy5;
	x5 += dx5;
	y5 += dy5;
	if (x6 < 0 || x6 > window.outerWidth) dx6 = -dx6;
	if (y6 < 0 || y6 > window.outerHeight) dy6 = -dy6;
	x6 += dx6;
	y6 += dy6;
	if (x7 < 0 || x7 > window.outerWidth) dx7 = -dx7;
	if (y7 < 0 || y7 > window.outerHeight) dy7 = -dy7;
	x7 += dx7;
	y7 += dy7;
	if (x8 < 0 || x8 > window.outerWidth) dx8 = -dx8;
	if (y8 < 0 || y8 > window.outerHeight) dy8 = -dy8;
	x8 += dx8;
	y8 += dy8;
	if (x9 < 0 || x9 > window.outerWidth) dx9 = -dx9;
	if (y9 < 0 || y9 > window.outerHeight) dy9 = -dy9;
	x9 += dx9;
	y9 += dy9;
}
<html>
<body onLoad="init();"> <canvas id="myCanvas" style='position: absolute; left: 0px; top: 0px;'>
  </canvas>
  <div id="colortext">
  </div>
  <script src="scripts/suchcolor.js"></script>
  <script>
    (function() {
      var htmlCanvas = document.getElementById('myCanvas'),
        context = htmlCanvas.getContext('2d');
      initialize();
      function initialize() {
        window.addEventListener('resize', resizeCanvas, false);
        resizeCanvas();
      }
      function redraw() {
        context.strokeStyle = 'blue';
        context.lineWidth = '5';
        context.strokeRect(0, 0, window.innerWidth, window.innerHeight);
      }
      function resizeCanvas() {
        htmlCanvas.width = window.innerWidth;
        htmlCanvas.height = window.innerHeight;
        redraw();
      }
    })();
  </script>
</body>
</html>

现在我该怎么做?

您可以通过引入数组和循环大大改进代码。创建一个空数组var boxes = []并将框放入其中。每个盒子由位置,尺寸和速度组成,例如:

var box = {x: 0, y: 0, width: 10, height: 10, dx: 1, dy: 1};
boxes.push(box);

然后,您可以使用For-loop在所有盒子上迭代:

for (var i = 0; i < boxes.length; i++) {
  var box = boxes[i];
  // Do something with the i-th box...
}

处理框盒碰撞可以用几行代码完成,但这不是很健壮。IE。您只能在每发中更新几个像素,然后通过直接更新框速度来检测框重叠并解决碰撞。在解析多箱碰撞之前,可能需要几个帧,并且在此期间盒可能会重叠。有关处理堆叠的更健壮的物理,物体之间的力并具有更好的集成机制,您应该寻找经过测试的2D盒子物理库。

对于物理模拟和动画,时机非常重要。对于动画,您应该使用requestAnimationFrame而不是setInterval。由于这两种方法都不能保证恒定的时间步骤,因此您需要计算两个物理更新之间传递的时间dt,并在此时间内进行集成(=倍数(速度步骤 dt以获取新位置。

用"穷人的物理学"重新组织代码:

// Return random RGB color string:
function randomColor() {
  var hex = Math.floor(Math.random() * 0x1000000).toString(16);
  return "#" + ("000000" + hex).slice(-6);
}
// Poor man's box physics update for time step dt:
function doPhysics(boxes, width, height, dt) {
  for (let i = 0; i < boxes.length; i++) {
    var box = boxes[i];
    // Update positions: 
    box.x += box.dx * dt;
    box.y += box.dy * dt;
    // Handle boundary collisions:
    if (box.x < 0) {
      box.x = 0;
      box.dx = -box.dx;
    } else if (box.x + box.width > width) {
      box.x = width - box.width;
      box.dx = -box.dx;
    }
    if (box.y < 0) {
      box.y = 0;
      box.dy = -box.dy;
    } else if (box.y + box.height > height) {
      box.y = height - box.height;
      box.dy = -box.dy;
    }
  }
  // Handle box collisions:
  for (let i = 0; i < boxes.length; i++) {
    for (let j = i + 1; j < boxes.length; j++) {
      var box1 = boxes[i];
      var box2 = boxes[j];
      var dx = Math.abs(box1.x - box2.x);
      var dy = Math.abs(box1.y - box2.y);
      // Check for overlap:
      if (2 * dx < (box1.width  + box2.width ) &&
          2 * dy < (box1.height + box2.height)) {
        // Swap dx if moving towards each other: 
        if ((box1.x > box2.x) == (box1.dx < box2.dx)) {
          var swap = box1.dx;
          box1.dx = box2.dx;
          box2.dx = swap;
        }
        // Swap dy if moving towards each other: 
        if ((box1.y > box2.y) == (box1.dy < box2.dy)) {
          var swap = box1.dy;
          box1.dy = box2.dy;
          box2.dy = swap;
        }
      }
    }
  }
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
// Initialize random boxes:
var boxes = [];
for (var i = 0; i < 10; i++) {
  var box = {
    x: Math.floor(Math.random() * canvas.width),
    y: Math.floor(Math.random() * canvas.height),
    width: 50,
    height: 20,
    dx: (Math.random() - 0.5) * 0.2,
    dy: (Math.random() - 0.5) * 0.2
  };
  boxes.push(box);
}
// Initialize random color and set up interval:
var color = randomColor();
setInterval(function() {
  color = randomColor();
}, 450);
// Update physics at fixed rate:
var last = performance.now();
setInterval(function(time) {
  var now = performance.now();
  doPhysics(boxes, canvas.width, canvas.height, now - last);
  last = now;
}, 50);
// Draw animation frames at optimal frame rate:
function draw(now) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  for (let i = 0; i < boxes.length; i++) {
    var box = boxes[i];
    
    // Interpolate position:
    var x = box.x + box.dx * (now - last);
    var y = box.y + box.dy * (now - last);
    
    context.beginPath();
    context.fillStyle = color;
    context.font = "20px fixedsys";
    context.textBaseline = "hanging";
    context.fillText("nerd", x, y);
    context.closePath();
  }
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
<canvas id="canvas"></canvas>

您的代码是一团糟,如果您保持这种方式,您将无法取得进步。让我们组织一点。

function textObject(color, width, height){
    this.color = color;
    this.x = Math.floor(Math.random()*width);
    this.y = Math.floor(Math.random()*height);
    this.dx = Math.floor(Math.random()*15);
    this.dy = Math.floor(Math.random()*15);
    this.show = function(context){
        context.beginPath();
        context.fillStyle = this.color;
        context.font = "64px fixedsys";
        context.fillText("nerd", this.x, this.y);
        context.closePath();
    }
    this.move = function(){
        this.x += dx;
        this.y += dy;
    }
}

好吧,这一切大惊小怪?我们在这里取得了什么成就?好的,我们将每个"nerd"单词都表示为一个实体,具有其自身的属性和行为。现在,我们可以做到这一点,而不是编写一系列无聊的重复代码:

var words = [];
for(var i=0; i<10; i++){
    words.push(new textObject(getRandomColor(), window.outerWidth, window.outerHeight));
}

和那样,我们有10个文本对象,其颜色,位置和"速度"。最重要的是?我们确实可以将它们添加到一个数组中(这正是我们如上所述所做的(!

现在,让我们将碰撞检测代码全部分组在一起:

function collisionDetection(arr){
    //checking for collision with the window boundaries
    for(var i=0; i<arr.length; i++){
        if(arr[i].x<0 || arr[i].x>window.outerWidth){
            arr[i].dx = - arr[i].dx;
        }
        if(arr[i].y<0 || arr[i].y>window.outerHeight){
            arr[i].dy = -arr[i].dy;
        }
    }
}

好吧,所以现在我们已经准备好了。将TextObject函数放入单独的JavaScript文件中,并将其包含在HTML文档中的脚本标签中,将其余的代码添加到当前代码所在的位置(从而替换它(。现在您的draw功能应该是:

function draw(){
    context.clearRect(0, 0, window.outerWidth, window.outerHeight);
    for(var i=0; i<words.length; i++){
        words[i].show(context);
        words[i].move();
    }
    collisionDetection();
}

到目前为止,您应该注意到,我还没有在您的主要问题上给您一个直接的答案,即相互碰撞的对象。我的建议是避免这样做,因为您要花费大量计算能力来计算碰撞。

考虑到您会提前知道单词对象的长度和高度(您应该自己发现(,您可以将以下方法添加到collisionDetection函数:

for(i=0; i<arr.length; i++){
    for(var j=0; j<arr.length; j++){
        if(i!=j){
            if(Math.abs(arr[i].x-arr[j].x) <= length){
                arr[i].dx = -arr[i].dx;
                arr[j].dx = -arr[j].dx;
            }
            if(Math.abs(arr[i].y-arr[j].y) <= height){
                arr[i].dy = -arr[i].dy;
                arr[j].dy = -arr[j].dy;
            }
        }
    }
}

此代码检查列表的每个对象是否与此列表的其他每个对象发生碰撞。当然,这不是一个很好的方法,如果您打算,您应该更改文本对象的数量,以减少必要的计算量。

我可能应该以警告:研究此代码,并在进行以对象为导向的编程(至少可以说是一个非常有用的概念(。我没有测试过,也许有一些错误。但是,我相信您有足够的知识来了解它的作用,并使用它来改进您的网站:)

P.S。欢迎来到堆栈溢出

最新更新