A pad to document the structure of the browser quest game code
Technologies:
- client: html5, css3, websockets,
- server: require, underscore, nodejs, (installation via npm!)
Documentation:
- not much in the original repo but you can view the forks ( https://github.com/mozilla/BrowserQuest/network ) and look at ones that are relatively active. This is interesting in and of itself and sometimes people have documented their changes and/or the existing code.
- @micolous and @browserquest have started some documentation in their repos: https://github.com/micolous/BrowserQuest/tree/master/doc
- boostrapping: https://github.com/browserquest/BrowserQuest/blob/master/doc/client/bootstrap.md
- game protocol/new player initialization: https://github.com/micolous/BrowserQuest/blob/master/doc/server/protocol.md
- The browserquest/BrowserQuest wiki is receiving fairly active development ( https://github.com/browserquest/BrowserQuest/wiki ). @jeffplang has joined their team, and his content has been merged into it.
Installation:
- clone the repo https://github.com/mozilla/BrowserQuest.git
- make sure you have nodejs and npm installed. http://nodejs.org/#download
- the dependencies are listed in package.json in the top level directory. they can be installed with
from the top level directory.
- for server:
edit server/config.json to reflect the port on which the server will run.leave "metrics_enabled": false. otherwise i would get the error:ERROR uncaughtException: Error: connect ECONNREFUSED
- then run from the top level directory
- for client,
cp config_build.json-dist config_build.json, edit for correct host/portcp config_local.json-dist config_local.json, edit for correct host/port** host needs to be an ip or domain, eg for localhost, you need to use "127.0.0.1". "localhost" caused an error connecting to the server.** if you have a proper domain, don't prefix it with http:// - eg. particlequest.com, not http://particlequest.com. - copy the shared directory into client/ dir: cf. https://gist.github.com/2275361- start an http server in the client directory. eg. to use python's build in http server, type: $ python -m SimpleHTTPServer 8080
- visit localhost:client_port (eg. http://localhost:8080) to view index.html
Resources:
- there's widespread use of RequireJS' "define": http://requirejs.org/docs/api.html#define
- Liberated Pixel Cup References on Pixel Art: http://lpc.opengameart.org/static/lpc-style-guide/styleguide.html#useful-generalist-resources
- Liberated Pixel Cup Free Art Submissions: http://opengameart.org/lpc-art-entries
- http://opengameart.org/
- free bitmap paint program: http://code.google.com/p/grafx2/
Overview:
- The server contains code related to any of the multiplayer logic (eg. player interactions, movements, etc. all go through the server because you need to check things like if it's occupied, whether movements to requested locations are valid given the state of the game, etc.).
- The client code focuses on entity-specific behaviours and interactions.
- The communication between client and server happens via the gameclient.js (client side) which talks to the gameserver.js (server side) using the messages and entity types defined in shared/gametypes.js.
- Players are of type Warrior (client/js/warrior.js) and the game class is initialized with an empty Warrior character. Warrior is of type Player (player.js)
- shared/js/gametypes.js: all the entities are enumerated and identified by integer (eg. Warrior is a 1) and grouped according to categories or "kind" (object, weapon, NPC, etc.). weapons and armor are ranked objects.
- Mobs
- Objects
- Achievements:
- Sprites:
- sprites need a row for each type of animation that character can undergo.
- correspondence between location within a sprite and character action is specified in json files within the client/sprites/ directory.
- the json file names different types of animations (eg. walk right, walk left). the set of images associated with each animation are contained in a single row, and the number of images per animation is given by the length parameter.
- mobs characters
- Initialization/World Setup:
- server/maps/world_server.json contains list of
- width, height - of the tile viewing area???
- collisions - tile names? i think these are where you cannot walk. (why are these not coordinates?)
- doors - list of hashes of the form {"x":80,"y":211,"p":0,"tcx":148,"tcy":306,"to":"u","tx":155,"ty":311}
- checkpoints: {"id":1,"x":14,"y":210,"w":9,"h":2,"s":1}
- roaming areas: {"id":0,"x":10,"y":206,"width":13,"height":7,"type":"rat","nb":3} - defined an area with a specific type and number of mob characters present?
- chestAreas: {"x":2,"y":77,"w":6,"h":5,"i":[24,66],"tx":6,"ty":75}
- staticChests: staticChests":[{"x":157,"y":141,"i":[61]}
- staticEntities: {"1305":"spectre", ... "2997":"deathknight","3191":"eye","3251":"skeleton". ...
- tilesize: 16px.
- server/js/worldserver.js reads this file and sets up all the entities
- Initial Position:
- when a new client connects (XXX), it requests a position from the server (XXX).
- the server/js/worldserver.js has a call back this.onPLayerConnect() that sets a random starting position either from within the last checkpoint of the player or, if a new player, chooses a randon location from one of several startingAreas in server/js/map.js: getRandomStartingPosition().
- starting areas are those checkpoints (in the world_server.json) that have s == 1 (server/js/map.js: initCheckPoints().
- initial statis entity positions - eg. you want to place an NPC in one of the starting areas:
- - tile id vs. x,y position? in server/js/worldserver.js, spawnStaticEntities() calls map.tileIndexToGridPosition()
- Attacking: the in client/js/game.js, the click() function, as it says, "Processes game logic when the user triggers a click/touch event during the game." this includes calling makePlayerAttack() if the target location of the click contains an entity of type Mob. makePlayerAttack() notifies the server by sending an ATTACK message and then calling createAttackLink() which calls engage(). engage (defined in client/js/character.js) sets attackingMode to be true, sets the target in the player object, and assigns the attacking player to follow the target if it moves.
- that's about it on the client side. on the server side, the ATTACK message invokes a callback onEntityAttack (in server/js/worldserver.js)
- ... (more server)
- - attack animation
- - attack computing when dead
- - despawn
- - object rewards
- Messages: messages are passed between client and server using a GameClient object (defined in client/js/gameclient.js), set to this.client inside the main Game (client/js/game.js).
Game Initialization
index.html triggers (via rquire-jquery) initApp() in main.js.
initApp():
- i think this calls init() of most of the main game classes referenced below.
Then the page/game waits till a new player is created or joins.
When a character is created:
client/js/main.js: app.tryStartingGame()
client/js/app.js: tryStartingGame() calls startGame() calls start()
- sets some server options. game.username (ie player-selected username) is set here.
- calls this.game.run()
client/js/game.js: run()
- calls initPlayer(), which sets the sprite according to this.player.getSpriteName(); the sprite is actually hard coded into the Player class as "clotharmor"; the "kind" is used to
Things to customize:
- player-user look and feel - creating 8 bit characters
- resources: see above
- create a new class that extends Player, similar to warrior.js, and replaces this.spriteName
- add the entity to shared/js/gametypes.js
- could optionally extend the initial signup form to specify sprite asset per-person.
- default sprite for Warrior: client/img/[3,2,1]/clotharmor.png
- objects to be picked up, and what happens when you get them. They could provide you with clues about where the particles are?
- initial location of character
- unlock the different subatomic particles
- objects - money, energy, LHC.
- developing the script - questions that lead to accessible explanations of why we think the model of fundamental forces and particles makes sense.
- Example question: Which particle is both a quantum of light and the force carrier for electromagnetic radiation?
- additional assets: picking up "weapons", armor, objects.
- initial player placement and nearby NPCs, assets
- badges
- the "world" design - pixel art for LHC, the universe...
- creating new NPCs - scripts, graphics
- particle interactions
GamePlay Ideas:
- instead of killing rats you
- Capture particles that have escaped from the LHC?
- find facts and answer puzzles in order to find the key particles.
- the NPCs provide advice. Or they could ask you questions about the lost particles?
- Which particles will appear in the game: photon, higgs boson, top quark, proton, neutron, electron?
- the adversarial objects
- in more advanced levels (which we won't get to yet!), your goal is to unlock the parameters of a model, so that you can tweak the inputs to a simulation.
Initialization Log Output:
=====================================================
=====================================================
App initialized. log.js:14
--------- log.js:22
Factor:2 log.js:22
W:30 H:14 log.js:22
--------- log.js:22
Factor:2 log.js:22
W:30 H:14 log.js:22
#entities set to 960 x 448 log.js:22
#background set to 960 x 448 log.js:22
#foreground set to 960 x 448 log.js:22
Loading map with web worker. log.js:14
Loading tileset: img/2/tilesheet.png log.js:14
Loading tileset: img/3/tilesheet.png log.js:14
2Map tileset loaded. log.js:14
All map tilesets loaded. log.js:22
Map loaded.
... sign in/create character...
Starting game with local dev config. log.js:22
Loading sprites... log.js:14
All sprites loaded. log.js:22
Loading sound files... log.js:14
Initialized the entity grid. log.js:14
Initialized the item grid. log.js:14
Initialized the pathing grid with static colliding cells. log.js:14
Initialized the rendering grid. log.js:14
Finished initPlayer log.js:22
Trying to connect to server : ws://127.0.0.1:8000/ log.js:14
audio/sounds/loot.mp3 is ready to play. log.js:22
audio/sounds/hit1.mp3 is ready to play. log.js:22
audio/sounds/hit2.mp3 is ready to play. log.js:22
audio/sounds/hurt.mp3 is ready to play. log.js:22
audio/sounds/heal.mp3 is ready to play. log.js:22
audio/sounds/chat.mp3 is ready to play. log.js:22
audio/sounds/death.mp3 is ready to play. log.js:22
audio/sounds/firefox.mp3 is ready to play. log.js:22
audio/sounds/achievement.mp3 is ready to play. log.js:22
audio/sounds/kill1.mp3 is ready to play. log.js:22
audio/sounds/kill2.mp3 is ready to play. log.js:22
audio/sounds/noloot.mp3 is ready to play. log.js:22
audio/sounds/teleport.mp3 is ready to play. log.js:22
audio/sounds/chest.mp3 is ready to play. log.js:22
audio/sounds/npc.mp3 is ready to play. log.js:22
Connected to server 127.0.0.1:8000 log.js:14
Starting client/server handshake log.js:14
audio/sounds/npc-end.mp3 is ready to play. log.js:22
audio/sounds/revive.mp3 is ready to play. log.js:22
Loading music files... log.js:14
data: [1,5242,"arachne",71,221,80] log.js:22
Received player ID from server : 5242 log.js:14
Game loop started. log.js:14
data: [[17,1,null],[19,926,927,928,1120,1121,1122,1220,1221,1222,1820,1821,11920,11921,12220,867220]] log.js:22
data: [[2,926,61,60,206],[2,927,61,34,210],[2,928,39,77,232],[2,1120,2,43,211,2],[2,1121,2,40,211,4],[2,1122,2,47,214,4],[2,1220,2,40,225,1],[2,1221,2,32,226,4],[2,1222,2,32,218,1],[2,1820,2,73,227,3],[2,1821,2,75,221,4],[2,11920,2,32,231,3],[2,11921,2,35,233,4],[2,12220,2,58,230,2],[2,867220,47,67,220]] log.js:22
Spawned sword2 (926) at 60, 206 log.js:14
Spawned sword2 (927) at 34, 210 log.js:14
Spawned cake (928) at 77, 232 log.js:14
Spawned rat (1120) at 43, 211 log.js:22
Spawned rat (1121) at 40, 211 log.js:22
Spawned rat (1122) at 47, 214 log.js:22
Spawned rat (1220) at 40, 225 log.js:22
Spawned rat (1221) at 32, 226 log.js:22
Spawned rat (1222) at 32, 218 log.js:22
Spawned rat (1820) at 73, 227 log.js:22
Spawned rat (1821) at 75, 221 log.js:22
Spawned rat (11920) at 32, 231 log.js:22
Spawned rat (11921) at 35, 233 log.js:22
Spawned rat (12220) at 58, 230 log.js:22
Spawned agent (867220) at 67, 220 log.js:22
- Error: audio/sounds/village.mp3 could not be loaded.
- paticle and anti-particle
- each anti particle drops data when its convinced
- you need to gather data to make enough observation to unlock the particles (achievements)
- particledex (pdg)
- music: cernettes.mp3, jamendo (openly licensed music), soundcloud. The ATLAS Boogie via web link.
- weapons - 5 weapons -
all the checkpoints:
"checkpoints":[
{"id":1,"x":14,"y":210,"w":9,"h":2,"s":1},
{"id":2,"x":40,"y":208,"w": 6,"h":5,"s":1},
{"id":3,"x":40,"y":221,"w":5,"h":4,"s":1},
{"id":4,"x":13,"y":223,"w":4,"h":3,"s":1},
{"id":5,"x":68,"y":220,"w":5,"h":5,"s":1},
{"id":6,"x":40,"y":232,"w":5,"h":5,"s":1},
{"id":7,"x":14,"y":233,"w":4,"h":3,"s":1},
{"id":8,"x":41,"y":184,"w":8,"h":4,"s":0},
{"id":9,"x":4,"y":184,"w":4,"h":3,"s":0},
{"id":10,"x":70,"y":184,"w":4,"h":3,"s":0},
{"id":11,"x":41,"y":133,"w":4,"h":3,"s":0},
{"id":12,"x":156,"y":118,"w":3,"h":2,"s":0},
{"id":13,"x":68,"y":100,"w":4,"h":2,"s":0},
{"id":14,"x":32,"y":81,"w":10,"h":2,"s":0},
{"id":15,"x":15,"y":50,"w":6,"h":3,"s":0},
{"id":16,"x":42,"y":49,"w":4,"h":2,"s":0},
{"id":17,"x":67,"y":52,"w":4,"h":2,"s":0},
{"id":18,"x":76,"y":48,"w":4,"h":2,"s":0},
{"id":19,"x":7,"y":257,"w":4,"h":3,"s":0},
{"id":20,"x":33,"y":255,"w":5,"h":2,"s":0},
{"id":21,"x":48,"y":253,"w":3,"h":2,"s":0},
{"id":22,"x":65,"y":250,"w":7,"h":2,"s":0},
{"id":23,"x":65,"y":143,"w":5,"h":2,"s":0},
{"id":24,"x":55,"y":92,"w":6,"h":2,"s":0}
],
note: x,y is the coordinates in the whole map (use Tiled); w,h is the area of the spawning point; s is a binary operator that makes the area a starting point or not
------------------------------------------------------------------------------------
Intro:
Welcome to ParticleQuest, fearless young scientist!
The discovery of the Higgs Boson has caused all the particles to become extremely massive
Now there has been a terrible meltdown at the LHC
And all the particles have escaped!
Please, you are young and spritely.
We desperately need your help to find the Higgs Boson
And stop this madness!
------------------------------------------------------------------------------------
DON'T TOUCH PLEASE...
Monsters:
rat == ve:
,
hp: 0.002,
armor: 1,
weapon: 1
}
crab == vmu:
,
hp: 170.0,
armor: 1,
weapon: 1
}
bat == e:
,
hp: 500.0,
armor: 1,
weapon: 1
}
goblin == u:
,
hp: 2400.0,
armor: 2,
weapon: 1
}
skeleton == d:
,
hp: 4800.0,
armor: 2,
weapon: 2
}
snake == vtau:
,
hp: 15500.0,
armor: 2,
weapon: 1
}
ogre == s:
,
hp: 104000.0,
armor: 3,
weapon: 2
}
skeleton2 == mu:
,
hp: 105700.0,
armor: 3,
weapon: 2
}
eye == c:
,
hp: 1270000.0,
armor: 4,
weapon: 3
}
spectre == tau:
,
hp: 1800000.0,
armor: 4,
weapon: 3
}
death knight == b:
,
hp: 4200000.0,
armor: 4,
weapon: 4
}
boss == H:
,
hp: 125000000.0,
armor: 6,
weapon: 7
}
## i plan the boss will be hard to kill if you are playing alone.. it was supposed to be defeated with other people :).. another way to promote the game
## This code goes to server\js\properties.js
------------------------------------------------------------------------------------
DON'T TOUCH PLEASE...
Weapons:
0.0004, 93.50000000000001, 720.0, 3565.0, 16640.0, 457200.0, 8750000.0
2e-05, 4.675000000000001, 36.0, 178.25, 832.0, 22860.0, 437500.0
weapon = [0.2*ve, 0.55*vmu, 0.3*u, 0.23*vtau, 0.16*s, 0.36*c, 0.07*H]
a = 0
unc = []
while a < len(weapon):
unc.append(0.05*weapon[a])
a += 1
## check server\js\formulas.js and randomint from server\js\utils.js
------------------------------------------------------------------------------------
Debugging - delete localstorage manually to reload new content
------------------------------------------------------------------------------------
NPCs:
Guard 01 (4, 195) == cern guard
[
"Bonjour. ",
"Votre carte s'il vous plait. ",
"Laissez tomber.",
" ",
"I used to be like you... ",
"...a strong-willed student... ",
"...but then I took an arrow to the knee. "
]
Guard 02 (7, 195) == cern guard
Guard 03 (41, 195) == cern guard
Guard 04 (47, 195) == cern guard
Guard 05 (70, 197) == cern guard
Guard 06 (73, 197) == cern guard
Guard 07 (32, 257) == cern guard
Guard 08 (38, 257) == cern guard
Guard 09 (65, 253) == cern guard
Guard 10 (72, 253) == cern guard
King (126, 138) == Peter Higgs
[
"Help! ",
"Help! Help! ",
"Help! ",
"You must find my boson ",
"I need to have my boson... ",
"...or else I won't be able to... ",
"...get my Nobel Prize! ",
]
Agent (67, 220) == Z0
[
"Hey! I'm a Z<sup>0</sup> boson. ",
"I'm neutral in electric charge. "
]
Rick (127, 186) == Graviton
[
"You've found me! ",
"Finally someone has found me. ",
"I thought humankind stopped... ",
"...on looking for me. ",
"I'm Graviton by the way. "
]
VillageGirl (15, 222) == Photon
[
"You see that? ",
"You see that? ",
"You see that? ",
"You can see that because of me. ",
"I'm Photon. "
]
Villager (37, 200) == Gluon
[
"Nature rarer uses yellow ",
"Than another hue; ",
"Saves she all of that for sunsets,-- ",
"Prodigal of blue, ",
"Spending scarlet like a woman, ",
"Yellow she affords ",
"Only scantly and selectly, ",
"Like a lover's words. ",
"-- Emily Dickinson "
"Oh by the way, I'm Gluon."
]
Coder (154, 138) == Truth Quark
[
"Please don't annihilate me. ",
"I don't want to fight you.",
"I'm too heavy to move. ",
"I'm Truth Quark. "
]
Scientist (127, 293) == W+
[
"Could you look for my lover? ",
"We were supposed to meet at the beach. ",
"But my parents found it out and held me here. ",
"Please tell my lover that I won't be able to go to the beach. "
"My name is W<sup>+</sup>."
]
Nyan (75, 164) == Schroedinger's Cat
[
"Am I real? ",
"Am I alive or am I dead? ",
"This is a recorded message. ",
"Don't assume that I am alive... ",
"...just because you can read this. "
"What does (|alive> + |dead>)/sqrt(2) mean? ",
]
Sorcerer (15, 246) == Gluon
[
"You need to find the anti-sword... ",
"...to defeat the other monsters. "
]
Priest (18, 209) == Photon
[
"Life is meaningless... ",
"...without you. ",
" ",
" I never thought...",
"...living with a secret...",
"...that was never shared... ",
"...like loving you...",
"...would be this hard."
" ",
"Let the rain fall down... ",
"...over my head... ",
"...and let these tears... ",
"...be masked by the water... ",
"...rushing over my cheeks"
]
BeachNpc (76, 293) == W-
[
"W<sup>+</sup>? ",
"W<sup>+</sup>? ",
"Where are you, W<sup>+</sup>? ",
"Oh. Hi.",
"Do you know where W<sup>+</sup> is? ",
"I'm W <sup>-</sup>. "
]
ForestNpc (x, y) - same as villager icon but the villager was used so this is not used/DNE
DesertNpc (48, 57) == Z0
[
"Woah. You are still alive. ",
"You might be strong. ",
"Please bring us back to our original size. "
]
LavaNpc (x, y) - not used/DNE
Octocat (10, 235) == Photon:
[
"Hey! Welcome brave student! ",
"Woah, you have an antidagger... ",
"...that has the same power... ",
"...of an electron neutrino. ",
"You can annihilate them. "
]