Demo: pacman

Click on the image below to lock mouse cursor to demo. Open demo in new window.

Source

grammar("JavaScript");
var GRASS = "../shared_assets/images/grass.png",
  ROCK = "../shared_assets/images/rock.png",
  SAND = "../shared_assets/images/sand.png",
  WATER = "../shared_assets/images/water.png",
  DECK = "../shared_assets/images/deck.png",
  CODE_KEY = "Pacman code",

  env = new Primrose.BrowserEnvironment({
    backgroundColor: 0x000000,
    skyTexture: DECK,
    groundTexture: DECK,
    font: "../shared_assets/fonts/helvetiker_regular.typeface.json",
    fullScreenButtonContainer: "#fullScreenButtonContainer"
  }),

  editor = null,

  modA = isMacOS ? "metaKey" : "ctrlKey",
  modB = isMacOS ? "altKey" : "shiftKey",
  cmdA = isMacOS ? "CMD" : "CTRL",
  cmdB = isMacOS ? "OPT" : "SHIFT",
  cmdPre = cmdA + "+" + cmdB,

  scriptUpdateTimeout,
  lastScript = null,
  scriptAnimate = null,

  subScene = hub();

env.addEventListener("ready", function () {
  env.scene.add(subScene);

  var editorSize = isMobile ? 512 : 1024,
    fontSize = isMobile ? 10 : 20;

  editor = new Primrose.Controls.TextBox({
      id: "Editor",
      width: editorSize,
      height: editorSize,
      geometry: shell(1.5, 25, 25),
      fontSize: fontSize,
      tokenizer: Primrose.Text.Grammars.JavaScript,
      value: getSourceCode(isInIFrame)
    })
    .addTo(env.vicinity)
    .at(0, env.options.avatarHeight, 0);

  Preloader.hide();
}, false);

window.addEventListener("beforeunload", function (evt) {
  if (false && editor && editor.value !== getSourceCode(true)) {
    return evt.returnValue = "Are you sure you want to leave?";
  }
}, false);

window.addEventListener("unload", function (evt) {
  var script = editor && editor.value;
  if (script && script.length > 0) {
    setSetting(CODE_KEY, script);
  }
}, false);

env.addEventListener("update", function () {
  if (!scriptUpdateTimeout) {
    scriptUpdateTimeout = setTimeout(updateScript, 500);
  }

  if (scriptAnimate) {
    // If quality has degraded, it's likely because the user bombed on a script.
    // Let's help them not lose their lunch.
    if (env.quality === Primrose.Constants.Quality.NONE) {
      scriptAnimate = null;
      wipeScene();
    }
    else {
      try {
        scriptAnimate.call(env, env.deltaTime);
      }
      catch (exp) {
        console.error(exp);
        scriptAnimate = null;
      }
    }
  }
});

function getSourceCode(skipReload) {
  var defaultDemo = pacman.toString(),
    src = skipReload && defaultDemo || getSetting(CODE_KEY, defaultDemo);
  // If there was no source code stored in local storage,
  // we use the script from a saved function and assume
  // it has been formatted with 2 spaces per-line.
  if (src === defaultDemo) {
    var lines = src.replace("\r\n", "\n")
      .split("\n");
    lines.pop();
    lines.shift();
    for (var i = 0; i < lines.length; ++i) {
      lines[i] = lines[i].substring(2);
    }
    src = lines.join("\n");
  }
  return src.trim();
}

env.addEventListener("keydown", function (evt) {
  if (evt[modA] && evt[modB]) {
    if (evt.keyCode === Primrose.Keys.E) {
      editor.visible = !editor.visible;
    }
    else if (evt.keyCode === Primrose.Keys.X) {
      editor.value = getSourceCode(true);
    }
  }

  if (scriptUpdateTimeout) {
    clearTimeout(scriptUpdateTimeout);
    scriptUpdateTimeout = null;
  }
});

function wipeScene() {
  for (var i = subScene.children.length - 1; i >= 0; --i) {
    subScene.remove(subScene.children[i]);
  }
}

var first = true;
function updateScript() {
  var newScript = editor.value,
    exp;
  if (newScript !== lastScript) {
    env.transition(function() {
      scriptUpdateTimeout = null;
      lastScript = newScript;
      if (newScript.indexOf("function update") >= 0 &&
        newScript.indexOf("return update") < 0) {
        newScript += "\nreturn update;";
      }
      console.log("----- loading new script -----");
      scriptAnimate = null;
      try{
        var scriptUpdate = new Function("scene", newScript);
        wipeScene();
        scriptAnimate = scriptUpdate.call(env, subScene);
        if (scriptAnimate) {
          scriptAnimate(0);
        }
        console.log("----- script loaded -----");
        if (!scriptAnimate) {
          console.log("----- No update script provided -----");
        }
        else if (env.quality === Primrose.Constants.Quality.NONE) {
          env.quality = Primrose.Constants.Quality.MEDIUM;
        }
      }
      catch(exp){
        scriptUpdate = null;
        console.error(exp);
        console.error(newScript);
      }
    }, null, first);
    first = false;
  }
}



function pacman() {
  var R = Primrose.Random.int,
    L = Primrose.Graphics.ModelFactory.loadObject,
    T = 3,
    W = 30,
    H = 30,
    colors = [
      0xff0000,
      0xffff00,
      0xff00ff,
      0x00ffff
    ],
    ghosts,
    map = [
      "12222222221",
      "10000000001",
      "10222022201",
      "10001000001",
      "10101022201",
      "10100010101",
      "10222220101",
      "10000000001",
      "12222222221"
    ];

  function C(n, x, y) {
    if (n !== 0) {
      cylinder(0.5, 0.5, T)
        .colored(0x0000ff)
        .addTo(scene)
        .rot(0, n * Math.PI / 2, Math.PI / 2)
        .at(T * x - W / 2, env.options.avatarHeight, T * y - H / 2);
    }
  }

  for (var y = 0; y < map.length; ++y) {
    var row = map[y];
    for (var x = 0; x < row.length; ++x) {
      C(row[x] | 0, x, y);
    }
  }
  console.log("Here we go");
  L("../shared_assets/models/ghost.obj")
    .then(function (ghost) {
      console.log("ghost", ghost);
      ghosts = colors.map(function (color, i) {
        var g = ghost.clone(),
          body = g.children[0];
        colored(body, color);
        scene.appendChild(g);
        g.position.set(i * 3 - 4, 0, -5);
        g.velocity = v3(0, 0, 0);
        g.velocity.x = R(-1, 2);
        if (g.velocity.x === 0 && g.velocity.z === 0) {
          g.velocity.z = R(-1, 2);
        }
        return g;
      });
    });

  function collisionCheck(dt, a, t) {
    var x = Math.floor((a.position.x + W / 2 + 1) / T),
      y = Math.floor((a.position.z + H / 2 + 1) / T),
      row = map[y],
      tile = row && row[x] | 0;
    var v = a.velocity.clone()
      .multiplyScalar(-dt * 1.5);
    if (tile > 0) {
      if (t || a.isOnGround) {
        a.position.add(v);
      }
      if (t) {
        a.velocity.set(
          a.velocity.z,
          0, -a.velocity.x
        );
      }
    }
  }

  return function (dt) {
    if (ghosts) {
      ghosts.forEach(function (g) {
        g.position.add(g.velocity.clone()
          .multiplyScalar(dt));
        collisionCheck(dt, g, env.head);
      });
    }
    collisionCheck(dt, env.head, null);
  }
}