web前端项目-超级玛丽【附源码】

发布时间:2024年01月22日

超级玛丽

【超级玛丽】是一个基于HTML5JavaScript开发的经典电子游戏。玩家需要控制主角马里奥在各种关卡中跳跃、奔跑、消灭敌人,以完成游戏目标。玩家通过浏览器可以体验经典的超级玛丽关卡和冒险。

运行效果:方向键控制马里奥的左右移动、跳跃、奔跑;CTRL键发射子弹
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

HTML源码-mario.html

<!DOCTYPE html>
<html lang="en-us">
<head>
    <meta charset="utf-8">
    <title>Full Screen Mario</title>
    <link href="mario.css" rel="stylesheet">
    <link href="Fonts/stylesheet.css" rel="stylesheet">
    <script src="data.js"></script>
    <script src="editor.js"></script>
    <script src="events.js"></script>
    <script src="generator.js"></script>
    <script src="library.js"></script>
    <script src="load.js"></script>
    <script src="maps.js"></script>
    <script src="mario.js"></script>
    <script src="quadrants.js"></script>
    <script src="sounds.js"></script>
    <script src="sprites.js"></script>
    <script src="things.js"></script>
    <script src="toned.js"></script>
    <script src="triggers.js"></script>
    <script src="upkeep.js"></script>
    <script src="utility.js"></script>
    <script src="gamepad.js"></script>
</head>
<body onload="FullScreenMario()">
</body>
</html>

CSS源码-mario.css

html { background: black; }
html, body, .text, .display {
  border: 0;
  margin: 0;
  padding: 0;
  color: #fafafa;
  text-align: center;
  vertical-align: middle;
  font-family: 'Press Start';
  z-index: 84;
  -webkit-font-smoothing: none;
  -webkit-user-select: none;
}

body { 
  width: 100%;
  height: 100%;
  overflow: hidden;
}

canvas {
  position: absolute;
  left: 0;
}

.display {
  position: fixed;
  font-size: 21px;
}
.indisplay {
  margin: 7px 14px 0 14px;
  text-align: center;
  z-index: 14;
}
.indisplay.counter, .indisplay.seed {
  position: fixed;
  padding: 3px 7px;
  bottom: 0;
  background: rgba(0,0,0,.49);
}
.indisplay.counter { right: 0; }
.indisplay.seed{ left: 0; }

.text {
  position: absolute;
  z-index: 14;
  text-align: left;
  line-height: 210%;
  vertical-align: middle;
}
.text * {
  margin: 0;
}

.score {
  width: 35px;
  height: 14px;
  font-size: 21px;
  z-index: 14;
 }

.editor #data_display {
  display: none;
}
 
#sidebar {
  background: black;
  position: fixed;
  right: -322px;
  width: 343px;
  height: 100%;
  z-index: 96;
  border-left: 2px solid #ccc;
  transition: right 280ms;
}
#sidebar:hover , #sidebar.expanded { right: 0; }
#sidebar * {
  font-family: 'Press Start';
  line-height: 140%;
  color: #ddd;
}
#sidebar #sectionselect {
  font-size: 1.4em;
}
#sidebar h1 {
  font-size: 1.4em;
  padding-bottom: 14px;
  border-bottom: 2px solid #999;
}
#sidebar .group {
  padding: 7px;
  width: 100%;
  min-height: 70px;
  line-height: 175%;
}
#sidebar .group select , #sidebar .group input{
  padding-bottom: 3px;
  height: 21px;
  border: 1px solid #333;
  border-radius: 3px;
  background-color: black;
}
#sidebar #options {
  font-size: 17px;
}
#sidebar .options.big {
  padding-top: 3px;
  height: 28px;
  text-align: center;
  font-size: 21px;
}
#sidebar #options h3.title {
  margin-top: -21px;
  padding-right: 105px;
  border-bottom: 1px solid #777;
  text-align: right;
  font-size: 19px;
}
#sidebar #options input, #sidebar #options select {
  margin-top: -14px;
  padding: 3px;
  max-width: 175px;
  min-height: 24px;
  background: black;
  border: 1px solid #333;
  text-align: left;
}
#sidebar #options .auto {
  padding: 3px 7px;
  text-align: left;
}
#sidebar #options input[type=Number] {
  max-width: 63px;
}
#sidebar #options .optspan {
  margin-right: 3px;
  font-size: 14px;
  color: #aaa;
}
#sidebar #options .optspan + input {
  margin-top: -3px;
}
#options tr td:first-of-type {
  text-align: right;
}
#options tr td:last-of-type {
  text-align: left;
}

#controls {
  position: absolute;
  bottom: 0;
  right: 3px;
  transition: 70ms opacity;
}
.control {
  float: right;
  width: 64px;
  height: 64px;
  border: 2px solid #aaa;
  cursor: pointer;
  transition: 49ms opacity;
  opacity: .7;
}
.control:hover, .control.enabled { opacity: 1; }
.controltext {
  padding-top: 21px;
  font-size: 11px;
  opacity: .49;
}

#bottombar {
  position: absolute;
  bottom: 68px;
  background: #111;
  transition: all 280ms, visibility 0;
  opacity: .7;
}
#bottombar:hover { 
  opacity: 1;
}
#bottombar .holder {
  float: left;
  width: 64px;
  height: 64px;
  border: 2px solid white;
  cursor: pointer;
  overflow: hidden;
}
#bottombar canvas {
  position: static;
  max-height: 100%;
}

#maplines {
  position: fixed;
  height: 100%;
  width: 100%;
  opacity: .49;
  border-left: 2px dashed #ddd;
  cursor: crosshair;
}
.mapline {
  position: fixed;
  padding: 1px;
  width: 100%;
  border-top: 2px dashed #eee;
  text-align: left;
  cursor: crosshair;
}

#erasing canvas, .erasing #maplines, .erasing .mapline, .erasing #follower {
  cursor: url(Theme/EraserTip.gif), pointer;
}

#follower {
  cursor: crosshair;
}

.scroller {
  position: fixed;
  width: 64px;
  height: 128px;
  opacity: .21;
  z-index: 7;
  cursor: none;
  background: url('Theme/Hand.gif') center center no-repeat;
}
.scroller:hover { opacity: .84; }
.scroller.off {
  display: none;
  visibility: hidden;
  z-index: -35;
}

.flipped {
  -moz-transform: scaleX(-1);
  -o-transform: scaleX(-1);
  -webkit-transform: scaleX(-1);
  transform: scaleX(-1);
  filter: FlipH;
  -ms-filter: "FlipH";
}

#input_window {
  position: fixed;
  height: 100%;
  padding-top: 42px;
  background: rgba(7,21,0,.84);
  box-shadow: 0 0 210px rgba(0,0,1,.7) inset;
  z-index: 98;
}
#input_window textarea {
  margin-top: 35px;
  padding: 7px 21px 14px 28px;
  width: 100%;
  height: 50%;
  background-color: rgba(14, 14, 14, .77);
  background-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAGZmZv///yH5BAEAAAEALAAAAAABAAEAAAICRAEAOw==);
  background-repeat: repeat-y;
  background-position: 21px;
  border-width: 1px 0 1px 0;
  color: white;
  vertical-align: top;
  font-family: "Courier New", "Courier", monospace;
}
#input_window textarea:focus {
  outline: 0;
  border-color: gold;
}
#input_window .window_button {
  float: right;
  margin: 0 21px 0 0;
  padding: 11px;
  padding-bottom: 7px;
  border: 3px solid rgba(175,175,175,.7);
  border-top: 0;
  border-bottom-right-radius: 7px;
  border-bottom-left-radius: 7px;
  cursor: pointer;
}

#window_submit { 
  margin-right: 4%;
  background: rgba(14,70,14,.84);
  font-size: 21px;
}
#window_cancel {
  margin-right: 14px;
  background: rgba(70,14,14,.84);
}

JS源码

(1)mario.js
function FullScreenMario() {
  var time_start = Date.now();
  ensureLocalStorage();
  TonedJS(true);
  window.body = document.body;
  window.bodystyle = body.style;
  window.verbosity = {Maps: false,
                      Sounds: false,
                      };
  if(Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s([^(]{1,})\(/,
                results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1].trim() : "";
        },
        set: function(value) {}
    });
  }
  window.requestAnimationFrame = window.requestAnimationFrame
                           || window.mozRequestAnimationFrame
                           || window.webkitRequestAnimationFrame
                           || window.msRequestAnimationFrame
                           || function(func) { setTimeout(func, timer); };
  window.cancelAnimationFrame = window.cancelAnimationFrame
                           || window.webkitCancelRequestAnimationFrame
                           || window.mozCancelRequestAnimationFrame
                           || window.oCancelRequestAnimationFrame
                           || window.msCancelRequestAnimationFrame
                           || clearTimeout;

  window.Uint8ClampedArray = window.Uint8ClampedArray
                          || window.Uint8Array
                          || Array;
  window.Uint8ArrayName = Uint8ClampedArray.name || "Uint8Array"; // ie

  resetMeasurements();
  resetLibrary();
  resetCanvas();
  resetMaps();
  resetScenery();
  resetTriggers();
  resetSeed();
  resetSounds();
  
  window.gameon = true;
  setMap(1,1);
  startLoadingSounds();
  
  log("It took " + (Date.now() - time_start) + " milliseconds to start.");
}
function ensureLocalStorage() {
  var ls_ok = false;
  try {
  if(!window.hasOwnProperty("localStorage"))
    window.localStorage = { crappy: true };
  
  if(window.localStorage) ls_ok = true;
 }
 catch(err) {
    ls_ok = false;
  }
  if(!ls_ok) {
    var nope = document.body.innerText = "It seems your browser does not allow localStorage!";
    throw nope;
  }
}

function resetMeasurements() {
  resetUnitsize(4);
  resetTimer(1000 / 60);
  
  window.jumplev1 = 32;
  window.jumplev2 = 64;
  window.ceillev  = 88;
  window.ceilmax  = 104;
  window.castlev  = -48;
  window.paused   = true;
  
  resetGameScreen();
  if(!window.parentwindow) window.parentwindow = false;
}

function resetUnitsize(num) {
  window.unitsize = num;
  for(var i = 2; i <= 64; ++i) {
    window["unitsizet" + i] = unitsize * i;
    window["unitsized" + i] = unitsize / i;
  }
  window.scale = unitsized2;
  window.gravity = round(12 * unitsize) / 100;
}

function resetTimer(num) {
  num = roundDigit(num, .001);
  window.timer = window.timernorm = num;
  window.timert2 = num * 2;
  window.timerd2 = num / 2;
  window.fps = window.fps_target = roundDigit(1000 / num, .001);
  window.time_prev = Date.now();
}

function resetGameScreen() {
  window.gamescreen = new getGameScreen();
}
function getGameScreen() {
  resetGameScreenPosition(this);
  this.middlex = (this.left + this.right) / 2;
  window.botmax = this.height - ceilmax;
  if(botmax < unitsize) {
    body.innerHTML = "<div><br>Your screen isn't high enough. Make it taller, then refresh.</div>";
  }
  
  this.deathheight = this.bottom + 48;
}
function resetGameScreenPosition(me) {
  me = me || window.gamescreen;
  me.left = me.top = 0;
  me.bottom = innerHeight;
  me.right = innerWidth;
  me.height = innerHeight / unitsize;
  me.width = innerWidth / unitsize;
  me.unitheight = innerHeight;
  me.unitwidth = innerWidth;
}

function resetGameState(nocount) {
  clearAllTimeouts();
  resetData();
  window.nokeys = window.spawning = window.spawnon =
    window.notime = window.editing = window.qcount = window.lastscroll = 0;
  window.paused = window.gameon = true;
  if(!nocount) window.gamecount = 0;
  resetQuadrants();
  window.gamehistory = [];
  window.gamehistory = [];
  pauseAllSounds();
  sounds = {};
}

function scrollWindow(x, y) {
  x = x || 0; y = y || 0;
  var xinv = -x, yinv = -y;
  
  gamescreen.left += x; gamescreen.right += x;
  gamescreen.top += y; gamescreen.bottom += y;
  
  shiftAll(characters, xinv, yinv);
  shiftAll(solids, xinv, yinv);
  shiftAll(scenery, xinv, yinv);
  shiftAll(quads, xinv, yinv);
  shiftElements(texts, xinv, yinv);
  updateQuads(xinv);
  
  if(window.playediting) scrollEditor(x, y);
}
function shiftAll(stuff, x, y) {
  for(var i = stuff.length - 1; i >= 0; --i)
      shiftBoth(stuff[i], x, y);
}
function shiftElements(stuff, x, y) {
  for(var i = stuff.length - 1, elem; i >= 0; --i) {
    elem = stuff[i];
    elementShiftLeft(elem, x);
    elementShiftTop(elem, y);
  }
}

function scrollMario(x, y, see) {
  var saveleft = mario.left,
      savetop = mario.top;
  y = y || 0;
  scrollWindow(x,y);
  setLeft(mario, saveleft, see);
  setTop(mario, savetop + y * unitsize, see);
  updateQuads();
}

function mlog(type) {
  if(verbosity[type]) {
    log.apply(console, arguments);
  }
}
(2)data.js
function resetData() {
  var check;
  if(check = document.getElementById("data_display"))
    body.removeChild(check);
  
  if(!window.data) {
    window.data = new Data();
  }
}
function Data() {
  this.mariopower = 1;
  this.traveled = this.traveledold = 0;
  this.scorelevs = [100, 200, 400, 500, 800, 1000, 2000, 4000, 5000, 8000];
  this.score = new DataObject(0, 6, "SCORE");
  this.time = new DataObject(350, 3, "TIME");
  this.world = new DataObject(0, 0, "WORLD");
  this.coins = new DataObject(0, 0, "COINS");
  this.lives = new DataObject(3, 1, "LIVES");
  this.time.dir = -1;
  this.scoreold = 0;
}

function DataObject(amount, length, name) {
  this.amount = amount;
  this.length = length;
  this.name = name;
  this.element = createElement("td", {className: "indisplay"});
}

function setDataDisplay() {
  var display = createElement("table", {
            id: "data_display",
            className: "display",
            style: {
              width: (gamescreen.right + 14) + "px"
            }}),
      elems = ["score", "coins", "world", "time", "lives"];
  body.appendChild(display);
  data.display = display;
  for(var i in elems) {
    display.appendChild(data[elems[i]].element);
    updateDataElement(data[elems[i]]);
  }
  body.appendChild(data.display);
}

function clearDataDisplay() {
  body.removeChild(data_display);
}

function startDataTime() {
  addEventInterval(updateDataTime, 25, Infinity, data.time);
}
function updateDataTime(me) {
  if(me.dir != 1) {
    if(me.amount == 100) playCurrentThemeHurry(); 
    else if(me.amount <= 0) killMario(mario, true);
  }
  if(!notime) {
    map.time = me.amount += me.dir;
    updateDataElement(me);
  }
}

function updateDataElement(me) {
  var text = me.name + "<br />" + (me.amount == "Infinity" ? "Inf" : me.amount);
  me.element.innerHTML = text;
  me.element.style.width = "";
}


function score(me, amount, appears) {
  if(amount <= 0) return;
  if(arguments.length == 1) return score(mario, me);
  localStorage.highscore = max(localStorage.highscore, data.score.amount += amount);
  if(appears) {
    var text = addText(amount, me.left, me.top);
    text.yvel = -unitsized4;
    addEvent(killScore, 49, text);
  }
  while(data.score > 10000) { 
    gainLife();
    data.score.amount = data.score.amount % 10000;
  }
  updateDataElement(data.score);
}
function killScore(text) {
  body.removeChild(text);
  killNormal(text);
  deleteThing(text, texts, texts.indexOf(text));
}

function findScore(lev) {
  if(lev < data.scorelevs.length) return data.scorelevs[lev];
  gainLife();
  return -1;
}

function gainLife(num, nosound) {
  data.lives.amount += typeof(num) == "number" ? num : 1;
  if(!nosound) play("Gain Life");
  updateDataElement(data.lives);
}

function setLives(num) {
  data.lives.amount = Number(num);
  updateDataElement(data.lives);
}

function storeMarioStats() {
  data.mariopower = mario.power;
}
function clearMarioStats() {
  data.mariopower = mario.power = 1;
}
(3)events.js
function addEvent(func, count) {
  if(!(func instanceof Function)) return false;
  count = count || 1;

  var args = arrayMake(arguments);
  args.splice(0, 2);

  var contents = {
    func: func,
    count: gamecount + count,
    args: args,
    timeout: count,
    repeat: true
  };
  insertSortedEvent(events, contents, contents.count);
  return contents;
}

function addEventInterval(func, count, reptimes) {

  if(!(func instanceof Function)) return false;
  count = count || 1;
  
  var args = arrayMake(arguments);
  args.splice(0, 3);
  
  var contents = {
    func: func,
    count: gamecount + count,
    args: args,
    timeout: count,
    repeat: reptimes
  };
  
  contents.func.event = contents;
  
  insertSortedEvent(events, contents, contents.count);
  return contents;
}

function addEventIntervalSynched(func, count, reptimes, me, settings) {
  var calctime = count * settings.length,
      entry = ceil(gamecount / calctime) * calctime,
      scope = this,
      addfunc = function(scope, args, me) {
        me.startcount = gamecount;
        return addEventInterval.apply(scope, args);
      };
  
  if(entry == gamecount) {
    return addfunc(scope, arguments, me);
  }
  else {
    var dt = entry - gamecount;
    addEvent(addfunc, dt, scope, arguments, me);
  }
}

function handleEvents() {
  ++gamecount;
  var events_current = events[gamecount],
      event, repfunc,
      len, i;
  
  if(!events_current) return;
  
  for(i = 0, len = events_current.length; i < len; ++i) {
    event = events_current[i];

    if(event.repeat && !event.func.apply(null, event.args)) {
      
      if(event.count_changer) event.count_changer(event);

      if(event.repeat instanceof Function) {
        repfunc = event.repeat.bind(event);
        if(repfunc()) {
          event.count += event.timeout;
          insertSortedEvent(events, event, event.count);
        }
      }
      
      else {
        if(--event.repeat != 0) {
          event.count += event.timeout;
          insertSortedEvent(events, event, event.count);
        }
      }
    }
  }
  
  delete events[gamecount];
}

function insertSortedEvent(events, contents, count) {
  if(!events[count]) events[count] = [];
  events[count].push(contents);
}

function clearEvent(event) {
  if(!event) return;
  event.repeat = false;
}
function clearEventInterval(event) {
  if(!event) return;
  event.repeat = false;
}

function addSpriteCycle(me, settings, name, timing) {
  if(!me.cycles) me.cycles = {};
  clearClassCycle(me, name);
  var cycle = me.cycles[name || 0] = setSpriteCycle(me, settings, typeof(timing) == "function" ? 0 : timing);
  if(cycle.event && typeof(timing) == "function") cycle.event.count_changer = timing;
  cycleClass(me, settings);
  return cycle;
}
function addSpriteCycleSynched(me, settings, name, timing) {
  if(!me.cycles) me.cycles = {}
  settings = settings || ["one", "two"];
  var cycle = me.cycles[name || 0] = setSpriteCycle(me, settings, timing, true);
  clearClassCycle(me, name);
  cycleClass(me, settings);
  return cycle;
}

function setSpriteCycle(me, settings, timing, synched) {
  settings.loc = -1;
  settings.oldclass = "761deadsoldiers";
  me.onadding = function() { 
    if(synched) settings.event = addEventIntervalSynched(cycleClass, timing || 9, Infinity, me, settings);
    else settings.event = addEventInterval(cycleClass, timing || 9, Infinity, me, settings);
  }
  if(me.placed) me.onadding();
  return settings;
}

function clearClassCycles(me, names) {
  names = names.split(" ");
  for(var i = names.length - 1; i >= 0; --i)
    clearClassCycle(me, names[i]);
}
function clearClassCycle(me, name) {
  if(!characterIsAlive(me) || !me.cycles[name]) return;
  me.cycles[name][0] = false;
  me.cycles[name].length = 1;
  delete me.cycles[name];
}
function clearAllCycles(me) {
  for(var i in me.cycles)
    clearClassCycle(me, i);
}

function cycleClass(me, settings) {
  if(!me || !settings || !settings.length) return true;
  
  if(settings.oldclass != "") removeClass(me, settings.oldclass);
  settings.loc = ++settings.loc % settings.length;
  var current = settings[settings.loc];
  if(current) {
    var name = current instanceof Function ? current(me, settings) : current;
    if(typeof(name) == "string") {
      settings.oldclass = name;
      addClass(me, name);
      return false;
    } 
    else return (name === false);
  }
  else {
    return (current === false);
  }
}

function addSpriteCycleManual(me, settings, name, timing) {
  if(!me.cycles) me.cycles = {}
  me.cycles[name || 0] = setSpriteCycleManual(me, settings, timing);
}
function setSpriteCycleManual(me, settings, timing) {
  settings.loc = -1;
  settings.oldclass = "761deadsoldiers";
  timing = (timing || 9) * timer;
  var interval = setInterval(function() {
    if(cycleClass(me, settings))
      clearInterval(interval);
  }, timing);
  return settings;
}

function removeSpriteCycle(me, name) {
}

function scrollTime(dx) {
  dx = dx || 21;
  mario.nofall = mario.nocollide = nokeys = true;
  addEventInterval(scrollMario, 1, Infinity, dx);
  
  mario.oldtop = mario.top;
  mario.siny = -Math.PI;
  addEventInterval(function() {
    setTop(mario, mario.oldtop - Math.sin(mario.siny -= .125) * unitsizet8);
  }, 1, Infinity);
  addEventInterval(function() {
    shiftVert(mario, -1.4);
    mario.oldtop -= 1.4;
  }, 1, 49);
  
  addEventInterval(function() {
    if(map.has_lakitu) killFlip(map.has_lakitu);
  }, 70);
}
(4)gamepad.js
(function(exports) {
	'use strict';
	var nullFunction = function() {};
	var nullPlatform = {
		getType: function() {
			return 'null';
		},
		isSupported: function() {
			return false;
		},
		update: nullFunction
	};

	var AnimFrameUpdateStrategy = function(requestAnimationFrame) {
		var that = this;
		var win = window;

		this.update = nullFunction;

		this.requestAnimationFrame = requestAnimationFrame || win.requestAnimationFrame ||
			win.webkitRequestAnimationFrame || win.mozRequestAnimationFrame;

		this.tickFunction = function() {
			that.update();
			that.startTicker();
		};

		this.startTicker = function() {
			that.requestAnimationFrame.apply(win, [that.tickFunction]);
		};
	};

	AnimFrameUpdateStrategy.prototype.start = function(updateFunction) {
		this.update = updateFunction || nullFunction;
		this.startTicker();
	};

	var ManualUpdateStrategy = function() {

	};

	ManualUpdateStrategy.prototype.update = nullFunction;

	ManualUpdateStrategy.prototype.start = function(updateFunction) {
		this.update = updateFunction || nullFunction;
	};

	var WebKitPlatform = function(listener, gamepadGetter) {
		this.listener = listener;
		this.gamepadGetter = gamepadGetter;
		this.knownGamepads = [];
	};

	WebKitPlatform.factory = function(listener) {
		var platform = nullPlatform;
		var navigator = window && window.navigator;

		if (navigator) {
			if (typeof(navigator.webkitGamepads) !== 'undefined') {
				platform = new WebKitPlatform(listener, function() {
					return navigator.webkitGamepads;
				});
			} else if (typeof(navigator.webkitGetGamepads) !== 'undefined') {
				platform = new WebKitPlatform(listener, function() {
					return navigator.webkitGetGamepads();
				});
			}
		}

		return platform;
	};

	WebKitPlatform.getType = function() {
		return 'WebKit';
	},

	WebKitPlatform.prototype.getType = function() {
		return WebKitPlatform.getType();
	},

	WebKitPlatform.prototype.isSupported = function() {
		return true;
	};

	WebKitPlatform.prototype.update = function() {
		var that = this;
		var gamepads = Array.prototype.slice.call(this.gamepadGetter(), 0);
		var gamepad;
		var i;

		for (i = this.knownGamepads.length - 1; i >= 0; i--) {
			gamepad = this.knownGamepads[i];
			if (gamepads.indexOf(gamepad) < 0) {
				this.knownGamepads.splice(i, 1);
				this.listener._disconnect(gamepad);
			}
		}

		for (i = 0; i < gamepads.length; i++) {
			gamepad = gamepads[i];
			if (gamepad && (that.knownGamepads.indexOf(gamepad) < 0)) {
				that.knownGamepads.push(gamepad);
				that.listener._connect(gamepad);
			}
		}
	};

	var FirefoxPlatform = function(listener) {
		this.listener = listener;

		window.addEventListener('gamepadconnected', function(e) {
			listener._connect(e.gamepad);
		});
		window.addEventListener('gamepaddisconnected', function(e) {
			listener._disconnect(e.gamepad);
		});
	};

	FirefoxPlatform.factory = function(listener) {
		var platform = nullPlatform;

		if (window && (typeof(window.addEventListener) !== 'undefined')) {
			platform = new FirefoxPlatform(listener);
		}

		return platform;
	};

	FirefoxPlatform.getType = function() {
		return 'Firefox';
	},

	FirefoxPlatform.prototype.getType = function() {
		return FirefoxPlatform.getType();
	},

	FirefoxPlatform.prototype.isSupported = function() {
		return true;
	};

	FirefoxPlatform.prototype.update = nullFunction;

	var Gamepad = function(updateStrategy) {
		this.updateStrategy = updateStrategy || new AnimFrameUpdateStrategy();
		this.gamepads = [];
		this.listeners = {};
		this.platform = nullPlatform;
		this.deadzone = 0.03;
		this.maximizeThreshold = 0.97;
	};

	Gamepad.UpdateStrategies = {
		AnimFrameUpdateStrategy: AnimFrameUpdateStrategy,
		ManualUpdateStrategy: ManualUpdateStrategy
	};

	Gamepad.PlatformFactories = [WebKitPlatform.factory, FirefoxPlatform.factory];

	Gamepad.Type = {
		PLAYSTATION: 'playstation',
		LOGITECH: 'logitech',
		XBOX: 'xbox',
		UNKNOWN: 'unknown'
	};

	Gamepad.Event = {
		CONNECTED: 'connected',

		UNSUPPORTED: 'unsupported',

		DISCONNECTED: 'disconnected',

		TICK: 'tick',

		BUTTON_DOWN: 'button-down',

		BUTTON_UP: 'button-up',

		AXIS_CHANGED: 'axis-changed'
	};

	Gamepad.StandardButtons = [
		'FACE_1', 'FACE_2', 'FACE_3', 'FACE_4',
		'LEFT_TOP_SHOULDER', 'RIGHT_TOP_SHOULDER', 'LEFT_BOTTOM_SHOULDER', 'RIGHT_BOTTOM_SHOULDER',
		'SELECT_BACK', 'START_FORWARD', 'LEFT_STICK', 'RIGHT_STICK',
		'DPAD_UP', 'DPAD_DOWN', 'DPAD_LEFT', 'DPAD_RIGHT',
		'HOME'
	];

	Gamepad.StandardAxes = ['LEFT_STICK_X', 'LEFT_STICK_Y', 'RIGHT_STICK_X', 'RIGHT_STICK_Y'];

	var getControlName = function(names, index, extraPrefix) {
		return (index < names.length) ? names[index] : extraPrefix + (index - names.length + 1);
	};

	Gamepad.StandardMapping = {
		env: {},
		buttons: {
			byButton: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
		},
		axes: {
			byAxis: [0, 1, 2, 3]
		}
	};

	Gamepad.Mappings = [
		{
			env: {
				platform: FirefoxPlatform.getType(),
				type: Gamepad.Type.PLAYSTATION
			},
			buttons: {
				byButton: [14, 13, 15, 12, 10, 11, 8, 9, 0, 3, 1, 2, 4, 6, 7, 5, 16]
			},
			axes: {
				byAxis: [0, 1, 2, 3]
			}
		},
		{
			env: {
				platform: WebKitPlatform.getType(),
				type: Gamepad.Type.LOGITECH
			},
			buttons: { // TODO: This can't be right - LEFT/RIGHT_STICK have same mappings as HOME/DPAD_UP
				byButton: [1, 2, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 10]
			},
			axes: {
				byAxis: [0, 1, 2, 3]
			}
		},
		{
			env: {
				platform: FirefoxPlatform.getType(),
				type: Gamepad.Type.LOGITECH
			},
			buttons: {
				byButton: [0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 11, 12, 13, 14, 10],
				byAxis: [-1, -1, -1, -1, -1, -1, [2, 0, 1],
					[2, 0, -1]
				]
			},
			axes: {
				byAxis: [0, 1, 3, 4]
			}
		}
	];

	Gamepad.prototype.init = function() {
		var platform = Gamepad.resolvePlatform(this);
		var that = this;

		this.platform = platform;
		this.updateStrategy.start(function() {
			that._update();
		});

		return platform.isSupported();
	};

	Gamepad.prototype.bind = function(event, listener) {
		if (typeof(this.listeners[event]) === 'undefined') {
			this.listeners[event] = [];
		}

		this.listeners[event].push(listener);

		return this;
	};

	Gamepad.prototype.unbind = function(type, listener) {
		if (typeof(type) === 'undefined') {
			this.listeners = {};

			return;
		}

		if (typeof(listener) === 'undefined') {
			this.listeners[type] = [];

			return;
		}

		if (typeof(this.listeners[type]) === 'undefined') {
			return false;
		}

		for (var i = 0; i < this.listeners[type].length; i++) {
			if (this.listeners[type][i] === listener) {
				this.listeners[type].splice(i, 1);

				return true;
			}
		}

		return false;
	};

	Gamepad.prototype.count = function() {
		return this.gamepads.length;
	};

	Gamepad.prototype._fire = function(event, data) {
		if (typeof(this.listeners[event]) === 'undefined') {
			return;
		}

		for (var i = 0; i < this.listeners[event].length; i++) {
			this.listeners[event][i].apply(this.listeners[event][i], [data]);
		}
	};

	Gamepad.getNullPlatform = function() {
		return Object.create(nullPlatform);
	};

	Gamepad.resolvePlatform = function(listener) {
		var platform = nullPlatform;
		var i;

		for (i = 0; !platform.isSupported() && (i < Gamepad.PlatformFactories.length); i++) {
			platform = Gamepad.PlatformFactories[i](listener);
		}

		return platform;
	};

	Gamepad.prototype._connect = function(gamepad) {
		var mapping = this._resolveMapping(gamepad);
		var count;
		var i;

		gamepad.state = {};
		gamepad.lastState = {};
		gamepad.updater = [];

		count = mapping.buttons.byButton.length;
		for (i = 0; i < count; i++) {
			this._addButtonUpdater(gamepad, mapping, i);
		}

		count = mapping.axes.byAxis.length;
		for (i = 0; i < count; i++) {
			this._addAxisUpdater(gamepad, mapping, i);
		}

		this.gamepads[gamepad.index] = gamepad;

		this._fire(Gamepad.Event.CONNECTED, gamepad);
	};


	Gamepad.prototype._addButtonUpdater = function(gamepad, mapping, index) {
		var updater = nullFunction;
		var controlName = getControlName(Gamepad.StandardButtons, index, 'EXTRA_BUTTON_');
		var getter = this._createButtonGetter(gamepad, mapping.buttons, index);
		var that = this;
		var buttonEventData = {
			gamepad: gamepad,
			control: controlName
		};

		gamepad.state[controlName] = 0;
		gamepad.lastState[controlName] = 0;

		updater = function() {
			var value = getter();
			var lastValue = gamepad.lastState[controlName];
			var isDown = value > 0.5;
			var wasDown = lastValue > 0.5;

			gamepad.state[controlName] = value;

			if (isDown && !wasDown) {
				that._fire(Gamepad.Event.BUTTON_DOWN, Object.create(buttonEventData));
			} else if (!isDown && wasDown) {
				that._fire(Gamepad.Event.BUTTON_UP, Object.create(buttonEventData));
			}

			if ((value !== 0) && (value !== 1) && (value !== lastValue)) {
				that._fireAxisChangedEvent(gamepad, controlName, value);
			}

			gamepad.lastState[controlName] = value;
		};

		gamepad.updater.push(updater);
	};

	Gamepad.prototype._addAxisUpdater = function(gamepad, mapping, index) {
		var updater = nullFunction;
		var controlName = getControlName(Gamepad.StandardAxes, index, 'EXTRA_AXIS_');
		var getter = this._createAxisGetter(gamepad, mapping.axes, index);
		var that = this;

		gamepad.state[controlName] = 0;
		gamepad.lastState[controlName] = 0;

		updater = function() {
			var value = getter();
			var lastValue = gamepad.lastState[controlName];

			gamepad.state[controlName] = value;

			if ((value !== lastValue)) {
				that._fireAxisChangedEvent(gamepad, controlName, value);
			}

			gamepad.lastState[controlName] = value;
		};

		gamepad.updater.push(updater);
	};

	Gamepad.prototype._fireAxisChangedEvent = function(gamepad, controlName, value) {
		var eventData = {
			gamepad: gamepad,
			axis: controlName,
			value: value
		};

		this._fire(Gamepad.Event.AXIS_CHANGED, eventData);
	};

	Gamepad.prototype._createButtonGetter = (function() {
		var nullGetter = function() {
			return 0;
		};

		var createRangeGetter = function(valueGetter, from, to) {
			var getter = nullGetter;

			if (from < to) {
				getter = function() {
					var range = to - from;
					var value = valueGetter();

					value = (value - from) / range;

					return (value < 0) ? 0 : value;
				};
			} else if (to < from) {
				getter = function() {
					var range = from - to;
					var value = valueGetter();

					value = (value - to) / range;

					return (value > 1) ? 0 : (1 - value);
				};
			}

			return getter;
		};

		var isArray = function(thing) {
			return Object.prototype.toString.call(thing) === '[object Array]';
		};

		return function(gamepad, buttons, index) {
			var getter = nullGetter;
			var entry;
			var that = this;

			entry = buttons.byButton[index];
			if (entry !== -1) {
				if ((typeof(entry) === 'number') && (entry < gamepad.buttons.length)) {
					getter = function() {
						return gamepad.buttons[entry];
					};
				}
			} else if (buttons.byAxis && (index < buttons.byAxis.length)) {
				entry = buttons.byAxis[index];
				if (isArray(entry) && (entry.length == 3) && (entry[0] < gamepad.axes.length)) {
					getter = function() {
						var value = gamepad.axes[entry[0]];

						return that._applyDeadzoneMaximize(value);
					};

					getter = createRangeGetter(getter, entry[1], entry[2]);
				}
			}

			return getter;
		};
	})();

	Gamepad.prototype._createAxisGetter = (function() {
		var nullGetter = function() {
			return 0;
		};

		return function(gamepad, axes, index) {
			var getter = nullGetter;
			var entry;
			var that = this;

			entry = axes.byAxis[index];
			if (entry !== -1) {
				if ((typeof(entry) === 'number') && (entry < gamepad.axes.length)) {
					getter = function() {
						var value = gamepad.axes[entry];

						return that._applyDeadzoneMaximize(value);
					};
				}
			}

			return getter;
		};
	})();

	Gamepad.prototype._disconnect = function(gamepad) {
		var newGamepads = [],
			i;

		if (typeof(this.gamepads[gamepad.index]) !== 'undefined') {
			delete this.gamepads[gamepad.index];
		}

		for (i = 0; i < this.gamepads.length; i++) {
			if (typeof(this.gamepads[i]) !== 'undefined') {
				newGamepads[i] = this.gamepads[i];
			}
		}

		this.gamepads = newGamepads;

		this._fire(Gamepad.Event.DISCONNECTED, gamepad);
	};

	Gamepad.prototype._resolveControllerType = function(id) {
		id = id.toLowerCase();

		if (id.indexOf('playstation') !== -1) {
			return Gamepad.Type.PLAYSTATION;
		} else if (
			id.indexOf('logitech') !== -1 || id.indexOf('wireless gamepad') !== -1) {
			return Gamepad.Type.LOGITECH;
		} else if (id.indexOf('xbox') !== -1 || id.indexOf('360') !== -1) {
			return Gamepad.Type.XBOX;
		} else {
			return Gamepad.Type.UNKNOWN;
		}
	};

	Gamepad.prototype._resolveMapping = function(gamepad) {
		var mappings = Gamepad.Mappings;
		var mapping = null;
		var env = {
			platform: this.platform.getType(),
			type: this._resolveControllerType(gamepad.id)
		};
		var i;
		var test;

		for (i = 0; !mapping && (i < mappings.length); i++) {
			test = mappings[i];
			if (Gamepad.envMatchesFilter(test.env, env)) {
				mapping = test;
			}
		}

		return mapping || Gamepad.StandardMapping;
	};

	Gamepad.envMatchesFilter = function(filter, env) {
		var result = true;
		var field;

		for (field in filter) {
			if (filter[field] !== env[field]) {
				result = false;
			}
		}

		return result;
	};

	Gamepad.prototype._update = function() {
		this.platform.update();

		this.gamepads.forEach(function(gamepad) {
			if (gamepad) {
				gamepad.updater.forEach(function(updater) {
					updater();
				});
			}
		});

		if (this.gamepads.length > 0) {
			this._fire(Gamepad.Event.TICK, this.gamepads);
		}
	},

	Gamepad.prototype._applyDeadzoneMaximize = function(
		value,
		deadzone,
		maximizeThreshold) {
		deadzone = typeof(deadzone) !== 'undefined' ? deadzone : this.deadzone;
		maximizeThreshold = typeof(maximizeThreshold) !== 'undefined' ? maximizeThreshold : this.maximizeThreshold;

		if (value >= 0) {
			if (value < deadzone) {
				value = 0;
			} else if (value > maximizeThreshold) {
				value = 1;
			}
		} else {
			if (value > -deadzone) {
				value = 0;
			} else if (value < -maximizeThreshold) {
				value = -1;
			}
		}

		return value;
	};

	exports.Gamepad = Gamepad;

})(((typeof(module) !== 'undefined') && module.exports) || window);

parser文件:

(1)parser.html
<!DOCTYPE html>
<html lang="en-us">
<head>
    <meta charset="utf-8">
    <title>Image Parser</title>
    
    <link href="parser.css" rel="stylesheet">
    
    <script src="parser.js"></script>

</head>
<body onload="load()">
  <h1>Sprite Image Converter</h1>
  
  <div id="sources" style="float:left" >
    <div id="left" class="column">
      <h2>Upload files</h2>
      <div id="dropzone">Drag & drop here</div>
      <ol id="curlist"></ol>
    </div>
    
    <div id="middle" class="column" style="max-width:420px">
      <h2>Select your color palette</h2>
      <div id="palettes">
        
      </div>
    </div>
  </div>
  
  <div id="right" class="column">
    <h2>Get your output</h2>
    <ol id="outlist"></ol>
  </div>
  
</body>
</html>
(2)parser.css
* {
  text-shadow: 1px 1px 3px white;
  transition: all 350ms linear;
}

body {
  margin: 0;
}

html {
  background: rgb(245,245,245);
  font-family: Georgia;
}

grey {
  color: rgb(140,140,140);
}

weak {
  font-style: italic;
  margin-left: 14px;
}

.column {
  margin: 14px;
  background: white;
  border-radius: 7px;
  border: 1px solid rgb(210,210,210);
  box-shadow: 3px 3px 7px rgb(210,210,210);
  float: left;
  min-width: 280px;
}

h1 {
  background: black;
  border-bottom: 1px solid white;
  color: white;
  margin: 0;
  padding: 0 0 3px 3px;
}

h2 {
  margin-top: 3px;
  padding: 0 7px 0 7px;
}

h3 {
  padding: 0 0 0 14px;
}

#dropzone {
  margin: 7px 7px -7px 7px;
  padding: 14px;
  font-size: 1.4em;
  border: 2px dashed rgb(140,140,140);
  border-radius: 7px;
  text-align: center;
}
#dropzone:hover {
  background: rgb(252,252,252);
  border-color: rgb(117,117,210);
}

#scaler {
  margin-top: 14px;
}
#scaler h3 {
  margin: 7px;
  float: left;
}
#scaler div {
  width: 35%;
  float: right;
  clear: right;
  margin: -3px 3px 0 7px;
}
#scaler input {
  width: 70px;
}

#curlist {
  clear: both;
}

.squares {
  margin: 3px 0 3px 0;
  transition: 140ms all;
  clear: both;
  cursor: pointer;
}
.squares:hover, .squares.selected {
  margin-left: 7px;
  background: rgb(245,245,245);
}

.palettename {
  margin: 7px 0 0 14px;
  padding: 3px 7px 0 0;
  float: right;
  font-style: italic;
  color: darkgrey;
}

.square {
  margin: 3px;
  width: 28px;
  height: 28px;
  border: 1px solid white;
  outline: 1px solid darkgrey;
  display: inline-block;
  background: url('squarebackground.gif');
}

.squarein {
  width: 100%;
  height: 100%;
}

#outlist {
  overflow: hidden;
}

.output {
  padding-bottom: 7px;
  height: 84px;
  width: 490px;
  border: 1px solid rgb(210,240,210);
  border-top-left-radius: 3px;
  border-bottom-left-radius: 7px;
}

.status {
  height: 0;
  padding-top: 7px;
  padding-left: 7px;
  font-weight: bold;
}

.progress {
  background: lightgreen;
  height: 35px;
  margin-top: -7px;
  width: 0;
  z-index: 7;
}

.title {
  position: absolute;
  width: 70px;
  text-align: right;
}

.displayer { margin-bottom: 3px; }

.display {
  margin: 3px 0 0 77px;
  font-family: "Courier New", "Courier", monospace;
  width: 406px;
}
(3)parser.js
var num_files, dropzone, curlist, outlist, numdisplay, files, scale_x = 1, scale_y = 1, digitsize = 1,
  palette, palettes, palette_name, palette_names, palette_elem, palette_elems,
  max = Math.max, min = Math.min, round = Math.round, abs = Math.abs;

function load() {
  dropzone = document.getElementById("dropzone");
  curlist = document.getElementById("curlist");
  outlist = document.getElementById("outlist");
  numdisplay = document.getElementById("num_files");
  num_files = 0;
  dropzone.onchange = handleInputChange;
  dropzone.ondragover = handleDragOver;
  dropzone.ondragleave = handleDragOff;
  dropzone.ondrop = handleFileSelect;
  
  initializePalettes();
}

function handleInputChange(event) {
  dropzone.ondragleave();
  event.target.ondragleave();
  console.log(window.e = event);
}

function handleFileSelect(event) {
  preventAll(event);
  this.style.backgroundColor = "";
  
  var files = window.files = event.dataTransfer.files,
      output = [],
      type;
  for(var i = 0, f; f = files[i]; i++) {
    type = f.type.split("/")[1];
    if(type == "gif" || type == "png" || type == "jpeg" || type == "jpg") {
      ++num_files;
      output.push("<li><strong>", f.name, "</strong> <grey>(", type, ")</grey>");
      outlist.appendChild(getWorkerElement(f));
    }
    else output.push("<li>Only images are supported! <grey>(" + type + ")</grey></li>");
  }
  dropzone.innerHTML = files.length + " file" + (files.length == 1 ? "" : "s") + " selected"
  curlist.innerHTML = output.join("");
}

function getWorkerElement(file) {
  var element = getOutputListElement(file.name),
      reader = new FileReader();
  
  reader.onprogress = updateProgress;
  reader.element = element;
  reader.onloadend = startWorking;
  reader.readAsDataURL(file);
  
  return element;
}

function getOutputListElement(name) {
  var element = document.createElement("li"),
      status = document.createElement("div"),
      progress = document.createElement("div"),
      base64 = document.createElement("div"),
      results = document.createElement("div"),
      close = document.createElement("div");
  
  element.name = name;
  element.statusbase = status.innerText = "Uploading " + name + "...";
  
  element.status = status;
  element.progress = progress
  element.base64 = base64,
  element.results = results;
  element.close = close;
  
  element.appendChild(status);
  element.appendChild(progress);
  element.appendChild(base64);
  element.appendChild(results);
  element.appendChild(close);
  
  status.className = "status";
  element.className = "output";
  progress.className = "progress";
  base64.className = "base64";
  results.className = "results";
  close.className = "close";
  
  setTextDisplayer(base64, "Base 64");
  setTextDisplayer(results, "Sprite");
  
  return element;
}

function updateProgress(event) {
  if(event.lengthComputable) {
    var percentLoaded = round((event.loaded / event.total) * 100);
    if(percentLoaded <= 100) {
      this.element.status.innerText = this.element.statusbase + " (" + percentLoaded + "%)";
      this.element.progress.style.width = percentLoaded + "%";
    }
  }
}

function startWorking(event) {
  var reader = event.currentTarget,
      element = reader.element,
      result = reader.result;
  
  setTimeout(function() {
    element.status.innerText = "Working on " + element.name + "...";
    element.progress.style.backgroundColor = "rgb(117,175,245)";
  }, 350);
  setDisplayerText(element.base64, result);
  
  var canvas = document.createElement("canvas"),
      context = canvas.getContext("2d");
  
  var img = document.createElement("image");
  img.src = result;
      
  img.onload = function() {
    canvas.width = img.width;
    canvas.height = img.height;
    context.drawImage(img, 0, 0);
    var data = context.getImageData(0, 0, img.width, img.height),
        output;

    setTimeout(function() {
      element.status.innerHTML = "<strong>" + element.name + "</strong><weak><grey style='text-shadow:none;'>(" + palette_name + ")</grey></weak>";
      element.status.style.color = "white";
      element.progress.style.backgroundColor = "rgb(35,35,70)";
      output = parseData(data.data, element, palette);
      setDisplayerText(element.results, output);
    }, 350);
  }
}

function parseData(data, element) {
  var outs = [],
      occurences = {},
      me,
      i, j, len = data.length;

  for(i = 0, j = 0; i < len; i += 4, ++j) {
    me = outs[j] = getClosestPalette([data[i], data[i+1], data[i+2], data[i+3]]);
    if(occurences[me]) ++occurences[me];
    else occurences[me] = 1;
  }
  
  return combineSimilarChars(outs, getNewPaletteFromOccurences(occurences));
}

function combineSimilarChars(textraw, paletteinfo) {
  var newpalette = paletteinfo[0],
      digitsize = paletteinfo[1],
      threshold = max(3, round(4 / digitsize)),
      text = "",
      i, j, len, cur;
      console.log(digitsize);
  for(i = 0, len = textraw.length; i < len; ++i) {
    j = i + 1;
    cur = textraw[i];
    while(cur == textraw[j]) ++j;
    if(j - i > threshold) {
      text += "x" + makedigit(cur, digitsize, newpalette) + String(j - i) + ",";
      i = j - 1;
    }
    else text += makedigit(cur, digitsize, newpalette);
  }
  return "p[" + grabKeys(newpalette) + "]" + text;
}
function getNewPaletteFromOccurences(occurences) {
  var counts = [],
      key, len = 0;
  for(key in occurences) {
    counts[key] = len;
    ++len;
  }
  console.log(len);
  return [counts,getDigitSizeFromLength(len)];
}

function makedigit(num, digitsize, newpalette) {
  return fillChars(max(0, digitsize - String(num).length), "0") + newpalette[num];
}
function fillChars(num, a) {
  var text = "";
  while(num--) text += a;
  return text;
}
function grabKeys(object) {
  var output = [], i;
  for(i in object) output.push(i);
  return output.join(",");
}

function getClosestPalette(rgba) {
  var i, bestloc, diff, bestdiff = Infinity;
  for(i = palette.length - 1; i >= 0; --i) {
    diff = arrayDiff(rgba, palette[i]);
    if(diff < bestdiff) {
      bestdiff = diff;
      bestloc = i;
    }
  }
  return bestloc;
}
function arrayDiff(a, b) {
  var sum = 0, i;
  for(i = a.length - 1; i >= 0; --i) sum += abs(a[i] - b[i]);
  return sum;
}

function arrayEquals(a,b) { return !(a<b || b<a); }

function handleDragOver(event) {
  preventAll(event);
  event.dataTransfer.dropEffect = "copy";
  this.style.backgroundColor = "lightgrey";
}
function handleDragOff(event) {
  this.style.backgroundColor = "";
}

function preventAll(event) {
  event.stopPropagation();
  event.preventDefault();
}

function setTextDisplayer(element, intitle) {
  element.className += " displayer";
  
  var title = element.title = document.createElement("div"),
      display = element.display = document.createElement("input"),
      copyout = element.copyout = document.createElement("div");
  
  title.innerText = intitle + ": ";
  title.className = "title";
  display.className = "display";
  
  element.appendChild(title);
  element.appendChild(display);
}
function setDisplayerText(element, text) {
  element.display.value = text;
}

function initializePalettes() {
  palettes = [
    [
      [0,0,0,0],
      [255,255,255,255],
      [0,0,0,255]
    ],
    [
      [0,0,0,0],
      [255,255,255,255],
      [0,0,0,255],
      [199,199,192,255],
      [128,128,128,255]
    ],
    [
      [0,0,0,0],
      // Grayscales (1-4)
      [255,255,255,255],
      [0,0,0,255],
      [188,188,188,255],
      [116,116,116,255],
      // Reds & Browns (5-11)
      [252,216,168,255],
      [252,152,56,255],
      [252,116,180,255],
      [216,40,0,255],
      [200,76,12,255],
      [136,112,0,255],
      [124,7,0,255],
      // Greens (12-14)
      [168,250,188,255],
      [128,208,16,255],
      [0,168,0,255],
      // Blues (15-20)
      [24,60,92,255],
      [0,128,136,255],
      [32,56,236,255],
      [156,252,240,255],
      [60,188,252,255],
      [92,148,252,255]
    ]
  ];
  palette_names = [
    "Black & White",
    "GameBoy",
    "Mario"
  ];
  
  var container = document.getElementById("palettes"),
      i, j, len, current, mine, square, squarein;
  
  palette_elems = []
  for(i = 0, len = palettes.length; i < len; ++i) {
    current = palettes[i];
    palette_elems[i] = mine = document.createElement("div");
    
    mine.innerHTML = "<p class='palettename'>" + palette_names[i] + "</p>";
    
    for(j = 0; j < current.length; ++j) {
      square = document.createElement("div");
      squarein = document.createElement("div");
      square.className = "square";
      squarein.className = "squarein";
      squarein.style.background = getColorFromArray(current[j]);
      square.appendChild(squarein);
      mine.appendChild(square);
    }
    
    mine.palettenum = i;
    mine.onclick = setCurrentPalette;
    mine.className = "squares";
    
    container.appendChild(mine);
  }
  
  palette_elems[localStorage.palette_num || 0].click();
}

function getColorFromArray(arr) {
  return "rgba(" + arr.join(", ") + ")";
}

function setCurrentPalette(event) {
  var num = this.palettenum;
  palette = palettes[num];
  palette_name = palette_names[num];
  
  digitsize = getDigitSize(palette);
  digitsize = palette.length >= 10 ? 2 : 1;
  
  if(palette_elem) palette_elem.className = "squares";
  palette_elem = this;
  this.className = "squares selected";
  
  localStorage.palette_num = num;
}
function getDigitSize(palette) { return Number(String(palette.length).length) }
function getDigitSizeFromLength(length) { return Number(String(length).length) }

function setScaleValue(event) {
  window["scale_" + this.alpha] = Number(this.value) || 1;
}

function sum(a,b) { return Number(a) + Number(b); }

Maps文件:

(1)World12.js
map.locs = [
  new Location(0, walkToPipe),
  new Location(1),
  new Location(2),
  new Location(1, exitPipeVert),
  new Location(3, exitPipeVert),
  new Location(1, false, 1000)
];
map.areas = [
  new Area("Overworld", function() {
    setLocationGeneration(0);
    
    pushPreCastle();
    pushPrePattern("backcloud", 0, 4, 1);
    pushPreFloor(0, 0, 24);
    pushPreThing(PipeSide, 80, 16, 1);
    pushPrePipe(96, 0, 32);
  }),
  new Area("Underworld", function() {
    setLocationGeneration(1);
  
    fillPreThing(Brick, 0, 8, 1, 11, 8, 8);
    pushPreFloor(0, 0, 80);
    makeCeiling(48, 83);
    pushPreThing(Block, 80, jumplev1, Mushroom);
    fillPreThing(Block, 88, jumplev1, 4, 1, 8, 8);
    
    pushPreThing(Goomba, 128, 8);
    pushPreThing(Stone, 136, 8);
    pushPreThing(Goomba, 136, 16);
    pushPreThing(Stone, 152, 16, 1, 2);
    pushPreThing(Stone, 168, 24, 1, 3);
    pushPreThing(Stone, 184, 32, 1, 4);
    pushPreThing(Stone, 200, 32, 1, 4);
    pushPreThing(Stone, 216, 24, 1, 3);
    pushPreThing(Goomba, 232, 8);
    pushPreThing(Brick, 232, 40, Coin);
    pushPreThing(Stone, 248, 24, 1, 3);
    pushPreThing(Stone, 264, 16, 1, 2);
    
    fillPreThing(Brick, 312, 32, 1, 3, 8, 8);
    pushPreThing(Brick, 320, 32);
    pushPreThing(Coin, 321, 39);
    fillPreThing(Brick, 328, 32, 1, 3, 8, 8);
    fillPreThing(Coin, 330, 63, 4, 1, 8, 8);
    pushPreThing(Brick, 336, 48);
    pushPreThing(Brick, 344, 48);
    fillPreThing(Koopa, 352, 12, 2, 1, 12);
    fillPreThing(Brick, 352, 32, 1, 3, 8, 8);
    
    // pushPreThing(Coin, 360, 62);
    pushPreThing(Brick, 360, 32);
    fillPreThing(Brick, 368, 32, 1, 2, 8, 8);
    pushPreThing(Coin, 361, 39);
    pushPreThing(Brick, 368, 48, Star);
    fillPreThing(Brick, 416, 32, 2, 5, 8, 8);
    fillPreThing(Brick, 432, 16, 2, 3, 8, 8);
    fillPreThing(Brick, 432, 72, 2, 2, 8, 8);
    fillPreThing(Brick, 464, 32, 4, 1, 8, 8);
    fillPreThing(Brick, 464, 72, 5, 2, 8, 8);
    fillPreThing(Coin, 465, 39, 4, 1, 8, 8);
    pushPreThing(Koopa, 472, 12);
    fillPreThing(Brick, 496, 32, 2, 7, 8, 8);
    pushPreThing(Goomba, 494, 8);
    pushPreThing(Goomba, 510, 8);
    
    fillPreThing(Brick, 528, 72, 4, 2, 8, 8);
    fillPreThing(Brick, 536, 32, 1, 5, 8, 8);
    fillPreThing(Brick, 544, 32, 2, 1, 8, 8);
    pushPreThing(Coin, 545, 39);
    pushPreThing(Brick, 552, 40, Mushroom);
    
    fillPreThing(Brick, 576, 32, 2, 1, 8, 8);
    pushPreThing(Brick, 576, 40);
    fillPreThing(Brick, 576, 48, 2, 3, 8, 8);
    pushPreThing(Brick, 584, 40, Coin);
    pushPreThing(Goomba, 584, 72);
    
    fillPreThing(Brick, 608, 32, 4, 1, 8);
    fillPreThing(Brick, 608, 72, 4, 2, 8);
    fillPreThing(Goomba, 608, 40, 2, 1, 12);
    
    pushPreFloor(664, 0, 34);
    fillPreThing(Brick, 672, 40, 6, 2, 8, 8);
    fillPreThing(Coin, 674, 64, 6, 1, 8, 8);
    pushPreThing(Brick, 712, 88, [Mushroom, 1]);
    makeCeiling(720, 45);
    fillPreThing(Goomba, 768, 8, 3, 1, 12, 8);
    pushPrePipe(800, 0, 24, true, 2);
    pushPrePipe(848, 0, 32, true);
    pushPrePipe(896, 0, 16, true, false, 3);
    
    pushPreFloor(952, 0, 2);
    fillPreThing(Brick, 952, 8, 2, 3, 8, 8);
    
    pushPreFloor(984, 0, 12);
    pushPreThing(Stone, 1040, 8);
    pushPreThing(Stone, 1048, 16, 1, 2);
    pushPreThing(Stone, 1056, 24, 1, 3);
    pushPreThing(Stone, 1064, 32, 1, 4);
    pushPreThing(Stone, 1072, 32, 1, 4);
    pushPrePlatformGenerator(1096, 6, 1);
    // pushPreThing(PlatformGenerator, 1096, ceilmax, 6, 1);
    
    pushPreFloor(1144, 0, 8);
    fillPreThing(Brick, 1144, 40, 5, 1, 8, 8);
    pushPreThing(Koopa, 1152, 12, true);
    pushPreThing(Brick, 1184, 40, Mushroom);
    pushPrePlatformGenerator(1224, 6, -1);
    // pushPreThing(PlatformGenerator, 1224, ceilmax, 6, -1);
    
    pushPreFloor(1266, 0, 32);
    fillPreThing(Brick, 1266, 8, 17, 3, 8, 8);
    pushPreThing(PipeSide, 1314, 40, 4);
    pushPreThing(PipeVertical, 1330, 88, 64);
    makeCeiling(1274, 7);
    fillPreThing(Brick, 1346, 32, 7, 7, 8, 8);
    pushPreThing(ScrollEnabler, 1340, ceilmax);
    makeCeiling(1346, 17);
    pushPreWarpWorld(1400, 0, [[4,1],[3,1],[2,1]], 0, true);
    fillPreThing(Brick, 1506, 8, 2, 11, 8, 8);
  }),
  new Area("Underworld", function() {
    setLocationGeneration(2);
    
    pushPreFloor(0, 0, 17);
    fillPreThing(Brick, 0, 8, 1, 11, 8, 8);
    fillPreThing(Coin, 25, 7, 9, 1, 8, 8);
    fillPreThing(Brick, 24, 32, 9, 1, 8, 8);
    fillPreThing(Coin, 33, 39, 8, 1, 8, 8);
    pushPreThing(Brick, 96, 32, Coin);
    fillPreThing(Brick, 24, 64, 10, 4, 8, 8);
    fillPreThing(Brick, 104, 24, 2, 9, 8, 8);
    pushPreThing(PipeSide, 104, 16, 3);
    pushPreThing(PipeVertical, 120, 100, 100);
  }),
  new Area("Overworld", function() {
    setLocationGeneration(4);
    
    pushPrePattern("backreg", 104, 0, 1);
    pushPreFloor(0, 0, 58);
    pushPrePipe(0, 0, 16, false, false, 4);
    pushPreThing(Stone, 16, 8);
    pushPreThing(Stone, 24, 16, 1, 2);
    pushPreThing(Stone, 32, 24, 1, 3);
    pushPreThing(Stone, 40, 32, 1, 4);
    pushPreThing(Stone, 48, 40, 1, 5);
    pushPreThing(Stone, 56, 48, 1, 6);
    pushPreThing(Stone, 64, 56, 1, 7);
    pushPreThing(Stone, 72, 64, 2, 8);
    endCastleOutside(148);
  })
];
(2)World13.js
map.time = 300;
map.locs = [
  new Location(0, true)
];
map.areas = [
  new Area("Overworld", function() {
    setLocationGeneration(0);

    pushPreCastle();
    pushPrePattern("backcloud", 0, 4, 5);
    pushPreFloor(0, 0, 16);
    
    pushPreTree(144, 8, 4);
    pushPreTree(192, 32, 8);
    pushPreTree(208, 64, 5);
    fillPreThing(Coin, 217, 71, 3, 1, 8, 8, true);
    pushPreThing(Koopa, 240, 76, true);
    pushPreTree(256, 8, 3);
    pushPreThing(Coin, 266, 15);
    pushPreTree(280, 40, 5);
    fillPreThing(Coin, 297, 87, 2, 1, 8);
    pushPreTree(320, 72, 7);
    fillPreThing(Goomba, 352, 80, 2, 1, 16);
    pushPreTree(400, 0, 4);
    fillPreThing(Coin, 402, 55, 2, 1, 8, 8);
    pushPreThing(Platform, 440, 56, 6, [moveFloating, -4, 56]);
    pushPreTree(472, 0, 5);
    pushPreThing(Block, 472, 24, Mushroom);
    pushPreTree(480, 64, 4);
    fillPreThing(Coin, 482, 71, 4, 1, 8);
    pushPreTree(520, 0, 5);
    pushPreTree(560, 32, 3);
    pushPreThing(Koopa, 592, 76, true, [16, 88]);
    pushPreTree(608, 56, 6);
    pushPreThing(Goomba, 640, 64);
    fillPreThing(Coin, 681, 63, 2, 1, 8, 8);
    pushPreThing(Platform, 688, 40, 6, [moveSliding, 660, 720]);
    fillPreThing(Coin, 745, 71, 2, 1, 8, 8);
    pushPreThing(Platform, 752, 32, 6, [moveSliding, 700, 776]);
    fillPreThing(Coin, 777, 71, 2, 1, 8, 8);
    pushPreTree(784, 16, 4);
    pushPreTree(832, 48, 8);
    pushPreThing(Koopa, 880, 60, true);
    pushPreTree(904, 0, 3);
    fillPreThing(Coin, 906, 7, 3, 1, 8, 8);
    pushPreThing(Koopa, 912, 68, true, [4, 76]);
    pushPreTree(928, 32, 4);
    fillPreThing(Coin, 962, 63, 2, 1, 8, 8);
    pushPreTree(976, 32, 4);
    
    pushPreFloor(1032, 0, 46);
    pushPreThing(Platform, 1048, 56, 6, [moveSliding, 1008, 1076]);
    pushPreThing(Koopa, 1064, 12, true); 
    pushPreThing(Stone, 1104, 32, 1, 4);
    pushPreThing(Stone, 1112, 32, 1, 4);
    pushPreThing(Stone, 1120, 48, 1, 6);
    pushPreThing(Stone, 1128, 48, 1, 6);
    pushPreThing(Stone, 1136, 64, 1, 8);
    pushPreThing(Stone, 1144, 64, 1, 8);
    
    endCastleOutside(1220, 0, true, 11);
  })
];

注意:

由于博客字数限制,本篇文章只展示了部分代码。本项目的完整代码及素材包我已上传至资源

文章来源:https://blog.csdn.net/qiao_yue/article/details/135738393
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。