canvas 碰撞反彈

weixin_34337265發表於2017-12-28

之前我們學習js的時候都寫過碰撞反彈,canvas裡的碰撞反彈也可以用同樣的條件判斷,現在我們回顧一下之前的判斷

外接矩形碰撞

7426643-3024037f370ce06c.png
4C4433E2-72F6-49FD-8429-3A39A65B5945.png

我們根據上面的判斷來寫一下效果

var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
        

運動方塊的建構函式

        function Rect(x,y,w,h,color,speedx,speedy){
            this.x = x;
            this.y = y;
            this.w = w;
            this.h = h;
            this.color = color;
            this.speedx = speedx;
            this.speedy = speedy;
        }
        Rect.prototype.draw=function(){
            context.beginPath();
            context.fillStyle = this.color;
            context.fillRect(this.x,this.y,this.w,this.h);
        }
        Rect.prototype.move=function(){
            this.x +=this.speedx;
            this.y +=this.speedy;
            //碰壁檢測
            if(this.x<0||this.x>canvas.width-this.w){
                this.speedx *=-1;
            }
            if(this.y<0||this.y>canvas.height-this.h){
                this.speedy *=-1;
            }
        }

例項化方塊,運動的函式

方式一:通過判斷方塊位置
        var rect1 = new Rect(0,0,50,50,"green",1,3)
        var rect2 = new Rect(450,0,50,50,"red",2,4)
        function act1(){
            context.clearRect(0,0,canvas.width,canvas.height);
            rect1.draw();
            rect1.move();
            rect2.draw();
            rect2.move();
            //碰撞檢測
            if((rect1.x+rect1.w)>rect2.x&&rect1.x<(rect2.x+rect2.w) && (rect1.y+rect1.h)>rect2.y&&rect1.y<(rect2.y+rect2.h)){
                console.log(11111111111)
                rect1.speedx *=-1;
                rect1.speedy *=-1;
                rect2.speedx *=-1;
                rect2.speedy *=-1;
            }
                      window.requestAnimationFrame(act1);
        }
        act1()
通過判斷方塊是否重疊
var rect1 = new Rect(0,0,50,50,"green",1,3)
        var rect2 = new Rect(450,0,50,50,"red",2,4)
        function act1(){
            context.clearRect(0,0,canvas.width,canvas.height);
            rect1.draw();
            rect1.move();
            rect2.draw();
            rect2.move();
            //畫素碰撞
            if(isCrash(rect1,rect2)){
                console.log(22222222)
                rect1.speedx *=-1;
                rect1.speedy *=-1;
                rect2.speedx *=-1;
                rect2.speedy *=-1;
            };
            window.requestAnimationFrame(act1);
        }
        act1()
        
        function isCrash(rect1,rect2){
            var min1x = rect1.x;
            var max1x = rect1.x+rect1.w;
            var min2x = rect2.x;
            var max2x = rect2.x+rect2.w;
            
            var min1y = rect1.y;
            var max1y = rect1.y+rect1.h;
            var min2y = rect2.y;
            var max2y = rect2.y+rect2.h;
            
            //假設碰撞出新的方塊
            var nminx = Math.max(min1x,min2x);
            var nmaxx = Math.min(max1x,max2x);
            
            var nminy = Math.max(min1y,min2y);
            var nmaxy = Math.min(max1y,max2y);
            
            if(nmaxx >nminx && nmaxy>nminy){
                return true;
            }
        }

外接圓碰撞

7426643-e34b2f36bef9edb8.png
480C32A5-3801-4BF2-B936-864601260910.png
var canvas = document.getElementById("mycanvas");
        var context = canvas.getContext("2d");
        
        function Ball(x,y,r,color,speedx,speedy){
            this.x = x;
            this.y = y;
            this.r = r;
            this.color = color;
            this.speedx = speedx;
            this.speedy = speedy;
        }
        Ball.prototype.draw=function(){
            context.beginPath();
            context.fillStyle = this.color;
            context.arc(this.x,this.y,this.r,0,Math.PI*2);
            context.fill();
        }
        Ball.prototype.move=function(){
            this.x +=this.speedx;
            this.y +=this.speedy;
            //碰壁檢測
            if(this.x<this.r||this.x>canvas.width-this.r){
                this.speedx *=-1;
            }
            if(this.y<this.r||this.y>canvas.height-this.r){
                this.speedy *=-1;
            }
        }
        var Ball1 = new Ball(50,50,25,"green",1,3)
        var Ball2 = new Ball(450,50,20,"red",2,4)
        function act1(){
            context.clearRect(0,0,canvas.width,canvas.height);
            Ball1.draw();
            Ball1.move();
            Ball2.draw();
            Ball2.move();
            
            //碰撞檢測
            if(Math.pow(Ball1.x-Ball2.x,2)+Math.pow(Ball1.y-Ball2.y,2)<Math.pow(Ball1.r+Ball2.r,2)){
                Ball1.speedx *=-1;
                Ball1.speedy *=-1;
                Ball2.speedx *=-1;
                Ball2.speedy *=-1;
            }
            window.requestAnimationFrame(act1);
        }
        act1()

最後顯示:

7426643-953aaa39c864151c.gif
QQ20171228-204510-HD.gif

畫素碰撞

7426643-d60806e6be413527.png
F43640B5-94DF-49B0-89A5-3E7A2A8BA681.png

還存在一種碰撞叫做畫素的碰撞,雖然影像所在矩形碰撞,但是不代表影像之間發生碰撞;
我們需要檢測影像所在矩形是否相較,同時檢測兩圖在相交矩形內的畫素,存在一點在兩個圖上的 alpha 值不為 0,則發生碰撞。

我們利用上面矩形碰撞的方式二來寫畫素碰撞,方式一我們不能得到重疊的矩形

var canvas = document.getElementById("mycanvas");
        var context = canvas.getContext("2d");
        var img = new Image();
        img.src = "Chat.png";
        var play = new Image();
        play.src = "Play.png";
        img.onload = function(){
            context.beginPath();
            context.drawImage(img,100,100);
            var rect1 = new Rect(100,100,img.width,img.height);
            canvas.onmousedown = function(){
                canvas.onmousemove = function(e){
                    var ev = e||window.event;
                    var x = ev.clientX-canvas.offsetLeft;
                    var y = ev.clientY-canvas.offsetTop;
                    context.clearRect(0,0,canvas.width,canvas.height);
                    context.drawImage(play,x,y)
//                  context.drawImage(play,x-play.width/2,y-(play.height/2))
                    var rect2 = new Rect(x,y,play.width,play.height);
                    //例項化
                    context.drawImage(img,100,100);
                    var res = isCrash(rect1,rect2)
                    if(res.judge){
                        var newRect = res.rect;
                        //分別遍歷碰撞區域的畫素點
                        //清除某一區域的畫布
                        context.clearRect(0,0,canvas.width,canvas.height)
                        //畫藍色圖
                        context.drawImage(img,100,100);
                        //獲取藍圖的畫素點
                        var imgData1 = context.getImageData(res.rect.x,res.rect.y,res.rect.w,res.rect.h);
                        
                        context.clearRect(0,0,canvas.width,canvas.height)
                        //畫綠色圖
                        context.drawImage(play,x,y);
                        //獲取綠色圖的畫素點
                        var imgData2 = context.getImageData(res.rect.x,res.rect.y,res.rect.w,res.rect.h);
                        context.drawImage(img,100,100);
                        for(var i=0;i<imgData1.data.length;i+=4){
                            if(imgData1.data[i+3]>0 && imgData2.data[i+3]>0){
                                console.log("畫素碰撞了")
                                break;
                            }
                        }
                    };
                }
            }
        }
        canvas.onmouseup =function (){
            canvas.onmousemove = null;
        }
        function Rect(x,y,w,h){
            this.x = x;
            this.y = y;
            this.w = w;
            this.h = h;
        }
        function isCrash(rect1,rect2){
            var min1x = rect1.x;
            var max1x = rect1.x+rect1.w;
            var min2x = rect2.x;
            var max2x = rect2.x+rect2.w;
            
            var min1y = rect1.y;
            var max1y = rect1.y+rect1.h;
            var min2y = rect2.y;
            var max2y = rect2.y+rect2.h;
            
            //假設碰撞出新的方塊
            var nminx = Math.max(min1x,min2x);
            var nmaxx = Math.min(max1x,max2x);
            
            var nminy = Math.max(min1y,min2y);
            var nmaxy = Math.min(max1y,max2y);
            
            var obj = new Rect(nminx,nminy,(nmaxx-nminx),(nmaxy-nminy));
            
            if(nmaxx >nminx && nmaxy>nminy){
                return {
                    judge:true,
                    rect:obj
                };
            }else{
                return {
                    judge:false
                };
            }
        }

相關文章