JavaScript 实现跳一跳小游戏

  • 文章
  • 作者:Hubery
  • 发布时间:2019-08-01
  • 阅读数:46
  • 分类:前端
  • 标签: 前端

使用Chrome浏览器的可能知道这个,当断网时,页面会出现一个彩蛋小游戏。

微信截图_20190801152657.png

这个还挺好玩,哈哈。(开会无聊时的减压神器)

下面是我用JavaScript实现的差不多的效果(还没人家做的一半好)。这里记录一下实现这个小游戏的思路。作为一个后端程序员,写起原始js还是很累的,其中主要麻烦是实现跳起和下落。这个部分写起来费了很大一部分功夫。原谅这丑陋的ui哈哈哈。主要目的是练练JavaScript。

image.png

效果演示地址https://www.panglb.top/lab/

源代码github地址 欢迎star.

进行游戏分析:

  • 跳动人物

  • 障碍物

  • 人物跳起高度和时间

  • 障碍物往右移动速度和障碍物出现地方

  • 元素相撞

  • 计分

  • 音效

具体实现:

  • 第一步先定义一个背景

<style>
    #game {
        width: 800px; 
        height: 400px;
        background-color: antiquewhite;
        margin: 0 auto;
    }
</style>

<div id="game">
</div>
  • 制作障碍物

function getObstacle() {
    // 页面随机出现一个障碍物
    var obstacle_list = ['images/comma_face_01.png', 'images/comma_face_02.png', 'images/comma_face_03.png', 'images/comma_face_04.png',
        'images/comma_face_05.png', 'images/comma_face_06.png', 'images/comma_face_07.png', 'images/comma_face_08.png',
        'images/comma_face_09.png', 'images/comma_face_10.png', 'images/comma_face_11.png', 'images/comma_face_12.png',
        'images/comma_face_13.png', 'images/comma_face_14.png', 'images/comma_face_15.png','images/comma_face_16.png',
        'images/comma_face_17.png','images/comma_face_18.png'];
    var game = document.getElementById('game');
    var x = game.offsetLeft;
    var y = game.offsetTop;
    var imageName = obstacle_list[parseInt(Math.random() * (obstacle_list.length))];
    var oImg = document.createElement('img');
    oImg.src = imageName;
    oImg.style.width = '64px';
    oImg.style.height = '64px';
    oImg.style.position = 'absolute';
    oImg.style.top = y + 400 - 64 + 'px';
    oImg.style.left = x + 746 + 'px';
    oImg.setAttribute("class", "obstacle");
    # 将元素添加到页面中
    game.appendChild(oImg);
}
  • 实现障碍物向左移动

function obstacleMove(speed) {
    //障碍物进行移动
    var obstacle = document.getElementsByClassName('obstacle')[0];
    var pos = 0;
    var x = obstacle.offsetLeft;
    var id = setInterval(frame, speed);
    function frame() {
        if (pos === 800) {
            //运行到区域外时,删除图片节点
            clearInterval(id);
            var game = document.getElementById('game');
            game.removeChild(obstacle)
        } else {
            pos++;
            obstacle.style.left = x - pos + "px";
        }
    }
}
  • 制作页面跳动的小人物

<--页面上显示人物--!>
< div id='game'>
img src="images/ren_r_1.gif" id='img' style="position: fixed;margin-top: 360px; margin-left: 30px">
  • 义人物切换的方法

function getImageSrc(imagePath) {
    var pos = imagePath.lastIndexOf('/');//从右边数'/'出现的位置
    return imagePath.substr(pos + 1);//取出'/'后一位开始到末尾的子字符串
}
function peopleGo() {
    //  人物切换
    var oImage = document.getElementById('img');
    var image1 = 'ren_r_1.gif';
    var image2 = 'ren_r_2.gif';
    var imageSrc = getImageSrc(oImage.src);
    if (imageSrc === image1) {
        oImage.src = 'images/' + image2;
    } else {
        oImage.src = 'images/' + image1;
    }
}
// setInterval方法可按照指定的周期(以毫秒计)来调用函数或计算表达式
var people_go = setInterval(peopleGo, 100);
  • 此时页面的人物就能显示运动状态了

  • 实现人物跳起和下落

// 用两个函数来实现一次跳起和下落
function move(obj, flag, height, speed, fn) {
    // obj: 传入的对象 flag: 上移还是下移  height:高度  fn:回调函数
    var n = 0;
    var y = parseInt(obj.style.marginTop)
    var timer = setInterval(function () {
        n++;
        if (flag === true) {
            obj.style.marginTop = y - n + "px";
        } else {
            obj.style.marginTop = y + n + "px";
        }
        if (n >= height) {
            clearInterval(timer);
            fn && fn();
        }
    }, speed);
}

function jump() {
    // 跳起和下落实现
    clearInterval(people_go);
    move(oImage, true, 100, 8, function () {
        move(oImage, false, 100, 8, function () {
            people_go = setInterval(peopleGo, 100);
        })
    })
}
  • 使用按空格键控制人物跳起

window.onkeydown = function (ev) {
    var oEvent = ev || window.event;
    var k = oEvent.which || oEvent.keyCode;
    switch (k) {
        case 32:  // 空格
            var top = oImage.offsetTop;
            if (top === 376) {
                jump();
            }
            break;
    }
}
  • 实现检测相撞

function smashTogether() {
    // 碰撞监控
    var obstacle = document.getElementsByClassName('obstacle');
    if (obstacle.length > 0) {
        var peopleWidth = oImage.offsetWidth;
        var peopleHeight = oImage.offsetHeight;
        var top = oImage.offsetTop;
        var left = oImage.offsetLeft;
        var x = obstacle[0].offsetLeft;
        var y = obstacle[0].offsetTop;
        if (((top >= y - peopleHeight) && (top <= y + peopleHeight)) && ((left >= x - peopleWidth) && (left <= x + peopleWidth))) {
            alert('Game Over!');	
        }
    }
}
windows.smashTogether_id = setInterval(smashTogether); // 监控是否碰撞
  • 需要的基本元素已经实现,下面初始化

// 初始化游戏
var flag = true; // 只执行一次init 的标志
var oImage = document.getElementById('img');
function init() {
    var speed = 5;
    var fenshu = 0;
    flag = false;
    window.people_go = setInterval(peopleGo, 100);
    window.smashTogether_id = setInterval(smashTogether); // 监控是否碰撞
    // 物体开始移动
    window.obstacle_id = setInterval(function () {
        var obstacle = document.getElementsByClassName('obstacle');
        if (obstacle.length <= 0) {
            getObstacle();
            obstacleMove(speed)
        }
    }, 10);
    window.score_id = setInterval(function () {
        fenshu += 1;
        var score = document.getElementById('score');
        score.innerHTML = fenshu;
        // console.log(fenshu%100);
        if (fenshu%100 ===0){
            speed -= 0.1
            if (speed <0){
                speed = 0.1
            }
        }
    }, 500);
}
  • 实现按键音效

window.AudioContext = window.AudioContext || window.webkitAudioContext;
    if (!window.AudioContext) {
        alert('当前浏览器不支持Web Audio API');
    }
function sound() {
    // 参考文章 https://www.zhangxinxu.com/wordpress/2017/06/html5-web-audio-api-js-ux-voice/
    var audioCtx = new AudioContext();
    var oscillator = audioCtx.createOscillator();
    // 创建一个GainNode,它可以控制音频的总音量
    var gainNode = audioCtx.createGain();
    // 把音量,音调和终节点进行关联
    oscillator.connect(gainNode);
    // audioCtx.destination返回AudioDestinationNode对象,表示当前audio context中所有节点的最终节点,一般表示音频渲染设备
    gainNode.connect(audioCtx.destination);
    // 指定音调的类型,其他还有square|triangle|sawtooth
    oscillator.type = 'sine';
    // 设置当前播放声音的频率,也就是最终播放声音的调调
    oscillator.frequency.value = 196.00;
    // 当前时间设置音量为0
    gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
    // 0.01秒后音量为1
    gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.01);
    // 音调从当前时间开始播放
    oscillator.start(audioCtx.currentTime);
    // 1秒内声音慢慢降低,是个不错的停止声音的方法
    gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 1);
    // 1秒后完全停止声音
    oscillator.stop(audioCtx.currentTime + 1);
}
  • 监控启动和跳起完整版

window.onkeydown = function (ev) {
    var oEvent = ev || window.event;
    var k = oEvent.which || oEvent.keyCode;
    switch (k) {
        case 32:  // 空格
            var top = oImage.offsetTop;
            if (top === 376) {
                jump();
                sound(); // 按键音效
            }
            break;
        case 13:  // enter键
            if (flag===true){
            	init();
            }
            break;
    }
}


评论列表
优秀的你不评论一下咩!!
新的评论