伴随Ajax与网页游戏的崛起,曾几何时JavaScript也成了游戏开发时可供选择的技术之一,文本仅列举数项由JavaScript技术实现的web小游戏(不含网游),聊作参考之用。
1、Mario(游戏地址:http://jsmario.com.ar/ )
传说中的马里奥网页版,一比一实现了红白机时代超级马里奥中所有功能与关卡,精细程度不逊原版游戏。
依赖库:无
2 、 Bunny Hunt (游戏地址: http://www.themaninblue.com/experiment/BunnyHunt/ )
猎兔,一款简单耐玩的网页狩猎游戏,没有使用第三方支持库,直接利用 css 与 JavasSript 实现。
依赖库:无
3 、 Bomberman ( 游戏地址: http://www.e-forum.ro/bomberman/dynagame.html )
炸弹人,经典到无以复加的桌面游戏,通过 JavaScript 获得了完美再现。
依赖库: MooTools , SoundManager2
4 、 PacMan ( 游戏地址: http://www.digitalinsane.com/api/yahoo/pacman/ )
又一款传说级的游戏,笔者开始怀疑有某个超级闲的家伙(或组织),开始悄悄将红白机时代的游戏统一移植为 web 版……嗯,或许近些年出现的 JavaScript 版 FC 模拟器就是他们的阴谋产物……
依赖库: YUI
5 、 Ajax Chinese Chess (游戏地址: http://ajaxchess.pragmaticlogic.com/ )
举凡识字的中国人看到此图,就会知道这是一款基于 JavaScript 的中国象棋游戏……
依赖库: MooTools , SoundManager2
6 、 Sudoku (游戏地址: http://www.dhtmlgoodies.com/scripts/game_sudoku/game_sudoku.html )
疯狂走红的数独游戏, JavaScript 狂人们又怎么可能放过呢?(似乎所有可以进行图形显示的系统上都能跑这个游戏了……)
依赖库:无
7 、 Spacius (游戏地址: http://scriptnode.com/lab/spacius/ )
就是著名的雷电啦,完成度相当高的经典射击游戏,效果流畅,笔者第一次运行时曾一度误以为在玩 Flash 。
依赖库: SoundManager2
8 、 Browser Shooter ( 游戏地址: http://valums.com/demos/game/ )
想让 IE 干掉 Firefox 抑或 Chrome ?哎,现实生活中是没希望了——不过,在该游戏中你却可以暂时做到这一点。
依赖库: jQuery
9 、 Berts Breakdown ( 游戏地址: http://www.paulbrunt.co.uk/bert/ )
又一款强悍到逆天的 JavaScript 横版游戏,在 Chrome 下的表现已经与同类 Flash 游戏不相伯仲了。
依赖库: 无
10 、 JS-Wars (游戏地址: http://29a.ch/jswars/ )
雷电类的横版射击游戏,似乎用 JavaScript 进行游戏开发的家伙都很喜欢横板游戏……作者在游戏介绍里写到——你们的任务是:找出骷髅博士,并消灭他!
依赖库: jQuery
11 、 Javascript Wolfenstein 3D (游戏地址: http://www.nihilogic.dk/labs/wolf/ )
由传说中的天才 JS 程序员—— Jacob Seidelin 所作(瞧瞧,人家名字是怎么叫的,学问啊……)。移植自世界上第一款第一人称射击游戏(有争议,一说为《 Ultima Underworld 》),也就是《重返德军总部》前作《德军总部》的 JavaScript 复刻版。
仅从现阶段 JavaScript 综合性能来说,其完成度之高令人叹为观止,恐怕连部分 Flash 游戏开发者也要自惭形秽。如果有朝一日 WebGL 标准普及了,哪怕该作者用 JavaScript 复刻出一个魔兽世界偶都毫不奇怪……唯一遗憾的是,此游戏依赖于 JavaScript 的 Canvas 技术,可能对 IE 不友好……
依赖库: SoundManager2
PS :本想收录 js 版《白之绊》、《逆转裁判》、《大恶司》等,却发现其对外链接皆已无法使用,故缺(似乎相关作者都跑去开发 web 网游,集体生死未卜中……)。
再者,长城以外 http://www.javascriptgaming.com/ 上还有很多 JavaScript 游戏实现,由于时间关系此处不一一列举,关心者请自行“翻而阅之”。
————————正文斩断,相关退散————————
转了不少JavaScript游戏过来,忽然自己也想写点东西,所以用开发了“半截”的LGame-Simple-0.2.5写了其中一个JavaScript游戏的复刻(目前修正了前版部分Bug,添加了一些精灵与辅助功能,但0.2.5的核心功能尚未添加,可理解为传说中的“降龙十八缺三掌”状态……),怎么说Java开发游戏也比JavaScript方便嘛,无论是桌面上,抑或网页里……
PS:不要问偶为什么移植Bunny Hunt而不是Javascript Wolfenstein 3D……除非偶吃顶了,或者不用睡觉……(另外偶最近会先忙正事,LGame将暂时停笔,留待12月中旬继续……12月底前发布0.2.5版……)
下载地址:http://code.google.com/p/loon-simple/downloads/list
package org.loon.test; import java.awt.Color; import java.awt.Graphics2D; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import org.loon.framework.game.simple.GameScene; import org.loon.framework.game.simple.action.map.Vector2D; import org.loon.framework.game.simple.action.sprite.Label; import org.loon.framework.game.simple.action.sprite.StatusBar; import org.loon.framework.game.simple.action.sprite.Picture; import org.loon.framework.game.simple.action.sprite.Sprite; import org.loon.framework.game.simple.action.sprite.Sprites; import org.loon.framework.game.simple.core.Deploy; import org.loon.framework.game.simple.core.LSystem; import org.loon.framework.game.simple.core.LTimer; import org.loon.framework.game.simple.core.LTimerContext; import org.loon.framework.game.simple.core.Screen; import org.loon.framework.game.simple.window.LButton; import org.loon.framework.game.simple.window.LPanel; import org.loon.framework.game.simple.window.LTag; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:[email protected] * @version 0.1 */ public class BunnyHunt extends Screen { interface IBunny { int type(); void reset(); void kill(); void setVisible(boolean visible); } private int level, count; private class Bunny extends Sprite implements IBunny { /** * */ private static final long serialVersionUID = 1L; private boolean init, kill; private int top, bottom, type; private LTimer timer; private Vector2D oldVector2D; public Bunny(String fileName, int row, int col, int top, int bottom) { super(fileName, row, col); this.top = top; this.bottom = bottom; this.isRunning(false); this.setCurrentFrameIndex(0); this.timer = new LTimer(100); this.reset(); } public void setLocation(double x, double y) { super.setLocation(x, y); this.oldVector2D = new Vector2D(x, y); } public int type() { return type; } public void reset() { this.kill = false; this.init = false; this.setVisible(false); this.setLocation(oldVector2D); if (getTotalFrames() == 2) { this.setCurrentFrameIndex(0); } } public void update(long elapsedTime) { if (!isVisible()) { return; } super.update(elapsedTime); if (gameStart) { if (!init) { if (y() > top) { // 精灵坐标向上移动(5倍速) this.move_up(5); } else { this.init = true; } } if (init && timer.action(elapsedTime)) { if (kill) { if (getTotalFrames() != 2) { this.type = 1; this.setCurrentFrameIndex(2); } } timer.setDelay(10); if (y() > bottom) { // 精灵坐标向下移动(10倍速) this.move_down(10); if (y() >= BunnyHunt.this.getHeight()) { this.reset(); BunnyHunt.this.randomBunny(); } } } } } public boolean isKill() { return kill; } public void kill() { if (getCurrentFrameIndex() != 2) { this.setCurrentFrameIndex(1); this.timer.setDelay(100); this.kill = true; } } } // 信息选择框,用于显示重启/结束菜单 private class MsgBox extends LPanel { private LTag text2 = new LTag("" + count, 370, 150, 50, 50); public void setNumber(int num) { text2.setTag(num); } public MsgBox(int x, int y, int w, int h) { super(x, y, w, h); // 面板设为灰色 setBackground(Color.GRAY); // 透明度0.5f setAlpha(0.5f); LButton button1 = new LButton("games/button_reload.gif", null, 180, 200) { public void doClick() { BunnyHunt.this.removeAll(); BunnyHunt.this.initBunny(); } }; LButton button2 = new LButton("games/button_stop.gif", null, 400, 200) { public void doClick() { BunnyHunt.this.removeAll(); BunnyHunt.this.setBackground("games/closing.jpg"); } }; LTag text1 = new LTag("Number of bunnies mutilated:", 215, 90, 50, 50); text1.setColor(Color.WHITE); text1.setFont("Dialog", 0, 25); text2.setColor(Color.WHITE); text2.setFont("Dialog", 1, 30); add(text1); add(text2); add(button1); add(button2); } } private class Cloud extends Picture { private static final long serialVersionUID = 1L; private LTimer timer = new LTimer(20); public Cloud(String fileName, int x, int y) { super(fileName, x, y); } public void update(long elapsedTime) { if (isVisible() && timer.action(elapsedTime)) { // 自动向左移动 move_left(); if(x()<0){ setX(BunnyHunt.this.getWidth()); } } } } private Label label1 = new Label("LEVEL :", "Dialog", 0, 15, 300, 23), label2 = new Label("", "Dialog", 1, 12, 360, 22), label3 = new Label("LIVES :", "Dialog", 0, 15, 530, 23); private StatusBar timeBar = new StatusBar(400, 15, 100, 5); private MsgBox msgBox = new MsgBox(0, 0, 800, 400); private Bunny bunny1, bunny2, bunny3, bunny4, bunny5; private IBunny[] bunnies; private Sprite lives = new Sprite("games/lives.gif", 600, 7, 60, 21); private Picture hill = new Picture("games/hill.png", 200, 288); private Cloud cloud1 = new Cloud("games/cloud.png", 195, 20); private Cloud cloud2 = new Cloud("games/cloud2.png", 75, 20); private Picture hills = new Picture("games/hills.png", 0, 235); private LTimer time = new LTimer(2 * LSystem.SECOND); private boolean gameStart; public BunnyHunt() { // 设定初始背景 this.setBackground("games/splash.jpg"); LButton startButton = new LButton("games/button_start.gif", null, 165, 260) { public void doClick() { // 变更背景图像 BunnyHunt.this.setBackground("games/stage.jpg"); BunnyHunt.this.initBunny(); this.dispose(); } }; // 添加开始按钮 this.add(startButton); } private void endGame() { this.gameStart = false; this.msgBox.setNumber(count); this.timeBar.setHit(false); this.add(msgBox); } private void randomBunny() { for (int i = 0; i < level && i < 3; i++) { bunnies[getBunnyRandom(bunnies.length)].setVisible(true); } } private int getBunnyRandom(int type) { return LSystem.random.nextInt(type); } private void initBunny() { this.gameStart = true; this.level = 1; this.count = 0; this.bunny1 = new Bunny("games/bunny1.png", 84, 152, 130, 50); this.bunny2 = new Bunny("games/bunny2.png", 119, 152, 190, 50); this.bunny3 = new Bunny("games/bunny3.png", 122, 152, 150, 50); this.bunny4 = new Bunny("games/bunny4.png", 135, 152, 180, 50); this.bunny5 = new Bunny("games/bunny5.png", 140, 152, 180, 50); this.bunnies = new IBunny[] { bunny1, bunny2, bunny3, bunny4, bunny5 }; this.timeBar.setHit(true); this.timeBar.empty(); this.label2.setLabel(level); this.label1.setAlpha(0.8f); this.add(label1); this.add(label2); this.label3.setAlpha(0.8f); this.add(label3); this.add(timeBar); this.lives.isRunning(false); this.lives.setCurrentFrameIndex(0); this.add(lives); this.bunny1.setLocation(40, 400); this.bunny3.setLocation(550, 400); this.bunny4.setLocation(130, 400); this.bunny5.setLocation(430, 400); this.add(bunny1); this.add(bunny3); this.add(bunny4); this.add(bunny5); this.add(hills); this.bunny2.setLocation(410, 400); this.add(bunny2); this.add(hill); this.add(cloud1); this.add(cloud2); this.randomBunny(); } public void alter(LTimerContext timer) { if (time.action(timer.getTimeSinceLastUpdate())) { if (timeBar.getValue() < timeBar.getMaxValue()) { timeBar.setUpdate(timeBar.getValue() + 10); } else { timeBar.empty(); level += 1; label2.setLabel(level); } } } public void draw(Graphics2D g) { } public void leftClick(MouseEvent e) { if (contains(msgBox)) { return; } Sprites ss = getSprites(); for (int i = ss.size(); i > -1; --i) { if (ss.getSprite(i) instanceof IBunny) { if (onClick(ss.getSprite(i))) { IBunny bunny = ((IBunny) ss.getSprite(i)); if (bunny.type() == 1) { lives .setCurrentFrameIndex(lives .getCurrentFrameIndex() + 1); if (lives.getCurrentFrameIndex() >= 3) { endGame(); } } else { bunny.kill(); count += 1; } return; } } } } public void middleClick(MouseEvent e) { } public void onKey(KeyEvent e) { } public void onKeyUp(KeyEvent e) { } public void rightClick(MouseEvent e) { } public static void main(String[] args) { GameScene frame = new GameScene("猎兔(素材取自同名Javascript游戏)", 800, 400); Deploy deploy = frame.getDeploy(); deploy.setScreen(new BunnyHunt()); deploy.setLogo(false); deploy.setShowFPS(true); deploy.setFPS(100); deploy.mainLoop(); frame.showFrame(); } }