使Canvas文本对象相互反弹并由数组创建

时间:2017-05-01 21:07:41

标签: javascript math

我最近开始在一个网站上工作并学习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>

现在我该怎么做呢?

2 个答案:

答案 0 :(得分:1)

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

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

然后,您可以使用for循环迭代所有框:

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

处理盒子盒碰撞可以在几行代码中完成,但它不会非常强大。即你只能在检测到盒子重叠并通过直接更新盒子速度来解决碰撞之前,每轮更新盒子位置几个像素。在解决多框冲突之前可能需要几帧,并且在此期间框可以明显重叠。对于处理堆叠,物体之间的力和更好的集成机制的更强大的物理,你应该寻找一个经过测试的2D盒子物理库。

对于物理模拟和动画,时间非常重要。对于动画,you should use requestAnimationFrame而不是setInterval。由于两种方法都不能保证恒定的时间步长,因此您需要计算两次物理更新之间传递的时间dt,并在该时间步dt上积分(=乘)速度以获得新的位置。< / p>

用“穷人的物理学”重组代码:

// 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>

答案 1 :(得分:0)

你的代码很乱,如果你保持这种状态就没有办法取得进展。让我们来组织一下。

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。欢迎堆栈溢出