最近在玩小程式中一個比較火的遊戲,最!強!彈!一!彈!!!,真的是超級模型的一款小遊戲,打發時間堪比抖音。。。。。。,今天就來研究下關於小球如何有
重力效果
和互相碰撞反彈
的效果。
1. 重力效果實現
- 首先我們當然是要先畫個球球啦!
.ball {
width: 100px;
height: 100px;
border-radius: 50%;
background: #ff5532;
position: absolute;
}
複製程式碼
- 然後我們需要給小球規定一個初始的
X
,Y
上的速度和一個讓小球運動起來的定時器timer
。
var speedX = 6;
var speedY = 0;
var timer = null;
複製程式碼
- 定義小球在
X,Y
上可以移動的最大距離。
//document.documentElement.clientHeight(螢幕高度)
//ball.offsetHeight(小球的高度)
var maxMoveH = document.documentElement.clientHeight - ball.offsetHeight;
var maxMoveW = document.documentElement.clientWidth - ball.offsetWidth;
複製程式碼
- 如果達到最小或最大距離,折返運動。
//y軸橫向移動超過做大可移動高度,就反彈折回。
if(ballMoveY >= maxMoveH || ballMoveY <= 0){
speedY = -speedY;
ballMoveY = maxMoveH;
}
//x軸橫向移動超過做大可移動寬度,就反彈折回。
if(ballMoveX >= maxMoveW){
speedX = -speedX;
//定死最大寬度
ballMoveX = maxMoveW;
speedX = speedX*0.95;
}
//移動到右邊邊界就自動折返。
if(ballMoveX <= 0){
speedX = -speedX;
speedX = speedX*0.95;
}
複製程式碼
- 為了防止小球不在彈起後,還在x軸上移動。
if(Math.abs(speedX) < 0.2 && ballMoveY >= maxMoveH){
clearInterval(timer);
}
複製程式碼
- 下面是完整程式碼。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style type="text/css">
.ball {
width: 100px;
height: 100px;
border-radius: 50%;
background: #ff6632;
position: absolute;
}
</style>
</head>
<body>
<button id="moveStart">點選觸發</button>
<div id="ball" class="ball"></div>
</body>
<script>
window.onload = function() {
var ball = document.getElementById("ball");
var moveStart = document.getElementById("moveStart");
moveStart.onclick = function() {
var speedX = 6;
var speedY = 0;
var timer = null;
moveStart();
function moveStart() {
clearInterval(timer);
timer = setInterval(function(){
var ballMoveY, ballMoveX;
var maxMoveH = document.documentElement.clientHeight - ball.offsetHeight;
var maxMoveW = document.documentElement.clientWidth - ball.offsetWidth;
speedY += 6;
//橫向移動會有能量損耗
speedX = speedX*0.99;
ballMoveY = ball.offsetTop + speedY;
ballMoveX = ball.offsetLeft + speedX;
if(ballMoveY >= maxMoveH || ballMoveY <= 0){
speedY = -speedY;
ballMoveY = maxMoveH;
}
//x軸橫向移動超過做大可移動寬度,就反彈折回
if(ballMoveX >= maxMoveW){
speedX = -speedX;
ballMoveX = maxMoveW;
speedX = speedX*0.95;
}
if(ballMoveX <= 0){
speedX = -speedX;
speedX = speedX*0.95;
}
//如果速度小於0.2且小球不在彈起,則不讓小球在移動了
if(Math.abs(speedX) < 0.2 && ballMoveY >= maxMoveH){
clearInterval(timer);
}
ball.style.top = ballMoveY + 'px';
ball.style.left = ballMoveX + 'px';
},30)
}
}
}
</script>
</html>
複製程式碼
上述大概就是簡單的一個js仿重力的簡單實現。
現在我們來看一看神奇的碰撞效果。
首先,我們需要知道實現小球碰撞需要哪些方法。
- 隨機生成方法。
function random(type) {
switch(type){
case 'color':
return 'rgb(' + Math.floor(Math.random()*255) + ',' + Math.floor(Math.random()*255) + ',' + Math.floor(Math.random()*255) + ')';
case 'top':
return Math.floor(Math.random()*280) + 'px';
case 'left':
return Math.floor(Math.random()*280) + 'px';
case 'speed':
return Math.floor((Math.random() - 0.5)*20);
default:
return false;
}
}
複製程式碼
- 定義一個碰撞區域。
#content {
width: 300px;
height: 300px;
border: 1px solid #f00;
position: relative;
}
複製程式碼
- 建立小球。
function createBall(num){
var p = null;
for(var i=0; i < num; i++){
p = document.createElement('p');
p.innerHTML = i + 1;
p.style.background = random('color');
p.style.color = '#fff';
p.style.top = random('top');
p.style.left = random('left');
p.style['textAlign'] = 'center';
p.id = 'ball' + i;
content.appendChild(p);
ballList.push(p);
moveBall(p);
}
}
複製程式碼
- 小球移動。
function moveBall(ball, startSX, startSY) {
var speedX = random('speed'),
speedY = random('speed'),
ballMoveX = null,
speedObj = {},
ballMoveY = null;
timer = setInterval(function(){
ballMoveY = ball.offsetTop + speedY;
ballMoveX = ball.offsetLeft + speedX;
if(ballMoveX >= maxMoveX || ballMoveX <= 0){
speedX = -speedX;
}
if(ballMoveY >= maxMoveY || ballMoveY <= 0){
speedY = -speedY;
}
ball.style.top = ballMoveY + 'px';
ball.style.left = ballMoveX + 'px';
speedObj = crashBall(ball, speedX, speedY);
speedX = speedObj.speedX;
speedY = speedObj.speedY;
}, 30)
}
複製程式碼
- 小球碰撞。
存在8種位置碰撞的情況。
function crashBall(ball, speedX, speedY) {
var speedObj = {};
for(var i = 0; i<ballList.length; i++){
//自己不跟自己比較
if(ball.id !== ballList[i].id && Math.abs(ball.offsetLeft - ballList[i].offsetLeft) <= 20 && Math.abs(ball.offsetTop - ballList[i].offsetTop) <= 20){
//**********物件小球在碰撞小球方位的8個情況***********
//左上方
if(ball.offsetLeft < ballList[i].offsetLeft && ball.offsetTop < ballList[i].offsetTop){
speedX > 0 && (speedX = -speedX);
speedY > 0 && (speedY = -speedY);
}
//正上方(不會影響水平運動的速度)
if(ball.offsetLeft === ballList[i].offsetLeft && ball.offsetTop < ballList[i].offsetTop){
speedY > 0 && (speedY = -speedY);
}
//右上方
if(ball.offsetLeft > ballList[i].offsetLeft && ball.offsetTop < ballList[i].offsetTop){
speedX < 0 && (speedX = -speedX);
speedY > 0 && (speedY = -speedY);
}
//正右方
if(ball.offsetLeft > ballList[i].offsetLeft && ball.offsetTop === ballList[i].offsetTop){
speedX < 0 && (speedX = -speedX);
}
//右下方
if(ball.offsetLeft > ballList[i].offsetLeft && ball.offsetTop > ballList[i].offsetTop){
speedX < 0 && (speedX = -speedX);
speedY < 0 && (speedY = -speedY);
}
//正下方
if(ball.offsetLeft === ballList[i].offsetLeft && ball.offsetTop > ballList[i].offsetTop){
speedY < 0 && (speedY = -speedY);
}
//左下方
if(ball.offsetLeft < ballList[i].offsetLeft && ball.offsetTop > ballList[i].offsetTop){
speedX > 0 && (speedX = -speedX);
speedY < 0 && (speedY = -speedY);
}
//正左方
if(ball.offsetLeft < ballList[i].offsetLeft && ball.offsetTop === ballList[i].offsetTop){
speedX > 0 && (speedX = -speedX);
}
}
}
speedObj.speedX = speedX;
speedObj.speedY = speedY;
return speedObj;
}
複製程式碼
完整程式碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style type="text/css">
html,body {
margin: 0;
padding: 0;
}
#content {
width: 300px;
height: 300px;
border: 1px solid #f00;
position: relative;
}
#content p {
position: absolute;
width: 20px;
height: 20px;
border-radius: 50%;
margin: 0;
}
</style>
</head>
<body>
<div id="content"></div>
</body>
<script>
window.onload = function() {
var content = document.getElementById('content');
var maxMoveX = content.clientWidth - 20;
var maxMoveY = content.clientHeight - 20;
var timer = null;
var ballList = [];
//0. 公共方法(隨機建立)
function random(type) {
switch(type){
case 'color':
return 'rgb(' + Math.floor(Math.random()*255) + ',' + Math.floor(Math.random()*255) + ',' + Math.floor(Math.random()*255) + ')';
case 'top':
return Math.floor(Math.random()*280) + 'px';
case 'left':
return Math.floor(Math.random()*280) + 'px';
case 'speed':
return Math.floor((Math.random() - 0.5)*20);
default:
return false;
}
}
//1. 建立小球
function createBall(num){
var p = null;
for(var i=0; i < num; i++){
p = document.createElement('p');
p.innerHTML = i + 1;
p.style.background = random('color');
p.style.color = '#fff';
p.style.top = random('top');
p.style.left = random('left');
p.style['textAlign'] = 'center';
p.id = 'ball' + i;
content.appendChild(p);
ballList.push(p);
moveBall(p);
}
}
//2. 移動小球
function moveBall(ball, startSX, startSY) {
var speedX = random('speed'),
speedY = random('speed'),
ballMoveX = null,
speedObj = {},
ballMoveY = null;
timer = setInterval(function(){
ballMoveY = ball.offsetTop + speedY;
ballMoveX = ball.offsetLeft + speedX;
if(ballMoveX >= maxMoveX || ballMoveX <= 0){
speedX = -speedX;
}
if(ballMoveY >= maxMoveY || ballMoveY <= 0){
speedY = -speedY;
}
ball.style.top = ballMoveY + 'px';
ball.style.left = ballMoveX + 'px';
speedObj = crashBall(ball, speedX, speedY);
speedX = speedObj.speedX;
speedY = speedObj.speedY;
}, 30)
}
//3. 處理小球間的碰撞
function crashBall(ball, speedX, speedY) {
var speedObj = {};
for(var i = 0; i<ballList.length; i++){
//自己不跟自己比較
if(ball.id !== ballList[i].id && Math.abs(ball.offsetLeft - ballList[i].offsetLeft) <= 20 && Math.abs(ball.offsetTop - ballList[i].offsetTop) <= 20){
//**********物件小球在碰撞小球方位的8個情況***********
//左上方
if(ball.offsetLeft < ballList[i].offsetLeft && ball.offsetTop < ballList[i].offsetTop){
speedX > 0 && (speedX = -speedX);
speedY > 0 && (speedY = -speedY);
}
//正上方(不會影響水平運動的速度)
if(ball.offsetLeft === ballList[i].offsetLeft && ball.offsetTop < ballList[i].offsetTop){
speedY > 0 && (speedY = -speedY);
}
//右上方
if(ball.offsetLeft > ballList[i].offsetLeft && ball.offsetTop < ballList[i].offsetTop){
speedX < 0 && (speedX = -speedX);
speedY > 0 && (speedY = -speedY);
}
//正右方
if(ball.offsetLeft > ballList[i].offsetLeft && ball.offsetTop === ballList[i].offsetTop){
speedX < 0 && (speedX = -speedX);
}
//右下方
if(ball.offsetLeft > ballList[i].offsetLeft && ball.offsetTop > ballList[i].offsetTop){
speedX < 0 && (speedX = -speedX);
speedY < 0 && (speedY = -speedY);
}
//正下方
if(ball.offsetLeft === ballList[i].offsetLeft && ball.offsetTop > ballList[i].offsetTop){
speedY < 0 && (speedY = -speedY);
}
//左下方
if(ball.offsetLeft < ballList[i].offsetLeft && ball.offsetTop > ballList[i].offsetTop){
speedX > 0 && (speedX = -speedX);
speedY < 0 && (speedY = -speedY);
}
//正左方
if(ball.offsetLeft < ballList[i].offsetLeft && ball.offsetTop === ballList[i].offsetTop){
speedX > 0 && (speedX = -speedX);
}
}
}
speedObj.speedX = speedX;
speedObj.speedY = speedY;
return speedObj;
}
createBall(3);
}
</script>
</html>
複製程式碼
關鍵的地方是要向清楚,兩個小球間碰撞後的運動方向,和碰到方框以後的碰撞方向。
好啦,上面就是今天的全部內容啦。
end。。。