简体   繁体   中英

Javascript game, array and object literals

I'm working on a game for Windows 8 in HTML5 and JavaScript. I have a working version of the game that stores "roach" objects in an array. I am trying to put the game code i have into a sample from Microsoft ( linked here ). In this example they decalere a set of object literals for the game state that are saved and used in various classes:

internal: {
    gamePaused: false,
    gamePhase: "ready",
    speed: 5,
    score: 0,
}

In there I would like to put the array for my roach objects. I thought I could do:

roaches: [],

but when I call:

this.state.roaches.push(new Roach());
this.state.roaches.length;

I get a:

JavaScript runtime error: Unable to get property 'length' of undefined or null reference

What am I doing wrong and how can I fix it?

Nat

additional info:

alright so here is my roach class:

var Roach = WinJS.Class.define( function () {
    this.position.x = Math.random() * gameCanvas.width + 1;
    this.position.y = Math.random() * gameCanvas.height + 1;
    this.squished = false;
    this.image = GameManager.assetManager.assets.roachImage;
},
{
    move: function (speed) {
        // changes position
    },
    squish: function() {

    }
});

this is in a file called game.js which contains another class:

var Game = WinJS.Class.define(
    null,
{
// other functions
// Called when the game is being prepared to start
    ready: function () {
        // TODO: Replace with your own new game initialization logic
        if (this.isSnapped()) {
            this.state.gamePaused = true;
        } else {
            this.state.gamePaused = false;
        }
        this.state.gamePhase = "ready";
        switch (this.settings.skillLevel) {
            case 0:
                this.state.speed = 3;
                break;
            case 1:
                this.state.speed = 5;
                break;
            case 2:
                this.state.speed = 10;
                break;
        }
        this.state.roaches.push(new Roach());
        this.state.score = 0;
    },
// Main game render loop
    draw: function () {
        this.gameContext.clearRect(0, 0, gameCanvas.width, gameCanvas.height);

        // TODO: Sample game rendering to be replaced

        // Draw the current score
        this.gameContext.fillStyle = "#FFFF99";
        this.gameContext.font = "bold 48px Segoe UI";
        this.gameContext.textBaseline = "middle";
        this.gameContext.textAlign = "right";
        this.gameContext.fillText(this.state.score, gameCanvas.width - 5, 20);

        // update image positions
        // THROWS ERROR HERE
        for (var i = 0; i < this.state.roaches.length; i++) {
            if (!this.state.roaches[i].squished) {

            }
        }

        // Draw a ready or game over or paused indicator
        if (this.state.gamePhase === "ready") {
            this.gameContext.textAlign = "center";
            this.gameContext.fillText("READY", gameCanvas.width / 2, gameCanvas.height / 2);
        } else if (this.state.gamePhase === "ended") {
            this.gameContext.textAlign = "center";
            this.gameContext.fillText("GAME OVER", gameCanvas.width / 2, gameCanvas.height / 2);
        } else if (this.state.gamePaused) {
            this.gameContext.textAlign = "center";
            this.gameContext.fillText("PAUSED", gameCanvas.width / 2, gameCanvas.height / 2);
        }
    }

Now in a file called gameState.js a gameState class is defined that holds the variables that I referenced earlier.

var GameState = WinJS.Class.define(
    null,
{
    config: {
    // TODO: Adjust these values to configure the template itself
        frameRate: 20, // Set to 0 to have no update loop at all
        minSquished: 20,
        currentPage: "/html/homePage.html",
        gameName: "SDK Game Sample", // Used by share contract on scores page
    },

    // TODO: Replace these public settings exposed on the settings panel
    external: {
        playerName: "Player",
        soundVolume: 100,
        skillLevel: 0,
    },

    // TODO: Replace these values with state variables relevant for your game
    internal: {
        gamePaused: false,
        gamePhase: "ready",
        roaches: [],
        speed: 5,
        score: 0,
    },

These files are assembled under the GameManager namespace which calls each class from the files and creates them under that namespace. So when the user starts the game the ready function is called by the GameManager and then the draw function is called to update the screen. Hopefully this helps clarify.

the namespace is defined here:

 var game = new Game();
 var touchPanel = new TouchPanel();
 var state = new GameState();
 state.load();

WinJS.Namespace.define("GameManager", {
        navigateHome: navigateHome,
        navigateGame: navigateGame,
        navigateRules: navigateRules,
        navigateScores: navigateScores,
        navigateCredits: navigateCredits,
        showPreferences: showPreferences,
        onBeforeShow: onBeforeShow,
        onAfterHide: onAfterHide,
        game: game,
        state: state,
        assetManager: assetManager,
        scoreHelper: scoreHelper,
        gameId: gameId,
        touchPanel: touchPanel
    });

I had a similar issue with writing to object literals then reading back the data and getting an error. Apparently, this is a gray area in two instances:

  1. The key/value pair is added using dot notation
  2. The object literal is accessed asynchronously

In the first case, the spec doesn't guarantee that the read operation will work. In the second case, you have to handle the access via:

  • multiple callbacks
  • a callback which handles multiple data types

You can test it with a simple one liner:

  var foo = {}; foo["bar"] = []; setTimeout(function(){foo.bar.push(new Date); console.log('Hi ' + foo.bar.length)}, 5000); 

References

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM