文档章节

udacity 前端进阶项目1 过河游戏

蓝色犀牛
 蓝色犀牛
发布于 2017/04/23 13:01
字数 3045
阅读 18
收藏 0

app.js

//禁止浏览器滚动条出现,避免在整个游戏未显示完全情况下操作键盘上下左右键出现滚动的情况!
document.body.style.overflow='hidden';
//定义创建积分函数
function createScore(){                  
        var oS=document.createElement("div");
        oS.id="score";
        oS.innerHTML="积分:<span>0</span>----关卡:<span>1</span>";
        oS.style.fontSize=25+"px";
        oS.style.marginTop=50+"px";
        document.body.appendChild(oS);
};
createScore();   //调用创建积分
//保存角色在数组中
var roles=['images/char-boy.png',        
   'images/char-cat-girl.png',
   'images/char-horn-girl.png',
   'images/char-pink-girl.png',
   'images/char-princess-girl.png'];
//每次游戏,角色随机选择  
var rolesNum=Math.floor(Math.random()*5+0);
//定义创建游戏时间函数
function creatTime(){
    var time=document.createElement("div");
    time.id="setTime";
    time.innerHTML='当前关卡剩时:<span id="dd">20</span>秒';
    document.getElementById('score').appendChild(time);
}
creatTime();//调用创建游戏时间
//创建时间秒倒计时函数
function run(){
    var s = document.getElementById("dd");
    if(s.innerHTML == 0){
        resetGame();
    };
    s.innerHTML = s.innerHTML * 1 - 1;
};
setInterval(run, 1000);   //调用秒倒计时
//定义难度系数,控制敌人速度
var level=1;   
//积分初始化
var jf=0;    
//关卡初始化
var gk=1;   
// 这是我们的玩家要躲避的敌人
var Enemy = function(x,y) {
// 要应用到每个敌人的实例的变量写在这里
this.x=x;
this.y=y; 
this.speed=Math.floor(Math.random()*100+100)*level;
// 加载敌人
this.sprite = 'images/enemy-bug.png';
};
// 此为游戏必须的函数,用来更新敌人的位置,参数: dt ,表示时间间隙
Enemy.prototype.update = function(dt) {
 // 你应该给每一次的移动都乘以 dt 参数,以此来保证游戏在所有的电脑上都是以同样的速度运行的
    this.x+=this.speed*dt;
    if(this.x>510){
    this.x=0;
    };
};
// 此为游戏必须的函数,用来在屏幕上画出敌人
Enemy.prototype.render = function() {    
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
};
// 现在实现你自己的玩家类
var Player=function(x,y){     
    this.x=x;
    this.y=y;
    this.sprite = roles[rolesNum]||'images/char-boy.png';
};
// 这个类需要一个 update() 函数, render() 函数和一个 handleInput()函数
Player.prototype.update=function(){
     if(this.x>=400){     //检测玩家右移到边界处,调整x使保持不动
         this.x=400;
     };
     if(this.x<0){        //检测玩家左移到边界处,调整x使保持不动
         this.x=0;
     };
     if(this.y>=400){    //检测玩家下移到边界处,调整x使保持不动
         this.y=400;
     };
};
//渲染角色
Player.prototype.render = function() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
};
//用方向键控制角色移动
Player.prototype.handleInput=function(keyNum){
    switch(keyNum){
        case 'left':
            this.x-=40;
            break;
        case 'up':
            this.y-=40;
            break;
        case 'right':
            this.x+=40;
            break;
        case 'down':
            this.y+=40;
            break;
        default:
            this.x=this.x;
    };
};
// 现在实例化你的所有对象,把所有敌人的对象都放进一个叫 allEnemies 的数组里面
var e1=new Enemy(0,65),
    e2=new Enemy(0,145),
    e3=new Enemy(0,230),
    allEnemies=[e1,e2,e3];
// 把玩家对象放进一个叫 player 的变量里面
var player=new Player(200,400);
// 这段代码监听游戏玩家的键盘点击事件并且代表将按键的关键数字送到 Play.handleInput()方法里面。你不需要再更改这段代码了。
document.addEventListener('keyup', function(e) {
    var allowedKeys = {
        37: 'left',
        38: 'up',
        39: 'right',
        40: 'down'
    };
    player.handleInput(allowedKeys[e.keyCode]);
});
//碰撞检测
function collide(){     
    if(player.y<=60){   //到达水池,游戏胜利
        player.x=200;
        player.y=400;
        jf+=10;         //积分+10
        gk++;            //关卡+1
        level+=0.2;     //难度提升
    for (var i=0;i<allEnemies.length;i++) {       //每个敌人速度整体增加,增加量随机
        allEnemies[i].speed=Math.floor(Math.random()*100+50)*level;
    };    
    var oJ=document.getElementById('score');
    oJ.innerHTML="积分:<span>"+jf+"</span>----关卡:<span>"+gk+"</span>";
    creatTime();
    }else{            //和敌人碰撞
        for(var i=0;i<allEnemies.length;i++){
        var distanceX=Math.abs(player.x-allEnemies[i].x),
            distanceY=Math.abs(player.y-allEnemies[i].y);
        if(distanceX<=70 && distanceY<=60){    //碰撞主要用两者交叉的算法,这里取的70、60是根据实际调整的数字
            resetGame();
            };    
        };    
    };
};
//定义重置游戏函数
function resetGame(){
    alert("游戏结束!单击确定重新再来!");
    window.location.href=window.location.href;
};
//时刻检测碰撞
setInterval(collide,100);

 

/* Engine.js
* 这个文件提供了游戏循环玩耍的功能(更新敌人和渲染)
 * 在屏幕上画出出事的游戏面板,然后调用玩家和敌人对象的 update / render 函数(在 app.js 中定义的)
 *
 * 一个游戏引擎的工作过程就是不停的绘制整个游戏屏幕,和小时候你们做的 flipbook 有点像。当
 * 玩家在屏幕上移动的时候,看上去就是图片在移动或者被重绘。但这都是表面现象。实际上是整个屏幕
 * 被重绘导致这样的动画产生的假象

 * 这个引擎是可以通过 Engine 变量公开访问的,而且它也让 canvas context (ctx) 对象也可以
 * 公开访问,以此使编写app.js的时候更加容易
 */

var Engine = (function(global) {
    /* 实现定义我们会在这个作用于用到的变量
     * 创建 canvas 元素,拿到对应的 2D 上下文
     * 设置 canvas 元素的高/宽 然后添加到dom中
     */
    var doc = global.document,
        win = global.window,
        canvas = doc.createElement('canvas'),
        ctx = canvas.getContext('2d'),
        lastTime;

    canvas.width = 505;
    canvas.height = 606;
    doc.body.appendChild(canvas);

    /* 这个函数是整个游戏的主入口,负责适当的调用 update / render 函数 */
    function main() {
        /* 如果你想要更平滑的动画过度就需要获取时间间隙。因为每个人的电脑处理指令的
         * 速度是不一样的,我们需要一个对每个人都一样的常数(而不管他们的电脑有多快)
         * 就问你屌不屌!
         */
        var now = Date.now(),
            dt = (now - lastTime) / 1000.0;

        /* 调用我们的 update / render 函数, 传递事件间隙给 update 函数因为这样
         * 可以使动画更加顺畅。
         */
        update(dt);
        render();

        /* 设置我们的 lastTime 变量,它会被用来决定 main 函数下次被调用的事件。 */
        lastTime = now;

        /* 在浏览准备好调用重绘下一个帧的时候,用浏览器的 requestAnimationFrame 函数
         * 来调用这个函数
         */
          win.requestAnimationFrame(main)
    }

    /* 这个函数调用一些初始化工作,特别是设置游戏必须的 lastTime 变量,这些工作只用
     * 做一次就够了
     */
    function init() {
        reset();
        lastTime = Date.now();
        main();
    }

    /* 这个函数被 main 函数(我们的游戏主循环)调用,它本身调用所有的需要更新游戏角色
     * 数据的函数,取决于你怎样实现碰撞检测(意思是如何检测两个角色占据了同一个位置,
     * 比如你的角色死的时候),你可能需要在这里调用一个额外的函数。现在我们已经把这里
     * 注释了,你可以在这里实现,也可以在 app.js 对应的角色类里面实现。
     */
    function update(dt) {
        updateEntities(dt);
        // checkCollisions();
    }

    /* 这个函数会遍历在 app.js 定义的存放所有敌人实例的数组,并且调用他们的 update()
     * 函数,然后,它会调用玩家对象的 update 方法,最后这个函数被 update 函数调用。
     * 这些更新函数应该只聚焦于更新和对象相关的数据/属性。把重绘的工作交给 render 函数。
     */
    function updateEntities(dt) {
        allEnemies.forEach(function(enemy) {
            enemy.update(dt);
        });
        player.update();
    }

    /* 这个函数做了一些游戏的初始渲染,然后调用 renderEntities 函数。记住,这个函数
     * 在每个游戏的时间间隙都会被调用一次(或者说游戏引擎的每个循环),因为这就是游戏
     * 怎么工作的,他们就像是那种每一页上都画着不同画儿的书,快速翻动的时候就会出现是
     * 动画的幻觉,但是实际上,他们只是不停的在重绘整个屏幕。
     */
    function render() {
        /* 这个数组保存着游戏关卡的特有的行对应的图片相对路径。 */
        var rowImages = [
                'images/water-block.png',   // 这一行是河。
                'images/stone-block.png',   // 第一行石头
                'images/stone-block.png',   // 第二行石头
                'images/stone-block.png',   // 第三行石头
                'images/grass-block.png',   // 第一行草地
                'images/grass-block.png'    // 第二行草地
            ],
            numRows = 6,
            numCols = 5,
            row, col;

        /* 便利我们上面定义的行和列,用 rowImages 数组,在各自的各个位置绘制正确的图片 */
        for (row = 0; row < numRows; row++) {
            for (col = 0; col < numCols; col++) {
                /* 这个 canvas 上下文的 drawImage 函数需要三个参数,第一个是需要绘制的图片
                 * 第二个和第三个分别是起始点的x和y坐标。我们用我们事先写好的资源管理工具来获取
                 * 我们需要的图片,这样我们可以享受缓存图片的好处,因为我们会反复的用到这些图片
                 */
                ctx.drawImage(Resources.get(rowImages[row]), col * 101, row * 83);
            }
        }

        renderEntities();
    }

    /* 这个函数会在每个时间间隙被 render 函数调用。他的目的是分别调用你在 enemy 和 player
     * 对象中定义的 render 方法。
     */
    function renderEntities() {
        /* 遍历在 allEnemies 数组中存放的作于对象然后调用你事先定义的 render 函数 */
        allEnemies.forEach(function(enemy) {
            enemy.render();
        });

        player.render();
    }

    /* 这个函数现在没干任何事,但是这会是一个好地方让你来处理游戏重置的逻辑。可能是一个
     * 从新开始游戏的按钮,也可以是一个游戏结束的画面,或者其它类似的设计。它只会被 init()
     * 函数调用一次。
     */
    function reset() {
        // 空操作
    }

    /* 紧接着我们来加载我们知道的需要来绘制我们游戏关卡的图片。然后把 init 方法设置为回调函数。
     * 那么党这些图片都已经加载完毕的时候游戏就会开始。
     */
    Resources.load([
        'images/stone-block.png',
        'images/water-block.png',
        'images/grass-block.png',
        'images/enemy-bug.png',
        'images/char-boy.png',
        'images/char-cat-girl.png',
        'images/char-horn-girl.png',
        'images/char-pink-girl.png',
        'images/char-princess-girl.png'
    ]);
    Resources.onReady(init);

    /* 把 canvas 上下文对象绑定在 global 全局变量上(在浏览器运行的时候就是 window
     * 对象。从而开发者就可以在他们的app.js文件里面更容易的使用它。
     */
    global.ctx = ctx;
})(this);

 

/* Resources.js
 * 这是一个简单的图片加载工具。他简化了图片加载的过程从而这些图片可以在你的游戏里面使用。
 * 这个工具还包含一个缓存层从而当你试图加载同一张图片多次的时候可以重复使用缓存的图片
 */

(function() {
    var resourceCache = {};
    var loading = [];
    var readyCallbacks = [];

    /* 这是公开访问的图片加载函数, 它接受一个指向图片文件的字符串的数组或者是单个图片的
     * 路径字符串。然后再调用我们私有的图片加载函数。
     */
    function load(urlOrArr) {
        if(urlOrArr instanceof Array) {
            /* 如果开发者传进来一个图片数组,循环访问每个值,然后调用我们的图片加载器 */
            urlOrArr.forEach(function(url) {
                _load(url);
            });
        } else {
            /* 如果开发者传进来的不是一个数组,那么就可以认为参数值是一个字符串,
             * 然后立即调用我们的图片加载器即可。
             */
            _load(urlOrArr);
        }
    }

    /* 这是我们私有的图片加载函数, 它会被公有的图片加载函数调用 */
    function _load(url) {
        if(resourceCache[url]) {
            /* 如果这个 URL 之前已经被加载了,那么它会被放进我们的资源缓存数组里面,
             * 然后直接返回那张图片即可。
             */
            return resourceCache[url];
        } else {
            /* 否则, 这个 URL 之前没被加载过而且在缓存里面不存在,那么我们得加载这张图片
             */
            var img = new Image();
            img.onload = function() {
                /* 一旦我们的图片已经被加载了,就把它放进我们的缓存,然后我们在开发者试图
                 * 在未来再次加载这个图片的时候我们就可以简单的返回即可。
                 */
                resourceCache[url] = img;
                /* 一旦我们的图片已经被加载和缓存,调用所有我们已经定义的回调函数。
                 */
                if(isReady()) {
                    readyCallbacks.forEach(function(func) { func(); });
                }
            };

            /* 将一开始的缓存值设置成 false 。在图片的 onload 事件回调被调用的时候会
             * 改变这个值。最后,将图片的 src 属性值设置成传进来的 URl 。
             */
            resourceCache[url] = false;
            img.src = url;
        }
    }

    /* 这个函数用来让开发者拿到他们已经加载的图片的引用。如果这个图片被缓存了,
     * 这个函数的作用和在那个 URL 上调用 load() 函数的作用一样。
     */
    function get(url) {
        return resourceCache[url];
    }

    /* 这个函数是否检查所有被请求加载的图片都已经被加载了。
     */
    function isReady() {
        var ready = true;
        for(var k in resourceCache) {
            if(resourceCache.hasOwnProperty(k) &&
               !resourceCache[k]) {
                ready = false;
            }
        }
        return ready;
    }

    /* 这个函数会在被请求的函数都被加载了这个事件的回调函数栈里面增加一个函数。*/
    function onReady(func) {
        readyCallbacks.push(func);
    }

    /* 这个对象通过创造一个公共的资源对象来定义公有的开发者可以访问的函数。*/
    window.Resources = {
        load: load,
        get: get,
        onReady: onReady,
        isReady: isReady
    };
})();
 

 

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Effective JavaScript: Frogger</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <script src="js/resources.js"></script>
    <script src="js/app.js"></script>
    <script src="js/engine.js"></script>
</body>
</html>

css.css

body {
    text-align: center;
}

 

图片类暂没放上来

© 著作权归作者所有

共有 人打赏支持
蓝色犀牛
粉丝 0
博文 21
码字总数 5800
作品 0
沙坪坝
其他
薪资会有怎样的质变,如果懂Python的程序员学了前端

我成为了前端开发的明星学员 前几天收到了 Udacity 的邀请,我被选为了明星学员.Udacity 是 Google 无人车之父创办的硅谷前沿技术学习平台,课程和导师都是来自Google、Facebook、亚马逊等硅...

菜鸟学python
2017/12/10
0
0
5分钟,掌握9个风骚又简洁的JavaScript技巧

5分钟,掌握9个风骚又简洁的JavaScript技巧 编辑于 2018-05-08

优达学城(Udacity)
05/16
0
0
漫画:如何学习人工智能?

什么是人工智能? 人工智能(Artificial Intelligence),英文缩写为AI,它是研究、开发用于模拟和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 上个世纪50年代一次学术讨...

bjweimengshu
01/10
0
0
从零编程基础小白到专业数据分析师,你需要走多远

美国企业与高等教育论坛(BHEF)与普华永道(PWC)近期发布重要报告,数据科学与数据分析的人才需求每年都在增长,而每年的高校毕业生数量远远无法满足行业需求。 就连NBA在选拔球员时也离不...

bf02jgtrs00xktcx
2017/12/13
0
0
学习Python网络课程推荐

首推优达学城,在美国那边经营得非常成功,退出特色的有含金量的纳米学位。 优达学城目前在中国开设了机器学习工程师、iOS 应用开发入门,Android 开发编程入门等等中文纳米学位。纳米学位,...

ApplySquare
01/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

这周撸了两款小程序,分享下关键点。

本周撸了两款小程序,在这里总结下开发过程中的小经验,希望对大家有用。 小程序端 我们先说小程序要注意的地方。 ##默认入口转发问题 当一个小程序Page的js文件中存在 onShareAppMessage 方...

阿北2017
18分钟前
1
0
物联网技术很新吗?不!都是旧技术

通常,当我们想到物联网时,我们会想到新的、令人兴奋的现代技术。毕竟,还有什么比不用起床就能通过智能手机告诉咖啡机开始煮晨杯的“未来”更重要呢? 多亏了物联网,我们可以在世界任何地方...

linuxCool
26分钟前
1
0
利用责任链模式设计一个拦截器

前言 近期在做 Cicada 的拦截器功能,正好用到了责任链模式。 这个设计模式在日常使用中频率还是挺高的,借此机会来分析分析。 责任链模式 先来看看什么是责任链模式。 引用一段维基百科对其...

crossoverJie
44分钟前
2
0
属性动画

透明度 alpha 平移translationX/translationY 旋转 rotation 缩放 scaleX/scaleY 多个动画一起AnimatorSet 透明度 ObjectAnimator oa = ObjectAnimator.ofFloat(iv,"alpha" ......

lanyu96
45分钟前
1
0
Docker和Kubernetes如何让DevOps更具效力

缩短time-to-makrt对于任何一家企业都至关重要,这直接决定了客户满意度、市场竞争力乃至盈利能力。但在部署应用时,大多数企业内的IT团队都或多或少会遇到Dev和Ops之间的问题,这两个部门围...

好雨云帮
53分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部