简体   繁体   English

JavaScript中画布上的碰撞检测

[英]Collision detection on a canvas in JavaScript

I'm working on a game for a university assignment. 我正在为大学分配游戏 The idea is that you defend the centre circle from the incoming asteroids (lines) by drawing a line (click, drag & release to draw a line) which blocks them. 这个想法是通过画一条线(单击,拖动并释放以画一条线)来阻止它们,从而保护中心圆免受传入的小行星(线)的伤害。 An asteroid hitting a line should destroy both the asteroid the line. 小行星撞到一条直线上应该会同时摧毁这条小行星。

The problem I'm currently having is that the collision isn't being detected. 我目前遇到的问题是未检测到碰撞。

I have arrays of objects of both lines & asteroids. 我有直线和小行星的物体阵列。 The lines consist of simply start & end x & y, the asteroids consist of a random speed & a random angle (their incoming angle) - the context is rotated, the asteroid drawn, & then it reset for the next line. 这些行仅由开始和结束x&y组成,小行星由随机速度和随机角度(其入射角)组成-旋转上下文,绘制小行星,然后将其重置为下一行。

To detect collision, I use getImageData & check in front of the asteroids however many pixels the line will progress in that iteration (basically, their speed) & if the colour is red, it will destroy the asteroid - I haven't got round to destroying the line yet, will tackle that hurdle when I come to it (suggestions are welcome though). 为了检测碰撞,我使用getImageData并在小行星前面进行检查,但是该行在该迭代中会前进很多像素(基本上是它们的速度),如果颜色是红色,它将破坏小行星-我还没来得及销毁这条线,将解决我遇到的障碍(不过我们建议)。

function asteroids_draw() {
            for (var i = 0; i < asteroids.length; i++) {
                //  Drawing setup
                context.save();
                context.translate(width / 2, height / 2);
                context.rotate(asteroids[i].angle);             

                //  Detecting close asteroids
                if ((asteroids[i].distance - asteroids[i].speed) < planet.size) {
                    asteroids.splice(i, 1);
                    game_life_lost();
                    context.restore();      
                    return;

                } else if ((asteroids[i].distance - asteroids[i].speed) < 150){
                    asteroids[i].colour = '#FF0000';
                }

                //  Scanning ahead for lines                    
                for (var j = 0; j < asteroids[i].speed; j++) {
                    if (context.getImageData(asteroids[i].distance - j, 0, 1, 1).data[0] == 255) {                          
                        asteroids.splice(i, 1);
                        context.restore();      
                        return;
                    }
                }                   

                //  Drawing asteroid
                context.beginPath();
                context.moveTo(asteroids[i].distance -= asteroids[i].speed, 0);
                context.lineTo(trig, 0);
                context.strokeStyle = asteroids[i].colour; 
                context.stroke();               
                context.closePath();

                context.restore();      
            }
        }

The problem is, the asteroids never collide with the lines & I can't for the life of me see why, or see another simple way of doing it. 问题是,小行星从不与直线碰撞,我一生都看不到为什么,也看不到另一种简单的方式。 Any advice would be much appreciated, thanks in advance. 任何建议将不胜感激,在此先感谢。

I think your problem is that when you rotate the context, previously drawn items(lines) don't get rotated, only objects drawn after the rotation are rotated. 我认为您的问题是,当旋转上下文时,先前绘制的项目(线)不会旋转,只有旋转后绘制的对象才会旋转。 See this page for more info . 有关更多信息,请参见此页面

You could try performing your asteroid/line intersection test before you translate and rotate the canvas, and use cosine and sine to find the x and y coordinates of the pixels you want to get image data from. 在平移和旋转画布之前,您可以尝试执行小行星/直线相交测试,并使用余弦和正弦找到要从中获取图像数据的像素的x和y坐标。

var pixelLocation = 
    [Math.cos(asteroids[i].angle) * j, Math.sin(asteroids[i].angle) * j];
if (context.getImageData(pixelLocation[0], pixelLocation[1], 1, 1).data[0] == 255) {

Just make sure your angle is in radians before passing to cos and sin. 只要确定您的角度是弧度,然后再传递给cos和sin。

I thought about the problem some more, & realised this method of doing things definitely isn't the best way. 我再考虑了这个问题,并意识到这种做事方法绝对不是最好的方法。 It should be doable without a view - a la Model View Controller design pattern. 它应该在没有视图的情况下也是可行的-一种“模型视图控制器”设计模式。 The best way to solve it would be to use maths! 解决该问题的最佳方法是使用数学!

There's simple maths for the intersection of two lines, but this needs intersection of two lines in a range. 两条线的交点有简单的数学运算,但这需要一个范围内两条线的交点。 I found an algorithm which simplifies this further, using eight coordinates - the start x & y & the end x & y of the two lines. 我发现了一种算法 ,它使用八个坐标-两行的开始x&y和结束x&y进一步简化了这一过程。

I've posted the results . 我已经发布了结果 Thanks for the help. 谢谢您的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM