效果图
html代码
<div class="container" id="container">
<!-- ----------------音效---------------- -->
<div style="display: none;">
<audio id="audio" loop="loop" src="audio/bgm_zhandou2.mp3"></audio>
<audio id="bomb" src="audio/bomb.wav"></audio>
</div>
<!-- ----------------开始页--------------------->
<div class="start-page" id="start-page">
<div id="title"></div>
<div id="startbtn">开始游戏</div>
</div>
<!-- ----------------主场景--------------------->
<div class="gamescene" id="gamescene">
<!-- ---------背景图1------------->
<div class="scrollmap1" id="scrollmap1"></div>
<!-- ---------背景图2------------->
<div class="scrollmap2" id="scrollmap2"></div>
<!-- ---------飞机层------------->
<div class="map" id="map"></div>
<!--<div id="xyinfo"></div>-->
<!-- ---------分数显示------------->
<div id="score">0</div>
<div id="pausebtn"></div>
<!-- ----------------结果页--------------------->
<div class="game-over-page" id="game-over-page">
<div class="bg"></div>
<div id="panel">
<div id="over-score">100</div>
<div id="replaybtn">重新开始</div>
</div>
</div>
</div>
</div>
<video class="input_video"></video>
<canvas class="output_canvas" width="1280px" height="720px"></canvas>
css代码
* {
padding: 0;
margin: 0;
user-select: none;
}
html,
body {
width: 100%;
height: 100%;
}
body {
overflow: hidden;
background:#000;
}
.container {
width: 512px;
height: 100%;
margin: 0 auto;
position: relative;
}
.start-page {
width: 100%;
height: 100%;
background: url(./img/img_bg_logo.jpg) no-repeat;
background-size: 100% 100%;
background-position: center;
position: absolute;
z-index: 1;
}
.start-page #title {
width: 100%;
height: 200px;
background: url(./img/LOGO.png) no-repeat center;
background-size: 60%;
margin: 0 auto;
margin-top: 150px;
font-size: 72px;
text-align: center;
line-height: 220px;
}
.start-page #startbtn {
width: 300px;
height: 80px;
background: url(./img/button.png) no-repeat center;
background-size: 100%;
margin: 0 auto;
margin-top: 100px;
font-size: 24px;
color: black;
text-align: center;
line-height: 70px;
font-size: 40px;
}
.gamescene {
width: 100%;
height: 100%;
margin: 0 auto;
background: #EEEEEE;
position: absolute;
z-index: 0;
overflow: hidden;
}
#scrollmap1 {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background: url(./img/img_bg_level_1.jpg) no-repeat center;
background-size: 100% 100%;
}
#scrollmap2 {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: -100%;
background: url(./img/img_bg_level_1.jpg) no-repeat center;
background-size: 100% 100%;
}
.map {
width: 100%;
height: 100%;
}
.hero {
width: 80px;
height: 65px;
position: absolute;
left: 100px;
top: 500px;
z-index: 10;
}
#xyinfo {
width: 100px;
height: 30px;
position: absolute;
left: 0;
top: 0;
background: #eee;
z-index: 10;
}
#score {
width: 200px;
height: 100px;
position: absolute;
top: 0;
right: 10px;
font-family: "arial black";
font-size: 72px;
text-align: right;
line-height: 100px;
color: #EEEEEE;
opacity: 0.75;
}
#pausebtn {
width: 50px;
height: 50px;
position: absolute;
top: 10px;
left: 10px;
background: url(./img/button2.png) no-repeat;
background-size: 100%;
}
.bullet {
position: absolute;
z-index: 1;
}
.game-over-page {
width: 100%;
height: 100%;
font-size: 24px;
color: black;
text-align: center;
line-height: 50px;
position: absolute;
top: 0;
z-index: 5;
display: none;
}
.game-over-page .bg {
width: 100%;
height: 100%;
background: black;
opacity: 0.5;
}
#panel {
width: 400px;
height: 300px;
background: url(./img/panel.png) no-repeat center;
background-size: 100% 100%;
font-size: 24px;
color: black;
text-align: center;
line-height: 50px;
position: absolute;
left: 55px;
top: 20%;
}
#replaybtn {
width: 200px;
height: 65px;
background: url(./img/button.png) no-repeat center;
background-size: 100%;
font-size: 24px;
color: black;
text-align: center;
line-height: 50px;
position: absolute;
left: 25%;
bottom: 20%;
}
#over-score {
width: 200px;
height: 100px;
font-family: "arial black";
font-size: 76px;
color: red;
text-align: center;
line-height: 100px;
position: absolute;
left: 25%;
top: 20%;
z-index: 11;
}
.input_video {
position: relative;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
visibility: hidden;
}
.input_video .selfie {
transform: scale(-1, 1);
}
.output_canvas {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: -1;
}
.loading {
display: flex;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
align-items: center;
backface-visibility: hidden;
justify-content: center;
opacity: 1;
transition: opacity 1s;
}
.loading .message {
font-size: x-large;
}
.loading .spinner {
position: absolute;
width: 120px;
height: 120px;
animation: spin 1s linear infinite;
border: 32px solid #bebebe;
border-top: 32px solid #3498db;
border-radius: 50%;
}
js代码
var container = getElement('container');
var gamescene = getElement('gamescene');
var startbtn = getElement('startbtn');
var startPage = getElement('start-page');
var map = getElement('map');
var xyinfo = getElement('xyinfo');
var overPanel = getElement('game-over-page');
var mapleft = map.offsetLeft;
var maptop = map.offsetHeight;
var replaybtn = getElement('replaybtn');
var scoreLabel = getElement('score');
var scrollmap1 = getElement('scrollmap1');
var scrollmap2 = getElement('scrollmap2');
var pausebtn = getElement('pausebtn');
var bullets = [];
var enemies = [];
var hero = null;
var ourPlan = null;
var SCORE = 0;
var GameState = 0;
var tex = {
hero: 'img/hero.png',
enemy: 'img/enemy1.png',
bullet: 'img/bullet1.png',
bomb: 'img/wsparticle_07.png'
}
var enemyTex = [
'img/enemy1.png',
'img/enemy2.png',
'img/enemy3.png',
'img/enemy4.png',
]
startbtn.onclick = function () {
console.log('start game');
startPage.style.display = 'none';
GameState = 1;
start();
}
replaybtn.onclick = function () {
if (GameState == 0) {
GameState = 1;
overPanel.style.display = 'none';
bullets = [];
enemies = [];
SCORE = 0;
scoreLabel.innerHTML = SCORE;
map.innerHTML = '';
start();
}
}
pausebtn.onclick = function () {
pauseGame();
}
var Plan = function (w, h, x, y) {
this.imgNode = null;
this.width = w;
this.height = h;
this.x = x;
this.y = y;
}
Plan.prototype = {
construtor: Plan,
init: function (imagesrc) {
this.imgNode = document.createElement("img");
this.imgNode.style.position = 'absolute';
this.imgNode.style.left = this.x + "px";
this.imgNode.style.top = this.y + "px";
this.imgNode.style.width = this.width + 'px';
this.imgNode.style.height = this.height + 'px';
this.imgNode.src = imagesrc;
map.appendChild(this.imgNode);
},
move: function (speed) {
this.y = this.imgNode.offsetTop + speed;
this.imgNode.style.top = this.y + "px";
return this.y;
},
remove: function () {
this.imgNode.src = 'img/wsparticle_07.png';
var that = this;
(function (node) {
setTimeout(function () {
map.removeChild(node);
}, 200)
})(that.imgNode)
},
fire: function () {
}
}
var Bullet = function (x, y) {
this.x = x;
this.y = y;
if (arguments.length >= 4) {
this.width = arguments[2];
this.height = arguments[3]
} else {
this.width = 15;
this.height = 30;
}
this.imgNode = document.createElement('img');
this.imgNode.style.left = this.x + "px";
this.imgNode.style.top = this.y + "px";
this.imgNode.style.width = this.width + 'px';
this.imgNode.style.height = this.height + 'px';
this.imgNode.setAttribute('class', 'bullet');
this.imgNode.src = tex.bullet;
map.appendChild(this.imgNode);
}
Bullet.prototype = {
constructor: Bullet,
move: function (speed) {
this.speed = speed;
this.y = this.imgNode.offsetTop - this.speed;
this.imgNode.style.top = this.y + "px";
return this.y;
},
remove: function (b, bullets, i) {
if (b.imgNode.parentNode) {
// map.removeChild(b.imgNode);
b.imgNode.parentNode.removeChild(b.imgNode);
bullets.splice(i, 1);
}
}
}
function movePlan() {
var event = window.event || arguments[0];
var selfplanX = event.clientX - container.offsetLeft;
var selfplanY = event.clientY;
var ourPlan = hero.imgNode;
hero.x = selfplanX - hero.width / 2;
hero.y = selfplanY - hero.height / 2;
var w = 512 - 80;
var h = 786 - 80;
hero.x = hero.x > w ? w : hero.x;
hero.x = hero.x < 0 ? 0 : hero.x;
hero.y = hero.y < 0 ? 0 : hero.y;
hero.y = hero.y > h ? h : hero.y;
ourPlan.style.left = hero.x + "px";
ourPlan.style.top = hero.y + "px";
}
function movePlaneWithFinger(x, y) {
if (hero) {
var x = x * document.body.offsetWidth - container.offsetLeft;
var y = y * document.body.offsetHeight;
var ourPlan = hero.imgNode;
hero.x = x - hero.width / 2;
hero.y = y - hero.height / 2;
var w = 512 - 80;
var h = 786 - 80;
hero.x = hero.x > w ? w : hero.x;
hero.x = hero.x < 0 ? 0 : hero.x;
hero.y = hero.y < 0 ? 0 : hero.y;
hero.y = hero.y > h ? h : hero.y;
ourPlan.style.left = hero.x + "px";
ourPlan.style.top = hero.y + "px";
}
}
if (document.addEventListener) {
gamescene.addEventListener("mousemove", movePlan, true);
} else if (document.attachEvent) {
gamescene.attachEvent("onmousemove", movePlan);
}
var updateTimer, fireTimer, addEnemyTimer, scrollbg;
function start() {
hero = new Plan(80, 65, 100, 500);
hero.init(tex.hero);
updateTimer = setInterval(update, 30);
fireTimer = setInterval(fire, 200);
addEnemyTimer = setInterval(addEnemy, 500);
scrollbg = setInterval(scrollBG, 50);
playMusic();
}
function pauseGame() {
console.log('pause:' + GameState)
if (GameState == 1) {
GameState = 2;
clearInterval(updateTimer);
clearInterval(fireTimer);
clearInterval(addEnemyTimer);
} else if (GameState == 2) {
GameState = 1;
updateTimer = setInterval(update, 30);
fireTimer = setInterval(fire, 200);
addEnemyTimer = setInterval(addEnemy, 500);
}
}
function gameOver() {
console.log('game over')
clearInterval(updateTimer);
clearInterval(fireTimer);
clearInterval(addEnemyTimer);
var overscore = getElement('over-score');
overscore.innerHTML = SCORE;
overPanel.style.display = 'block';
}
function scrollBG() {
if (scrollmap1.offsetTop > container.offsetHeight - 10) {
scrollmap1.style.top = '-' + container.offsetHeight + 'px';
} else {
scrollmap1.style.top = scrollmap1.offsetTop + 1 + 'px';
}
if (scrollmap2.offsetTop > container.offsetHeight - 10) {
scrollmap2.style.top = '-' + container.offsetHeight + 'px';
} else {
scrollmap2.style.top = scrollmap2.offsetTop + 1 + 'px';
}
}
function addEnemy() {
var x = Math.random() * 350 + 50;
var ene = new Plan(100, 85, x, 0);
var index = Math.floor(Math.random() * 4);
ene.init(enemyTex[index]);
enemies.push(ene);
}
function fire() {
var ourPlan = hero.imgNode;
var x = ourPlan.offsetLeft + 35;
var y = ourPlan.offsetTop - 10;
var bullet = new Bullet(x, y);
bullets.push(bullet);
}
function update() {
for (var i = 0, l = bullets.length; i < l; i++) {
var b = bullets[i];
if (b) {
var y = b.move(20);
if (y < 0) {
b.remove(b, bullets, i);
}
for (var j = 0, k = enemies.length; j < k; j++) {
var e = enemies[j];
if (e) {
if (collision(b, e)) {
b.remove(b, bullets, i);
e.remove();
// bullets.splice(i,1);
enemies.splice(j, 1);
SCORE++;
scoreLabel.innerHTML = SCORE;
// console.log(SCORE)
playBomb();
}
}
}
}
}
for (var i = 0; i < enemies.length; i++) {
var e = enemies[i];
if (e) {
var y = e.move(5);
if (y > 600) {
enemies.splice(i, 1);
e.remove();
}
if (collision(hero, e)) {
e.remove();
enemies.splice(i, 1);
hero.remove();
GameState = 0;
setTimeout(function () {
gameOver();
}, 200)
}
}
}
}
function collision(a, b) {
if (b.x + b.width > a.x && b.x < a.x + a.width && b.y < a.y + a.height && b.y + b.height > a.y) {
return true;
}
}
function getElement(id) {
return document.getElementById(id);
}
var audio = getElement('audio');
function playMusic() {
audio.play();
}
var bomb = getElement('bomb');
function playBomb() {
if (bomb.currentTime > 0) {
bomb.currentTime = 0
}
bomb.play();
}
const videoElement =
document.getElementsByClassName('input_video')[0];
const canvasElement =
document.getElementsByClassName('output_canvas')[0];
const canvasCtx = canvasElement.getContext('2d');
const mpHands = window
function onResults(results) {
document.body.classList.add('loaded');
if (results.multiHandLandmarks && results.multiHandedness) {
for (let index = 0; index < results.multiHandLandmarks.length; index++) {
const classification = results.multiHandedness[index];
const isRightHand = classification.label === 'Right';
const landmarks = results.multiHandLandmarks[index];
movePlaneWithFinger(landmarks[8].x, landmarks[8].y)
}
}
// canvasCtx.restore();
}
const hands = new Hands({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/hands@0.1.1606863095/${file}`;
}
});
hands.onResults(onResults);
hands.setOptions({
selfieMode: true,
maxNumHands: 1,
minDetectionConfidence: 0.75,
minTrackingConfidence: 0.75
});
const camera = new Camera(videoElement, {
onFrame: async () => {
await hands.send({ image: videoElement });
},
width: 1280,
height: 720
});
camera.start();