废话不多说,直接上源码
在Web应用中,实现动画效果的方法比较多,Javascript 中可以通过定时器 setTimeout/ setInterval 来实现,css3 可以使用 transition和 animation 来实现,html5 中的 canvas 也可以实现。除此之外,html5 还提供一个专门用于请求动画的API,那就是 requestAnimationFrame。
原文详解链接:https://blog.csdn.net/qq_45890970/article/details/123576140
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
font-family: "Microsoft yahei", serif;
}
li {
list-style-type: none;
}
body {
overflow: hidden;
user-select: none;
/* 禁止选择文字 */
-moz-user-select: -moz-none;
/* 禁止鼠标右键复制 */
-ms-user-select: none;
}
#box {
position: relative;
width: 512px;
height: 768px;
margin: 20px auto;
}
#map {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url("img/bg_1.jpg");
}
#level {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
}
#level h1 {
font-size: 40px;
padding-top: 60px;
padding-bottom: 150px;
line-height: 60px;
text-align: center;
color: #fff;
}
#level p {
margin: 30px auto;
width: 200px;
height: 35px;
line-height: 35px;
text-align: center;
background: #fff;
font-weight: bolder;
cursor: pointer;
}
#level p:hover {
background: pink;
color: #fff;
}
#map .plane,
#map .biu,
#map .enemy,
#map .boom,
#map .boom2 {
position: absolute;
}
#map .plane {
z-index: 8;
}
#map .biu {
z-index: 10;
}
#map .boom2 {
z-index: 11;
animation: bling 2s 1;
animation-fill-mode: forwards;
}
#map .enemy {
z-index: 9;
}
#map .boom {
z-index: 7;
animation: fade .8s 1;
animation-fill-mode: forwards;
}
/*爆炸后的消失效果*/
/* @keyframes动画是循环的
而transform 只执行一遍. */
@keyframes fade {
from {
/* “1”完全不透明 */
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes bling {
0% {
opacity: 1;
}
20% {
opacity: 0;
}
40% {
opacity: 1;
}
60% {
opacity: 0;
}
80% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#score {
display: none;
position: absolute;
top: 10px;
left: 10px;
color: #fff;
line-height: 20px;
font-size: 14px;
font-weight: bold;
/* z-index 属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。 */
z-index: 20;
}
#restart {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 30;
}
#restart p {
width: 300px;
height: 40px;
line-height: 20px;
margin: 140px auto;
color: #fff;
}
#restart p span {
display: block;
font-weight: bolder;
font-size: 22px;
text-align: center;
}
#restart .p1 span {
color: red;
}
#restart .p2 span {
color: #ffa80c;
}
#restart .p3 {
font-family: "楷体";
font-size: 20px;
width: 100px;
height: 35px;
background: rgb(255, 255, 255);
background: rgba(255, 255, 255, .8);
color: #000;
font-weight: bolder;
line-height: 35px;
text-align: center;
border-radius: 3px;
/* 设置浏览网页时鼠标光标的样式为手 */
cursor: pointer;
}
#restart .p3:hover {
background: white;
}
</style>
<script type="text/javascript">
window.onload = function () {
/*
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
*/
// requestAnimationFrame实现无限循环动画
window.requestAnimationFrame = window.requestAnimationFrame || function (fn) {
// 间隔时间为每秒60帧
// 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
// 一般来说,这个频率为每秒60帧
return setTimeout(fn, 1000 / 60)
};
//方法用于取消以前通过对window.requestAnimationFrame()的调用计划的动画帧请求。
window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
//定义全局变量,获取数据
var oBox = document.getElementById("box"),
oScore = document.getElementById("score"),
oRe = document.getElementById("restart"),
oLevel = document.getElementById("level"),
oMap = document.getElementById("map"),
oBiuAll = document.getElementById("BiuAll"),
// 获取节点
allBiu = oBiuAll.children,
allReChild = oRe.children,
// offsetTop是找距离定位父级左边的距离,没有定位则找body
boxOffsetTop = oBox.offsetTop,
// offsetLeft是找距离定位父级上边的距离
boxOffsetLeft = oBox.offsetLeft;
//启动
exe();
//初始选择难度界面的点击事件
function exe() {
//难度选择
var aP = oLevel.getElementsByTagName("p");
for (var i = 0, length = aP.length; i < length; i++) {
(function (i) {
aP[i].onclick = function (e) {
e = e || window.event;
startGame(i, {
x: e.clientX - boxOffsetLeft,
y: e.clientY - boxOffsetTop
});//第一个实参为序号 ,第二个实参为存储着鼠标距离map边缘距离的json
}
})(i);
}
//restart按钮
allReChild[2].onclick = function (ev) {
// cancelAnimationFrame(oMap.bgTimer);//停止背景滚动
oRe.style.display = "none";
oLevel.style.display = "block";
oScore.innerHTML = 0;
oMap.innerHTML = "";
oBiuAll = document.getElementById("BiuAll");
allBiu = oBiuAll.children;
};
}
//开始游戏
function startGame(level, pos) {
//执行 隐藏和清理
clearMap();
//执行 Map背景相关操作
MapBg(level);
//执行 创建我军
var p = plane(level, pos);
//执行 创建敌军
enemy(level, p);
//enemy(level , plane(level , pos));
//得分清零
oBox.score = 0;
}
//隐藏和清理
function clearMap() {
oScore.style.display = "block";
oLevel.style.display = "none";//隐藏关卡选择框
}
//Map背景选择与运动
function MapBg(level) {
oMap.style.backgroundImage = "url('img/bg_" + (level + 1) + ".gif')";
(function m() {
oMap.bgPosY = oMap.bgPosY || 0;
// oMap.bgPosY++;//背景移动
oMap.style.backgroundPositionY = oMap.bgPosY + 'px';
oMap.bgTimer = requestAnimationFrame(m);
})();
}
//创建我军
function plane(level, pos) {
//创建我军图片
var oImg = new Image();
oImg.src = "img/plane_0.png";
oImg.width = 70;
oImg.height = 70;
oImg.className = "plane";
oImg.style.left = pos.x - oImg.width / 2 + 'px';
oImg.style.top = pos.y - oImg.height / 2 + 'px';
oMap.appendChild(oImg);
//边界值
var leftMin = -oImg.width / 2,
leftMax = oMap.clientWidth - oImg.width / 2,
topMin = 0,
topMax = oMap.clientHeight - oImg.height / 2;
//加入mousemove事件(飞机移动)
document.onmousemove = function (ev) {
ev = ev || window.event;
//获取飞机实时坐标,并限制边界值
var left = ev.clientX - boxOffsetLeft - oImg.width / 2;
var top = ev.clientY - boxOffsetTop - oImg.height / 2;
left = Math.max(leftMin, left);
left = Math.min(leftMax, left);
top = Math.max(topMin, top);
top = Math.min(topMax, top);
//赋值
oImg.style.left = left + 'px';
oImg.style.top = top + 'px';
};
//调用子弹函数
fire(oImg, level);
return oImg;
}
//我军子弹
function fire(oImg, level) {
oBox.biuInterval = setInterval(function () {
if (oBox.score >= 500) {
createBiu(true, -1);
createBiu(true, 1);
} else {
createBiu();
}
}, [100, 200, 200, 15][level]);
function createBiu(index, d) {
//创建子弹
var oBiu = new Image();
oBiu.src = "img/fire1.png";
oBiu.width = 30;
oBiu.height = 30;
oBiu.className = "biu";
var left = oImg.offsetLeft + oImg.width / 2 - oBiu.width / 2;
var top = oImg.offsetTop - oBiu.height + 5;
if (index) {
left += oBiu.width * d
}
oBiu.style.left = left + "px";
oBiu.style.top = top + 'px';
oBiuAll.appendChild(oBiu);
//子弹运动
function m() {
if (oBiu.parentNode) {
var top = oBiu.offsetTop - 20;
if (top < -oBiu.height) {
oBiuAll.removeChild(oBiu);
} else {
oBiu.style.top = top + 'px';
requestAnimationFrame(m);
}
}
}
//将运动执行队列放后面,不然子弹会直接初始就在 top-50 的位置
setTimeout(function () {
requestAnimationFrame(m);
}, 50);
}
}
//创建敌军
function enemy(level, oPlane) {
var w = oMap.clientWidth,
h = oMap.clientHeight;
var speed = [5, 6, 8, 8][level]; //敌军下落速度
var num = 1;
oBox.enemyIntetval = setInterval(function () {
var index = num % 30 ? 1 : 0;
//生成敌军
var oEnemy = new Image();
oEnemy.index = index;
oEnemy.HP = [20, 1][index];
oEnemy.speed = speed + (Math.random() * 0.6 - 0.3) * speed;
oEnemy.speed *= index ? 1 : 0.5;
oEnemy.src = "img/enemy_" + ["big", "small"][index] + ".png";
oEnemy.className = "enemy";
oEnemy.width = [104, 54][index];
oEnemy.height = [80, 40][index];
oEnemy.style.left = Math.random() * w - oEnemy.width / 2 + 'px';
oEnemy.style.top = -oEnemy.height + 'px';
oMap.appendChild(oEnemy);
num++;
//敌军运动
function m() {
if (oEnemy.parentNode) {
var top = oEnemy.offsetTop;
top += oEnemy.speed;
if (top >= h) {
//漏掉飞机减分
oBox.score--;
oScore.innerHTML = oBox.score;
oMap.removeChild(oEnemy);
} else {
oEnemy.style.top = top + 'px';
//子弹碰撞检测
for (var i = allBiu.length - 1; i >= 0; i--) {
var objBiu = allBiu[i];
if (coll(oEnemy, objBiu)) {
//移除子弹
oBiuAll.removeChild(objBiu);
oEnemy.HP--;
if (!oEnemy.HP) {
//打掉飞机加分
oBox.score += oEnemy.index ? 2 : 20;
oScore.innerHTML = oBox.score;
//敌军爆炸图
boom(oEnemy.offsetLeft, oEnemy.offsetTop, oEnemy.width, oEnemy.height, index ? 0 : 2);
//移除敌军
oMap.removeChild(oEnemy);
return;
}
}
}
//我军碰撞检测
if (oPlane.parentNode && coll(oEnemy, oPlane)) {
//敌军爆炸图
boom(oEnemy.offsetLeft, oEnemy.offsetTop, oEnemy.width, oEnemy.height, index ? 0 : 2);
//我军爆炸图
boom(oPlane.offsetLeft, oPlane.offsetTop, oPlane.width, oPlane.height, 1);
//移除敌军
oMap.removeChild(oEnemy);
//移除我军
oMap.removeChild(oPlane);
GameOver();
return;
}
requestAnimationFrame(m);
}
}
}
requestAnimationFrame(m);
}, [350, 150, 120, 40][level]);
}
//爆炸函数
function boom(l, t, w, h, i) {
var oBoom = new Image();
oBoom.src = "img/" + ["boom_small", "plane_0", "boom_big"][i] + ".png";
oBoom.className = 'boom' + ["", "2", ""][i];
oBoom.width = w;
oBoom.height = h;
oBoom.style.left = l + "px";
oBoom.style.top = t + 'px';
oMap.appendChild(oBoom);
setTimeout(function () {
oBoom.parentNode && oMap.removeChild(oBoom);
}, [1200, 2500, 1200][i]);
}
//两个物体 碰撞检测
function coll(obj1, obj2) {
var T1 = obj1.offsetTop,
B1 = T1 + obj1.clientHeight,
L1 = obj1.offsetLeft,
R1 = L1 + obj1.clientWidth;
var T2 = obj2.offsetTop,
B2 = T2 + obj2.clientHeight,
L2 = obj2.offsetLeft,
R2 = L2 + obj2.clientWidth;
return !(B1 < T2 || R1 < L2 || T1 > B2 || L1 > R2);
}
//游戏结束
function GameOver() {
document.onmousemove = null; //清除移动事件
clearInterval(oBox.biuInterval);//不再产生新子弹
clearInterval(oBox.enemyIntetval);//不再产生新敌军
restart();
}
//结算+重新开始
function restart() {
oScore.style.display = "none";
var s = oBox.score;
var honor;
if (s < -300) {
honor = "闪避+MAX!!!";
} else if (s < 10) {
honor = "菜得…算了我不想说了…";
} else if (s < 30) {
honor = "抠脚侠!";
} else if (s < 100) {
honor = "初级飞机大师";
} else if (s < 200) {
honor = "渐入佳境";
} else if (s < 500) {
honor = "中级飞机大师";
} else if (s < 1000) {
honor = "高级飞机大师";
} else if (s < 5000) {
honor = "终极飞机大师";
} else {
honor = "孤独求败!";
}
oRe.style.display = "block";
allReChild[0].children[0].innerHTML = s;
allReChild[1].children[0].innerHTML = honor;
}
}
</script>
</head>
<div id="box">
<div id="level">
<h1>飞机大作战</h1>
<p>简单</p>
<p>中等</p>
<p>困难</p>
<p style="color: #f00">开挂啊</p>
</div>
<div id="map">
<div id="BiuAll"></div>
</div>
<div id="score">0</div>
<div id="restart">
<p class="p1">您的最终得分是:<span>0</span></p>
<p class="p2">获得称号:<span>抠脚侠</span></p>
<p class="p3">重新开始</p>
</div>
</div>
</body>
</html>
以上就是今天所展示的内容,本文是我初学这门课程后做的一个实战小项目,欢迎何为大佬留言指点