无法读取null的属性'addEventListener'

时间:2017-07-11 22:01:48

标签: javascript

我正在开展一个大学项目,要求我用javascript构建2D游戏。我现在遇到的一个问题是它无法读取'addEventListener'。这个错误导致我的游戏无法完全运作。

document.getElementById('restart').addEventListener('click', startGame);

这是我使用的完整代码。错误在最底层。

(function()
{
//Define variables
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var player, score, stop, ticker;
var ground = [], water = [], enemies = [], environment = [];

//Platform variables
var platformHeight, platformLength, gapLength;
var platformWidth = 32;
var platformBase = canvas.height - platformWidth;
var platformSpacer = 64;

//Randomly generates a number
function random(low, high)
{
    return Math.floor(Math.random() * (high - low + 1) + low);
}

//Bounds a number
function bound(num, low, high)
{
    return Math.max(Math.min(num, high), low);
}

//Loads all of the assets
var assetLoader = (function()
{
    this.imgs = {
        'bg'            : 'Images/bg.png',
        'sky'           : 'Images/sky.png',
        'backdrop'      : 'Images/backdrop.png',
        'backdrop2'     : 'Images/backdrop_ground.png',
        'grass'         : 'Images/grass.png',
        'avatar_normal' : 'Images/normal_walk.png',
        'water'         : 'imgs/water.png',
        'grass1'        : 'imgs/grassMid1.png',
        'grass2'        : 'imgs/grassMid2.png',
        'bridge'        : 'imgs/bridge.png',
        'plant'         : 'imgs/plant.png',
        'bush1'         : 'imgs/bush1.png',
        'bush2'         : 'imgs/bush2.png',
        'cliff'         : 'imgs/grassCliffRight.png',
        'spikes'        : 'imgs/spikes.png',
        'box'           : 'imgs/boxCoin.png',
        'slime'         : 'imgs/slime.png'
    };

    var assetsLoaded = 0; //How many assets have been loaded
    var numImgs = Object.keys(this.imgs).length; //Total number of image assets
    this.totalAssest = numImgs; //Total number of assets

    function assetLoaded(dic, name)
    {
        if(this[dic][name].status !== 'loading')
        {
            return;
        }

        this[dic][name].status = 'loaded';
        assetsLoaded++;

        if(assetsLoaded === this.totalAssest && typeof this.finished === 'function')
        {
            this.finished();
        }
    }

    this.downloadAll = function()
    {
        var _this = this;
        var src;

        for (var img in this.imgs)
        {
            if (this.imgs.hasOwnProperty(img))
            {
                src = this.imgs[img];

                (function(_this, img)
                {
                    _this.imgs[img] = new Image();
                    _this.imgs[img].status = 'loading';
                    _this.imgs[img].name = img;
                    _this.imgs[img].onload = function() {assetLoaded.call(_this, 'imgs', img)};
                    _this.imgs[img].src = src;
                })(_this, img);
            }
        }
    }

    return{
        imgs: this.imgs,
        totalAssest: this.totalAssest,
        downloadAll: this.downloadAll
    };
})();

assetLoader.finished = function()
{
    startGame();
}

function SpriteSheet(path, frameWidth, frameHeight)
{
    this.image = new Image();
    this.frameWidth = frameWidth;
    this.frameHeight = frameHeight;

    var self = this;
    this.image.onload = function()
    {
        self.framesPerRow = Math.floor(self.image.width / self.frameWidth);
    };

    this.image.src = path;
}

function Animation(spritesheet, frameSpeed, startFrame, endFrame)
{

    var animationSequence = [];
    var currentFrame = 0;
    var counter = 0;

for (var frameNumber = startFrame; frameNumber <= endFrame; frameNumber++)
{
    animationSequence.push(frameNumber);
}

this.update = function()
{
    if (counter == (frameSpeed - 1))
    {
        currentFrame = (currentFrame + 1) % animationSequence.length;
    }
    counter = (counter + 1) % frameSpeed;
};

this.draw = function(x, y)
{
    var row = Math.floor(animationSequence[currentFrame] / spritesheet.framesPerRow);
    var col = Math.floor(animationSequence[currentFrame] % spritesheet.framesPerRow);

    ctx.drawImage
    (
        spritesheet.image,
        col * spritesheet.frameWidth, row * spritesheet.frameHeight,
        spritesheet.frameWidth, spritesheet.frameHeight,
        x, y,
        spritesheet.frameWidth, spritesheet.frameHeight);
    };
}

var background = (function()
{
    var sky   = {};
    var backdrop = {};
    var backdrop2 = {};

    this.draw = function()
    {
        ctx.drawImage(assetLoader.imgs.bg, 0, 0);

        sky.x -= sky.speed;
        backdrop.x -= backdrop.speed;
        backdrop2.x -= backdrop2.speed;

        ctx.drawImage(assetLoader.imgs.sky, sky.x, sky.y);
        ctx.drawImage(assetLoader.imgs.sky, sky.x + canvas.width, sky.y);

        ctx.drawImage(assetLoader.imgs.backdrop, backdrop.x, backdrop.y);
        ctx.drawImage(assetLoader.imgs.backdrop, backdrop.x + canvas.width, backdrop.y);

        ctx.drawImage(assetLoader.imgs.backdrop2, backdrop2.x, backdrop2.y);
        ctx.drawImage(assetLoader.imgs.backdrop2, backdrop2.x + canvas.width, backdrop2.y);

        if (sky.x + assetLoader.imgs.sky.width <= 0)
        {
            sky.x = 0;
        }
        if (backdrop.x + assetLoader.imgs.backdrop.width <= 0)
        {
            backdrop.x = 0;
        }
        if (backdrop2.x + assetLoader.imgs.backdrop2.width <= 0)
        {
            backdrop2.x = 0;
        }
    };

    this.reset = function()
    {
        sky.x = 0;
        sky.y = 0;
        sky.speed = 0.2;

        backdrop.x = 0;
        backdrop.y = 0;
        backdrop.speed = 0.4;

        backdrop2.x = 0;
        backdrop2.y = 0;
        backdrop2.speed = 0.6;
    }

    return{
        draw: this.draw,
        reset: this.reset
    };
})();

//A vector for 2D space
function Vector(x, y, dx, dy)
{
    // position
    this.x = x || 0;
    this.y = y || 0;
    // direction
    this.dx = dx || 0;
    this.dy = dy || 0;
}

//Advances the vector's position
Vector.prototype.advance = function()
{
    this.x += this.dx;
    this.y += this.dy;
};

//Gets the minimum distance between two vectors
Vector.prototype.minDist = function(vec)
{
    var minDist = Infinity;
    var max = Math.max(Math.abs(this.dx), Math.abs(this.dy),Math.abs(vec.dx), Math.abs(vec.dy));
    var slice   = 1 / max;

    var x, y, distSquared;

    // get the middle of each vector
    var vec1 = {}, vec2 = {};
    vec1.x = this.x + this.width/2;
    vec1.y = this.y + this.height/2;
    vec2.x = vec.x + vec.width/2;
    vec2.y = vec.y + vec.height/2;
    for(var percent = 0; percent < 1; percent += slice)
    {
        x = (vec1.x + this.dx * percent) - (vec2.x + vec.dx * percent);
        y = (vec1.y + this.dy * percent) - (vec2.y + vec.dy * percent);
        distSquared = x * x + y * y;

        minDist = Math.min(minDist, distSquared);
    }
    return Math.sqrt(minDist);
};

//The player object
var player = (function(player)
{
    //Player properties
    player.width = 60;
    player.height = 96;
    player.speed = 6;

    //Jumping
    player.gravity = 1;
    player.dy = 0;
    player.jumpDy = -10;
    player.isFalling = false;
    player.isJumping = false;

    //Spritesheets
    player.sheet = new SpriteSheet('Images/normal_walk.png', player.width, player.height);
    player.walkAnim = new Animation(player.sheet, 4, 0, 15);
    player.jumpAnim = new Animation(player.sheet, 4, 15, 15);
    player.fallAnim = new Animation(player.sheet, 4, 11, 11);
    player.anim = player.walkAnim;

    Vector.call(player, 0, 0, 0, player.dy);

    var jumpCounter = 0;

    player.update = function()
    {
        //Jump if not currently jumping or falling
        if(KEY_STATUS.space && player.dy === 0 && !player.isJumping)
        {
            player.isJumping = true;
            player.dy = player.jumpDy;
            jumpCounter = 12;
        }

        //Jump higher if the spacebar is continually pressed
        if(KEY_STATUS.space && jumpCounter)
        {
            player.dy = player.jumpDy;
        }

        jumpCounter = Math.max(jumpCounter - 1, 0);

        this.advance();

        //Gravity
        if(player.isFalling || player.isJumping)
        {
            player.dy += player.gravity;
        }

        //Falling Animation
        if(player.dy > 0)
        {
            player.anim = player.fallAnim;
        }
        // change animation is jumping
        else if(player.dy < 0)
        {
            player.anim = player.jumpAnim;
        }
        else
        {
            player.anim = player.walkAnim;
        }

        player.anim.update();
    };

    //Draw the player's current position
    player.draw = function()
    {
        player.anim.draw(player.x, player.y);
    };

    //Resets the player's position
    player.reset = function()
    {
        player.x = 64;
        player.y = 250;
    };

    return player;
})(Object.create(Vector.prototype));

//Sprites
function Sprite(x, y, type)
{
    this.x = x;
    this.y = y;
    this.width = platformWidth;
    this.height = platformWidth;
    this.type = type;
    Vector.call(this, x, y, 0, 0);

    //Updating the sprites
    this.update = function()
    {
        this.dx = -player.speed;
        this.advancer();
    }

    //Drawing the sprites
    this.draw = function()
    {
        ctx.save();
        ctx.translate(0.5, 0.5);
        ctx.drawImage(assetLoader.imgs[this.type], this.x, this.y);
        ctx.restore();
    }
}
Sprite.prototype = Object.create(Vector.prototype);

//Platforms
function getType()
{
    var type;
    switch(platformHeight)
    {
        case 0:
        case 1:
            type = Math.random() > 0.5 ? 'grass1' : 'grass2';
            break;
        case 2:
            type = 'grass';
            break;
        case 3:
            type = 'bridge';
            break;
        case 4:
            type = 'box';
            break;
    }
    if (platformLength === 1 && platformHeight < 3 && rand(0, 3) === 0)
    {
        type = 'cliff';
    }

    return type;
}

//Update and draw all ground positions
function updateGround()
{
    //Animate ground
    player.isFalling = true;
    for(var i = 0; i < ground.length; i++)
    {
        ground[i].update();
        ground[i].draw();

        //Stop the player going through the platforms when landing
        var angle;
        if(player.minDist(ground[i]) <= player.height/2 + platformWidth/2 && (angle = Math.atan2(player.y - ground[i].y, player.x - ground[i].x) * 180/Math.PI) > -130 &&angle < -50)
        {
            player.isJumping = false;
            player.isFalling = false;
            player.y = ground[i].y - player.height + 5;
            player.dy = 0;
        }
    }

    //Remove the ground that has gone off screen
    if(ground[0] && ground[0].x < -platformWidth)
    {
        ground.splice(0, 1);
    }
}

//Update and draw all water positions
function updateWater()
{
    //Animate water
    for(var i = 0; i < water.length; i++)
    {
        water[i].update();
        water[i].draw();
    }

    //Remove water that has gone off screen
    if (water[0] && water[0].x < -platformWidth)
    {
        var w = water.splice(0, 1)[0];
        w.x = water[water.length-1].x + platformWidth;
        water.push(w);
    }
}

//Update and draw all environment positions
function updateEnvironment()
{
    //Animate environment
    for(var i = 0; i < environment.length; i++)
    {
        environment[i].update();
        environment[i].draw();
    }

    //R emove environment that have gone off screen
    if(environment[0] && environment[0].x < -platformWidth)
    {
        environment.splice(0, 1);
    }
}

//Update and draw all enemies position. Also check for collision against the player.
function updateEnemies()
{
    //Animate enemies
    for(var i = 0; i < enemies.length; i++)
    {
        enemies[i].update();
        enemies[i].draw();

        //Player ran into enemy
        if(player.minDist(enemies[i]) <= player.width - platformWidth/2)
        {
            gameOver();
        }
    }

    //Remove enemies that have gone off screen
    if(enemies[0] && enemies[0].x < -platformWidth)
    {
        enemies.splice(0, 1);
    }
}

//Update and draw the players position
function updatePlayer()
{
    player.update();
    player.draw();

    //Game over
    if(player.y + player.height >= canvas.height)
    {
        gameOver();
    }
}

//Spawn new sprites off screen
function spawnSprites()
{
    //Increase score
    score++;

    //First create a gap
    if(gapLength > 0)
    {
        gapLength--;
    }
    //Then create the ground
    else if(platformLength > 0)
    {
        var type = getType();

        ground.push(new Sprite(
            canvas.width + platformWidth % player.speed,
            platformBase - platformHeight * platformSpacer,
            type
        ));
        platformLength--;

        //Add random environment sprites
        spawnEnvironmentSprites();

        //Add random enemies
        spawnEnemySprites();
    }
    //Start over
    else
    {
        //Increase gap length every speed increase of 4
        gapLength = rand(player.speed - 2, player.speed);
        // only allow a ground to increase by 1
        platformHeight = bound(rand(0, platformHeight + rand(0, 2)), 0, 4);
        platformLength = rand(Math.floor(player.speed/2), player.speed * 4);
    }
}

//Spawn new environment sprites off screen
function spawnEnvironmentSprites()
{
    if(score > 40 && rand(0, 20) === 0 && platformHeight < 3)
    {
        if (Math.random() > 0.5)
        {
            environment.push(new Sprite(canvas.width + platformWidth % player.speed, platformBase - platformHeight * platformSpacer - platformWidth, 'plant'));
        }
        else if(platformLength > 2)
        {
            environment.push(new Sprite(canvas.width + platformWidth % player.speed, platformBase - platformHeight * platformSpacer - platformWidth, 'bush1'));
            environment.push(new Sprite(canvas.width + platformWidth % player.speed + platformWidth, platformBase - platformHeight * platformSpacer - platformWidth, 'bush2'));
        }
    }
}

//Spawn new enemy sprites off screen
function spawnEnemySprites()
{
    if(score > 100 && Math.random() > 0.96 && enemies.length < 3 && platformLength > 5 && (enemies.length ? canvas.width - enemies[enemies.length-1].x >= platformWidth * 3 || canvas.width - enemies[enemies.length-1].x < platformWidth : true))
    {
        enemies.push(new Sprite(canvas.width + platformWidth % player.speed, platformBase - platformHeight * platformSpacer - platformWidth, Math.random() > 0.5 ? 'spikes' : 'slime'));
    }
}

//Game Loop
function animate()
{
    if(!stop)
    {
        requestAnimFrame(animate);
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        background.draw();

        //Update entities
        updateWater();
        updateEnvironment();
        updatePlayer();
        updateGround();
        updateEnemies();

        //Draw the score
        ctx.fillText('Score: ' + score + 'm', canvas.width - 140, 30);

        //Spawn a new Sprite
        if(ticker % Math.floor(platformWidth / player.speed) === 0)
        {
            spawnSprites();
        }

        //Increase player's speed only when player is jumping
        if(ticker > (Math.floor(platformWidth / player.speed) * player.speed * 20) && player.dy !== 0)
        {
            player.speed = bound(++player.speed, 0, 15);
            player.walkAnim.frameSpeed = Math.floor(platformWidth / player.speed) - 1;

            //Reset ticker
            ticker = 0;

            //Spawn a platform to fill in gap created by increasing player speed
            if(gapLength === 0)
            {
                var type = getType();
                ground.push(new Sprite(canvas.width + platformWidth % player.speed, platformBase - platformHeight * platformSpacer, type));
                platformLength--;
            }
        }

        ticker++;
    }
}

//Spacebar events
var KEY_CODES = {
    32: 'space'
};
var KEY_STATUS = {};
for(var code in KEY_CODES)
{
    if(KEY_CODES.hasOwnProperty(code))
    {
        KEY_STATUS[KEY_CODES[code]] = false;
    }
}
document.onkeydown - function(e)
{
    var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
    if(KEY_CODES[keyCode])
    {
        e.preventDefault();
        KEY_STATUS[KEY_CODES[keyCode]] = true;
    }
};
document.onkeydown - function(e)
{
    var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
    if(KEY_CODES[keyCode])
    {
        e.preventDefault();
        KEY_STATUS[KEY_CODES[keyCode]] = false;
    }
};

//Request Animation Polyfill
var requestAnimFrame = (function()
{
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element)
    {
        window.setTimeout(callback, 1000 / 60);
    };
})();

//Start the game and resets all variables and entities, spawn ground and water.
function startGame()
{
    document.getElementById('game-over').style.display = 'none';
    ground = [];
    water = [];
    environment = [];
    enemies = [];
    player.reset();
    ticker = 0;
    stop = false;
    score = 0;
    platformHeight = 2;
    platformLength = 15;
    gapLength = 0;

    ctx.font = '16px arial, sans-serif';

    for (var i = 0; i < 30; i++)
    {
        ground.push(new Sprite(i * (platformWidth-3), platformBase - platformHeight * platformSpacer, 'grass'));
    }

    for (i = 0; i < canvas.width / 32 + 2; i++)
    {
        water.push(new Sprite(i * platformWidth, platformBase, 'water'));
    }

    background.reset();
    animate();
}

//End the game and restart
function gameOver()
{
    stop = true;
    document.getElementById('game-over').style.display = 'block';
}

document.getElementById('restart').addEventListener('click', startGame);

assetLoader.downloadAll();
})();

0 个答案:

没有答案