1. 程式人生 > >js 小球碰壁反彈and小球碰撞

js 小球碰壁反彈and小球碰撞

好像好幾天沒有更博了呢,最近有點變懶了,這樣不好,不好~~我們要做熱愛學習的好孩子,嘻嘻,今天下午補上。。。

我們在學習js的時候,一個很經典的案例就是小球的碰壁反彈效果啦~簡單的小球碰壁效果可以慢慢延伸,讓我們做出的效果更漂亮。如圖~

這裡寫圖片描述

這個樣子放上好像有點單調,這個案例就是實現了多個小球的同時碰壁反彈,並且不同的小球碰撞後也可發生碰撞反應,相應的小球運動方向也會發生改變。

什麼事情都要從簡單開始,一點一點的去做,要想實現好多小球同時運動,首先就要搞清楚一個小球是怎麼去運動的。要想讓小球動起來,最常用的就是兩種方法,一種是要改變小球的margin值,使小球移動,還有一種就是利用position定位,讓小球動起來。我用了position定位的方法。我們可以利用計時器控制小球left和top值的變化,是小球一直移動。解決了小球移動的問題,第二個問題就是方向的變化,對小球的位置進行一個判斷,二維空間內,小球的運動可以分解為x方向和y方向上的運動,所以我們可以分別設定一個flag標記,對小球的位置進行判斷,等小球到達邊界時,就改變flag的值,使小球的運動方向發生改變。

實現了一個小球的運動,再去實現多個小球就容易啦,首先,我先建立了一個數組,陣列中的每一個元素都存一個物件,每個物件均包括一個x(小球的初始x值),y(小球的初始y值),cx(圓心x座標),cy(圓心y座標),movex(小球x軸運動方向),movey(小球y軸運動方向),bgcolor(小球的背景顏色),speed(小球運動速度),timer(小球運動計時器,每一個小球需要一個計時器控制這個小球的運動),index (小球的索引值)。
給每一個物件繫結一個計時器,這樣小球就可以動起來啦~

現在每一個小球都可以動啦,我們可以繼續優化,實現小球的碰撞反彈。博主的物理學的不大好,也比較懶,所以對於小球的反彈,就比較簡單粗暴的來寫了。首先先比較小球啊與除了本身之外的其他所有小球的圓心距,如果圓心距小於一個小球的直徑,即兩個小球便會發生碰撞事件。(方向的改變僅僅考慮了簡單碰撞後方向改變,並未考慮物理實際的碰撞反應,僅實現簡單的方向改變,速度不會改變)

如果小球b處於小球a的正上或正下,便只改變小球a的movey,
如果小球b處在小球a的正左或正右,便只改變小球a的movex,
如果小球a處在小球b的左下方,小球a向左下移動,
如果小球a處在小球b的左上方,小球a向左上移動,
如果小球a處在小球b的右下方,小球a向右下移動,
如果小球a處在小球b的右上方,小球a向右上移動,

html,css程式碼如下:

<style>
        *{margin: 0;
            padding:0;}
        #main{margin: 0px auto;position: relative;}
        #main
div{overflow: hidden;position: absolute;width: 200px;height: 200px;opacity: 0.5; -moz-border-radius: 50%;-webkit-border-radius: 50%;border-radius: 50%;}
</style> <div id="main"> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> </div>

所有的js程式碼:

<script>
        var main = document.getElementById('main');
        var circles = main.getElementsByTagName('div');
        var st = [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'];
        var json = [],arr=[],color = [];
        var maxW = 0;
        var maxH = 0;
        var cwidth = circles[0].offsetWidth;
        var cheight = circles[0].offsetHeight;

        //根據瀏覽器視窗的大小自動調節小球的運動空間
        window.onresize=function(){
            var main = document.getElementById('main');
            maxW=window.innerWidth-circles[0].clientWidth;
            maxH=window.innerHeight-circles[0].clientHeight;
            main.style.width = window.innerWidth+'px';
            main.style.height = window.innerHeight+'px';

        }
        onresize();
        //陣列物件的初始化
        for(var i=0;i<circles.length;i++){
            arr=[];
            for(var j=0;j<6;j++){
                color[j] = st[Math.floor(Math.random()*16)];
            }
            arr.x = Math.floor(Math.random()*(maxW+1));//初始x座標
            arr.y = Math.floor(Math.random()*(maxH+1));//初始y座標
            arr.cx = arr.x + circles[0].offsetWidth/2;//圓心x座標
            arr.cy = arr.y + circles[0].offsetHeight/2;//圓心y座標
            arr.movex = Math.floor(Math.random()*2);//x軸移動方向
            arr.movey = Math.floor(Math.random()*2);//y軸移動方向
            arr.bgolor = '#'+ color.join('');//隨機生成一個6位字串
            arr.speed = 2+Math.floor(Math.random()*5);
            //隨機生成一個2~6之間的移動速度(如果設定的改變速度太大,容易造成小球碰撞時兩個小球之間有重合,也有可能小球會出界)
            arr.timer = null;//計時器
            arr.index = i;//索引值
            json.push(arr);
            circles[i].style.left = arr.x + 'px';//小球位置初始化
            circles[i].style.top = arr.y + 'px';//小球位置初始化
            circles[i].style.backgroundColor = arr.bgolor;//小球背景顏色初始化
        }
        //碰撞函式
        function crash(a){
            var ball1x = json[a].cx;
            var ball1y = json[a].cy;
            for(var i= 0;i<json.length;i++){
                if(i!=a){
                    var ball2x = json[i].cx;
                    var ball2y = json[i].cy;
                    //圓心距離的平方
                    var len = (ball1x-ball2x)*(ball1x-ball2x)+(ball1y-ball2y)*(ball1y-ball2y);
                    if(len <= cwidth*cwidth){
                    //小球位置的判斷,發生碰撞反應
                        if(ball1x >ball2x){
                            if(ball1y > ball2y){
                                json[a].movex=1;
                                json[a].movey=1;
                            }else if(ball1y < ball2y){
                                json[a].movex=1;
                                json[a].movey=0;
                            }else{
                                json[a].movex=1;
                            }
                        }else if(ball1x < ball2x){
                            if(ball1y > ball2y){
                                json[a].movex=0;
                                json[a].movey=0;
                            }else if(ball1y < ball2y){
                                json[a].movex=0;
                                json[a].movey=1;
                            }else{
                                json[a].movex=0;
                            }
                        }else{
                            if(ball1y > ball2y){
                                json[a].movey=1;
                            }else if(ball1y < ball2y){
                                json[a].movey=0;
                            }
                        }
                    }
                }

            }
        }
        //移動函式
        function move(circle){
            circle.timer = setInterval(function () {
                if(circle.movex == 1){
                    circle.x+=circle.speed;
                    if(circle.x+circle.speed >= maxW){//防止小球出界
                        circle.x = maxW;
                        circle.movex=0;//小球運動方向發生改變
                    }
                }else{
                    circle.x-=circle.speed;
                    if(circle.x-circle.speed <= 0){
                        circle.x = 0;
                        circle.movex=1;
                    }
                }
                if(circle.movey == 1){
                    circle.y += circle.speed;
                    if(circle.y+circle.speed >= maxH){
                        circle.y = maxH;
                        circle.movey=0;
                    }
                }else{
                    circle.y-=circle.speed;
                    if(circle.y-circle.speed <= 0){
                        circle.y = 0;
                        circle.movey=1;
                    }
                }
                circle.cx = circle.x + circles[0].offsetWidth/2;//小球每一次運動圓心都會發生改變
                circle.cy = circle.y + circles[0].offsetHeight/2;
                circles[circle.index].style.left = circle.x + 'px';//小球位置重定位
                circles[circle.index].style.top = circle.y + 'px';
                /*console.log('x'+circle.cx+'y'+circle.cy);*/
                crash(circle.index);
            },15);
        }
        //對每一個小球繫結計時器,讓小球動起來
        for(var i=0;i<circles.length;i++){
            move(json[i]);
        }
    </script>

其實在寫的過程中,也遇到了很多很多的bug,這已經是改進後的版本,也許現在的版本還有bug,期待大家來發現哦~