Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Some work on comments, to make docco a bit happier.

  • Loading branch information...
commit 9acf3599d05722cfb5ebdb29da625441a403acff 1 parent 98491d6
Stéphan Kochen authored
8 src/client/base64.coffee
View
@@ -31,17 +31,17 @@ decodeBase64 = (input) ->
else if cc == 47 then 63 # /
else if cc == 61 then -1 # Padding
else throw new Error "Invalid base64 input character: #{c}"
- # Did we complete a quad?
- continue unless quadIndex == 3
- # Calculate the octet values.
+ # Did we complete a quad? If so, calculate the octet values and add them to the output.
# We take bits from the character values as follows: 000000 001111 111122 222222
+ continue unless quadIndex == 3
output[outputIndex++] = ((quad[0] & 0x3F) << 2) + ((quad[1] & 0x30) >> 4)
output[outputIndex++] = ((quad[1] & 0x0F) << 4) + ((quad[2] & 0x3C) >> 2) unless quad[2] == -1
output[outputIndex++] = ((quad[2] & 0x03) << 6) + ((quad[3] & 0x3F) ) unless quad[3] == -1
+ # Return output.
output
-# Exports.
+#### Exports
exports.decodeBase64 = decodeBase64
9 src/client/brequire.coffee
View
@@ -2,6 +2,8 @@
# This version is slightly modified, and rewritten in CoffeeScript.
+# The require function loads the module on-demand, or returns the existing `exports` object in case
+# the module is already loaded.
require = (path) ->
unless m = require.modules[path]
throw "Couldn't find module for: #{path}"
@@ -12,8 +14,11 @@ require = (path) ->
m.exports
+# Our index of modules.
require.modules = {}
+# Helper used to create the `require` function used in the inner scope of the module. It takes
+# care of making paths relative to the current module work as expected.
require.bind = (path, directory) ->
(p) ->
return require(p) unless p.charAt(0) == '.'
@@ -27,6 +32,8 @@ require.bind = (path, directory) ->
require cwd.join('/')
+# The function used to define a module. Each module that is loaded into the browser should be
+# wrapped with a call to this function.
require.module = (path, directory, fn) ->
fn.directory =
if typeof(directory) == 'boolean'
@@ -38,5 +45,5 @@ require.module = (path, directory, fn) ->
require.modules[path] = fn
-# Exports.
+#### Exports
window.require = require
23 src/client/index.coffee
View
@@ -22,6 +22,9 @@ DefaultRenderer = require './renderer/offscreen_2d'
EverardIsland = require './everard'
+
+#### Common logic
+
class BaseGame
constructor: ->
# Setup the key handlers.
@@ -51,12 +54,11 @@ class BaseGame
@renderer = new DefaultRenderer(@resources.images, @sim)
@sim.map.setView(@renderer)
- # Game loop.
+ ##### Game loop.
start: ->
return if @gameTimer?
- # Are we networked or not?
@tick()
@lastTick = Date.now()
@@ -76,7 +78,7 @@ class BaseGame
@lastTick += TICK_LENGTH_MS
@renderer.draw()
- # Abstract methods.
+ ##### Abstract methods.
# Called after resources are loaded.
startup: ->
@@ -89,6 +91,9 @@ class BaseGame
handleKeyup: (e) ->
+
+#### Local game simulation
+
class LocalGame extends BaseGame
startup: ->
map = SimulationMap.load decodeBase64(EverardIsland)
@@ -100,7 +105,7 @@ class LocalGame extends BaseGame
tick: ->
@sim.tick()
- # Key press handlers.
+ ##### Key press handlers.
handleKeydown: (e) ->
switch e.which
@@ -122,6 +127,8 @@ class LocalGame extends BaseGame
e.preventDefault()
+#### Networked game simulation
+
class NetworkGame extends BaseGame
constructor: ->
@heartbeatTimer = 0
@@ -155,7 +162,7 @@ class NetworkGame extends BaseGame
@heartbeatTimer = 0
@ws.send('')
- # Key press handlers.
+ ##### Key press handlers.
handleKeydown: (e) ->
return unless @ws?
@@ -179,7 +186,7 @@ class NetworkGame extends BaseGame
else return
e.preventDefault()
- # Network message handlers.
+ ##### Network message handlers.
handleMessage: (e) ->
@netctx.authoritative = yes
@@ -238,6 +245,8 @@ class NetworkGame extends BaseGame
-1
+#### Entry point
+
game = null
init = ->
@@ -247,7 +256,7 @@ init = ->
game = new NetworkGame()
-# Exports.
+#### Exports
exports.init = init
exports.start = -> game.start()
exports.stop = -> game.stop()
7 src/client/loader.coffee
View
@@ -2,8 +2,9 @@
# firing a single event when everything is complete, and exposing resources in a tidy structure.
-# FIXME: Add audio file support. Needs to be smart about supported formats.
-# FIXME: Implement progress notification.
+# FIXME:
+# * Add audio file support. Needs to be smart about supported formats.
+# * Implement progress notification.
class Loader
constructor: ->
@@ -52,5 +53,5 @@ class Loader
onError: ->
-# Exports.
+#### Exports
module.exports = Loader
2  src/client/renderer/common_2d.coffee
View
@@ -118,5 +118,5 @@ class Common2dRenderer extends BaseRenderer
@ctx.restore()
-# Exports.
+#### Exports
module.exports = Common2dRenderer
2  src/client/renderer/direct_2d.coffee
View
@@ -35,5 +35,5 @@ class Direct2dRenderer extends Common2dRenderer
, stx, sty, etx, ety
-# Exports
+#### Exports
module.exports = Direct2dRenderer
6 src/client/renderer/index.coffee
View
@@ -39,7 +39,7 @@ class BaseRenderer
# Inherited from MapView.
onRetile: (cell, tx, ty) ->
- # Common functions.
+ #### Common functions.
# Draw a single frame.
draw: ->
@@ -67,6 +67,8 @@ class BaseRenderer
# Update all DOM HUD elements.
@updateHud()
+ #### HUD elements
+
# Draw HUD elements that overlay the map. These are elements that need to be drawn in regular
# game coordinates, rather than screen coordinates.
drawOverlay: ->
@@ -126,5 +128,5 @@ class BaseRenderer
$(node).attr('status', 'neutral')
-# Exports.
+#### Exports
module.exports = BaseRenderer
18 src/client/renderer/offscreen_2d.coffee
View
@@ -20,7 +20,9 @@ MAP_SIZE_SEGMENTS = MAP_SIZE_TILES / SEGMENT_SIZE_TILES
SEGMENT_SIZE_PIXEL = SEGMENT_SIZE_TILES * TILE_SIZE_PIXELS
-# This class represents a single segment.
+#### Cached segment
+
+# This class represents a single map segment.
class CachedSegment
constructor: (@renderer, x, y) ->
# Tile bounds
@@ -71,31 +73,34 @@ class CachedSegment
cell.x * TILE_SIZE_PIXELS, cell.y * TILE_SIZE_PIXELS, @ctx
+#### Renderer
+
+# The off-screen renderer keeps a 2D array of instances of MapSegment.
class Offscreen2dRenderer extends Common2dRenderer
constructor: (images, sim) ->
super
- # Build a 2D array of map segments.
@cache = new Array(MAP_SIZE_SEGMENTS)
for y in [0...MAP_SIZE_SEGMENTS]
row = @cache[y] = new Array(MAP_SIZE_SEGMENTS)
for x in [0...MAP_SIZE_SEGMENTS]
row[x] = new CachedSegment(this, x, y)
+ # When a cell is retiled, we store the tile index and update the segment.
onRetile: (cell, tx, ty) ->
- # Remember the tilemap index.
cell.tile = [tx, ty]
- # Notify the segment, so it can update it's buffer if it has one.
segx = floor(cell.x / SEGMENT_SIZE_TILES)
segy = floor(cell.y / SEGMENT_SIZE_TILES)
@cache[segy][segx].onRetile(cell, tx, ty)
+ # Drawing the map is a matter of iterating the map segments that are on-screen, and blitting
+ # the off-screen canvas to the main canvas. The segments are prepared on-demand from here, and
+ # extra care is taken to only build one segment per frame.
drawMap: (sx, sy, w, h) ->
ex = sx + w - 1
ey = sy + h - 1
- # Iterate all cache segments.
alreadyBuiltOne = no
for row in @cache
for segment in row
@@ -106,7 +111,6 @@ class Offscreen2dRenderer extends Common2dRenderer
# Make sure the segment buffer is available.
unless segment.canvas
- # Let's only draw one segment per frame, to keep things smooth.
continue if alreadyBuiltOne
segment.build()
alreadyBuiltOne = yes
@@ -119,5 +123,5 @@ class Offscreen2dRenderer extends Common2dRenderer
return
-# Exports
+#### Exports
module.exports = Offscreen2dRenderer
92 src/client/renderer/webgl.coffee
View
@@ -1,8 +1,8 @@
# The WebGL renderer works much like the Direct2D renderer, but uses WebGL to accomplish it.
# The advantage is that we can draw individual tiles, but actually feed them in large batches to
-# the graphics hardware using Vertex Buffer Objects. Another advantage is that we can do all the
-# styling we need in a fragment shader.
-
+# the graphics hardware using Vertex Buffer Objects (VBO). Another advantage is that we can do all
+# the styling we need in a fragment shader.
+#
# All in all, this is the least CPU intensive drawing method, but strangely not the smoothest.
@@ -13,6 +13,10 @@ BaseRenderer = require '.'
TEAM_COLORS = require '../../team_colors'
+
+#### Shaders
+
+# The vertex shader simply applies the transformation matrix, and interpolates texture coordinates.
VERTEX_SHADER =
'''
/* Input variables. */
@@ -30,6 +34,8 @@ VERTEX_SHADER =
}
'''
+# The fragment shader makes the decision which tilemap to sample from, and combines the styled
+# tilemap with the styling overlay. Three texture units are used.
FRAGMENT_SHADER =
'''
#ifdef GL_ES
@@ -68,7 +74,6 @@ FRAGMENT_SHADER =
}
'''
-
# Helper function that is used to compile the above shaders.
compileShader = (ctx, type, source) ->
shader = ctx.createShader type
@@ -79,6 +84,8 @@ compileShader = (ctx, type, source) ->
shader
+#### Renderer
+
class WebglRenderer extends BaseRenderer
constructor: (images, sim) ->
super
@@ -175,8 +182,9 @@ class WebglRenderer extends BaseRenderer
@handleResize()
$(window).resize => @handleResize()
+ # On resize, we update the canvas size, and recalculate the translation matrix. Because this is
+ # called at convenient times, we also check the GL error state at this point.
handleResize: ->
- # Update the canvas size.
@canvas[0].width = window.innerWidth
@canvas[0].height = window.innerHeight
@canvas.css(
@@ -185,43 +193,41 @@ class WebglRenderer extends BaseRenderer
)
@ctx.viewport(0, 0, window.innerWidth, window.innerHeight)
- # Recalculate the transformation matrix.
@setTranslation(0, 0)
- # This seems like a good spot to do a quick check for errors.
@checkError()
+ # This function checks the GL error state and throws an exception if necessary.
checkError: ->
gl = @ctx
unless (err = gl.getError()) == gl.NO_ERROR
throw "WebGL error: #{err}"
return
+ # Rebuild the translation matrix. The translation matrix accomplishes the following:
+ #
+ # A. Apply the requested translation by (px,py).
+ # B. The WebGL coordinate space runs from -1 to 1. Scale the pixel coordinates to fit in the
+ # range 0 to 2.
+ # C. Then translate to fit in the range -1 to 1.
+ # D. The WebGL y-axis is inverted compared to what we want. So multiply the y-axis by -1.
+ #
+ # To chain all this into one matrix, we have to apply these into reverse order. The math then
+ # looks as follows:
+ #
+ # D C B A
+ # | 1 0 0 0 | | 1 0 0 -1 | | xt 0 0 0 | | 1 0 0 px |
+ # T = | 0 -1 0 0 | x | 0 1 0 -1 | x | 0 xy 0 0 | x | 0 1 0 py |
+ # | 0 0 1 0 | | 0 0 1 0 | | 0 0 1 0 | | 0 0 1 0 |
+ # | 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 |
+ #
+ # To top that off, WebGL expects things in column major order. So the array indices should be
+ # read as being transposed.
setTranslation: (px, py) ->
- # Rebuild the translation matrix.
-
- # A. Apply the requested translation by (px,py).
- # B. The WebGL coordinate space runs from -1 to 1.
- # Scale the pixel coordinates to fit in the range 0 to 2.
- # C. Then translate to fit in the range -1 to 1.
- # D. The WebGL y-axis is inverted compared to what we want.
- # So multiply the y-axis by -1.
-
- # To chain all this into one matrix, we have to apply these into reverse order.
- # The math then looks as follows:
xt = 2 / window.innerWidth
yt = 2 / window.innerHeight
- # D C B A
- # | 1 0 0 0 | | 1 0 0 -1 | | xt 0 0 0 | | 1 0 0 px |
- # T = | 0 -1 0 0 | x | 0 1 0 -1 | x | 0 xy 0 0 | x | 0 1 0 py |
- # | 0 0 1 0 | | 0 0 1 0 | | 0 0 1 0 | | 0 0 1 0 |
- # | 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 |
-
- # To top that off, WebGL expects things in column major order.
- # So the array indices below should be read as being transposed.
-
arr = @transformArray
arr[0] = xt
arr[5] = -yt
@@ -229,8 +235,8 @@ class WebglRenderer extends BaseRenderer
arr[13] = py * -yt + 1
@ctx.uniformMatrix4fv(@uTransform, no, arr)
+ # Apply a translation that centers everything around the given coordinates.
centerOn: (x, y, cb) ->
- # Apply a translation that centers everything around the player.
{width, height} = @canvas[0]
left = round(x / PIXEL_SIZE_WORLD - width / 2)
top = round(y / PIXEL_SIZE_WORLD - height / 2)
@@ -240,8 +246,10 @@ class WebglRenderer extends BaseRenderer
@setTranslation(0, 0)
+ # Helper function that adds a tile to an array that is used to prepare the VBO. It takes care
+ # of calculating texture coordinates based on tile coordinates `tx` and `ty`, and adds entries
+ # for two triangles to the given `buffer` at the given `offset`.
bufferTile: (buffer, offset, tx, ty, styled, sdx, sdy) ->
- # Calculate texture coordinate bounds for the tile.
if styled
stx = tx * @hStyledTileSizeTexture
sty = ty * @vStyledTileSizeTexture
@@ -253,11 +261,9 @@ class WebglRenderer extends BaseRenderer
etx = stx + @hTileSizeTexture
ety = sty + @vTileSizeTexture
- # Calculate pixel coordinate bounds for the destination.
edx = sdx + TILE_SIZE_PIXELS
edy = sdy + TILE_SIZE_PIXELS
- # Update the quad array.
buffer.set([
sdx, sdy, stx, sty,
sdx, edy, stx, ety,
@@ -267,45 +273,35 @@ class WebglRenderer extends BaseRenderer
edx, edy, etx, ety
], offset * (6*4))
+ # Draw a single tile, unstyled.
drawTile: (tx, ty, sdx, sdy) ->
gl = @ctx
-
- # Initialize the uniforms, so the shader knows this is an unstyled tile.
gl.uniform1i(@uUseStyled, 0)
-
- # Update the quad array.
@bufferTile(@vertexArray, 0, tx, ty, no, sdx, sdy)
-
- # Draw.
gl.bufferData(gl.ARRAY_BUFFER, @vertexArray, gl.DYNAMIC_DRAW)
gl.drawArrays(gl.TRIANGLES, 0, 6)
+ # Draw a single tile, styled with a team color.
drawStyledTile: (tx, ty, style, sdx, sdy) ->
gl = @ctx
-
- # Initialize the uniforms, to tell the uniform the style color.
gl.uniform1i(@uUseStyled, 1)
if color = TEAM_COLORS[style]
gl.uniform1i(@uIsStyled, 1)
gl.uniform3f(@uStyleColor, color.r / 255, color.g / 255, color.b / 255)
else
gl.uniform1i(@uIsStyled, 0)
-
- # Update the quad array.
@bufferTile(@vertexArray, 0, tx, ty, yes, sdx, sdy)
-
- # Draw.
gl.bufferData(gl.ARRAY_BUFFER, @vertexArray, gl.DYNAMIC_DRAW)
gl.drawArrays(gl.TRIANGLES, 0, 6)
+ # When a cell is retiled, we simply store the tile index for the upcoming frames.
onRetile: (cell, tx, ty) ->
- # Simply cache the tile index.
cell.tile = [tx, ty]
+ # Draw the map.
drawMap: (sx, sy, w, h) ->
gl = @ctx
- # Calculate pixel boundaries.
ex = sx + w - 1
ey = sy + h - 1
@@ -326,16 +322,14 @@ class WebglRenderer extends BaseRenderer
gl.drawArrays(gl.TRIANGLES, 0, arrayTileIndex * 6)
arrayTileIndex = 0
- # Iterate each tile in view.
+ # Only draw unstyled tiles, but build an index of styled tiles by color.
gl.uniform1i(@uUseStyled, 0)
@sim.map.each (cell) =>
if obj = cell.pill || cell.base
- # Only draw unstyled tiles, but index styled tiles by color.
style = obj.owner?.team
style = 255 unless TEAM_COLORS[style]
(styledCells[style] ||= []).push(cell)
else
- # Add the tile to the vertex buffer.
@bufferTile @vertexArray, arrayTileIndex, cell.tile[0], cell.tile[1], no,
cell.x * TILE_SIZE_PIXELS, cell.y * TILE_SIZE_PIXELS
if ++arrayTileIndex == maxTiles
@@ -360,5 +354,5 @@ class WebglRenderer extends BaseRenderer
flushArray()
-# Exports.
+#### Exports
module.exports = WebglRenderer
2  src/explosion.coffee
View
@@ -38,5 +38,5 @@ class Explosion
WorldObject.register Explosion
-# Exports.
+#### Exports
module.exports = Explosion
10 src/index.coffee
View
@@ -17,7 +17,7 @@ class Simulation
@spawnMapObjects()
- # Basic object management.
+ #### Basic object management.
tick: ->
# Work on a shallow copy of the object list.
@@ -80,7 +80,7 @@ class Simulation
for i in [obj.idx...@objects.length]
@objects[i].idx--
- # Serialization
+ #### Serialization
buildSerializer: (packer) ->
(specifier, value) ->
@@ -97,7 +97,7 @@ class Simulation
when 'T' then @tanks[unpacker('B')]
else unpacker(specifier)
- # Player management.
+ #### Player management.
addTank: (tank) ->
tank.tank_idx = @tanks.length
@@ -108,7 +108,7 @@ class Simulation
@tanks.splice tank.tank_idx, 1
@resolveMapObjectOwners()
- # Map object management.
+ #### Map object management.
getAllMapObjects: -> @map.pills.concat @map.bases
@@ -143,5 +143,5 @@ class Simulation
obj.cell.retile()
return
-# Exports.
+#### Exports
module.exports = Simulation
14 src/map.coffee
View
@@ -30,7 +30,8 @@ createTerrainMap = ->
createTerrainMap()
-# A class to represent a cell on the map.
+#### Cell class
+
class MapCell
constructor: (@map, @x, @y) ->
@type = TERRAIN_TYPES['^']
@@ -354,6 +355,8 @@ class MapCell
else @setTile 11, 6
+#### View class
+
# This is an interface for map views. Map views are responsible for actually displaying the map on
# the screen. This class also functions as the do-nothing dummy implementation. You need not
# inherit from this class, just make sure whatever view object you use responds to the methods
@@ -364,6 +367,8 @@ class MapView
onRetile: (cell, tx, ty) ->
+#### Map objects
+
# The following are interfaces and dummy default implementations of map objects. If a subclass
# of `Map` wishes to use different classes for map objects, it simply needs to define new classes
# with similar constructors and exposing the same attributes.
@@ -378,7 +383,8 @@ class Start
constructor: (map, @x, @y, @direction) ->
-# This class holds a complete map.
+#### Map class
+
class Map
CellClass: MapCell
PillboxClass: Pillbox
@@ -436,6 +442,8 @@ class Map
cell.retile()
, sx, sy, ex, ey
+ #### Saving and loading
+
# Dump the map to an array of octets in BMAP format.
dump: (options) ->
options ||= {}
@@ -638,7 +646,7 @@ class Map
child.load = @load unless child.load
-# Exports.
+#### Exports
exports.TERRAIN_TYPES = TERRAIN_TYPES
exports.MapView = MapView
exports.Map = Map
2  src/net.coffee
View
@@ -55,7 +55,7 @@ inContext = (ctx, cb) ->
retval
-# Exports.
+#### Exports
exports.inContext = inContext
# Delegate the functions used by the simulation to the active context.
10 src/server/index.coffee
View
@@ -23,7 +23,7 @@ class Game
@netctx = new ServerContext(@sim)
@oddTick = no
- # Connection handling.
+ #### Connection handling.
onConnect: (ws) ->
# In order to create the tank object, we need to be in the networking context.
@@ -108,7 +108,7 @@ class Game
client.sendMessage(message) unless client.heartbeatTimer > 20
return
- # Simulation updates.
+ #### Simulation updates.
tick: ->
net.inContext @netctx, => @sim.tick()
@@ -135,6 +135,8 @@ class Game
return
+#### HTTP server application
+
class Application
constructor: ->
@games = []
@@ -180,6 +182,8 @@ class Application
ws.on 'connect', -> handler(ws)
+#### Entry point
+
# Don't export a server directly, but this factory function. Once called, the timer loop will
# start. I believe it's untidy to have timer loops start after a simple require().
createBoloServer = ->
@@ -195,5 +199,5 @@ createBoloServer = ->
server
-# Exports.
+#### Exports
module.exports = createBoloServer
2  src/server/net.coffee
View
@@ -46,5 +46,5 @@ class ServerContext
packer.finish()
-# Exports
+#### Exports
module.exports = ServerContext
2  src/server/websocket.coffee
View
@@ -214,5 +214,5 @@ class WebSocket extends EventEmitter
_onClose: (had_error) -> @emit 'close', had_error
-# Exports
+#### Exports
module.exports = WebSocket
2  src/shell.coffee
View
@@ -115,5 +115,5 @@ class Shell
WorldObject.register Shell
-# Exports.
+#### Exports
module.exports = Shell
10 src/simulation_map.coffee
View
@@ -11,6 +11,8 @@ net = require './net'
WorldObject = require './world_object'
+# Extend `TERRAIN_TYPES` with additional attributes that matter to the simulation.
+
TERRAIN_TYPE_ATTRIBUTES =
'|': { tankSpeed: 0, tankTurn: 0.00, manSpeed: 0 }
' ': { tankSpeed: 3, tankTurn: 0.25, manSpeed: 0 }
@@ -33,6 +35,8 @@ extendTerrainMap = ->
extendTerrainMap()
+#### Cell class
+
class SimMapCell extends Map::CellClass
getTankSpeed: (tank) ->
# Check for a pillbox.
@@ -74,7 +78,7 @@ class SimMapCell extends Map::CellClass
net.mapChanged this, oldType, hadMine
-# Map objects.
+#### Map objects
# These implement the interface of each kind of map object, and also implement WorldObject. The
# latter is so that we may synchronize their state across the network. Drawing is not done like
@@ -165,6 +169,8 @@ class SimBase
WorldObject.register SimBase
+#### Map class
+
class SimMap extends Map
CellClass: SimMapCell
PillboxClass: SimPillbox
@@ -182,5 +188,5 @@ class SimMap extends Map
@starts[round(random() * (@starts.length - 1))]
-# Exports.
+#### Exports
exports.SimulationMap = SimMap
10 src/struct.coffee
View
@@ -9,6 +9,8 @@
# deal with arrays of byte values instead.
+#### Helpers
+
# The following methods pack Fixnums in an array of bytes, in network byte order (MSB).
toUint8 = (n) -> [
@@ -35,6 +37,8 @@ fromUint16 = (d, o) -> (d[o] << 8) + d[o+1]
fromUint32 = (d, o) -> (d[o] << 24) + (d[o+1] << 16) + (d[o+2] << 8) + d[o+3]
+#### Streaming packers
+
# Return a generator function, that is used to generate binary data. Basic usage is as follows:
#
# packer = buildPacker()
@@ -143,7 +147,9 @@ buildUnpacker = (data, offset) ->
retval
-# The following are non-streaming variants, that work more like Python's `struct`.
+#### Non-streaming packers
+
+# These work more like Python's `struct`.
# The `pack` function takes a format string, and the respective values as its arguments. It then
# returns the binary data as an array of byte values.
@@ -162,7 +168,7 @@ unpack = (fmt, data, offset) ->
[values, unpacker.finish()]
-# Exports
+#### Exports
exports.buildPacker = buildPacker
exports.buildUnpacker = buildUnpacker
exports.pack = pack
4 src/tank.coffee
View
@@ -113,7 +113,7 @@ class Tank
# FIXME
- # The following methods all update the simulation.
+ #### Simulation update
update: ->
return if @death()
@@ -288,5 +288,5 @@ class Tank
WorldObject.register Tank
-# Exports.
+#### Exports
module.exports = Tank
2  src/team_colors.coffee
View
@@ -16,5 +16,5 @@ TEAM_COLORS = [
]
-# Exports.
+#### Exports
module.exports = TEAM_COLORS
26 src/world_object.coffee
View
@@ -17,8 +17,6 @@ class WorldObject
# tilemap. May also be `null`, in which case the object is not drawn at all.
styled: null
- # Callbacks. All of the following are optional.
-
# These are properties containing the world coordinates of this object. These are actually
# defined in the constructor. The value `null` for either means that the object is not physical
# or 'not in the world' at this moment (ie. dead tanks).
@@ -35,13 +33,14 @@ class WorldObject
# then proceeds as normal with `postInitialize` and further updates.
constructor: (sim) ->
+ #### Callbacks
+
+ # *The following are optional callbacks.*
+
# Return the (x,y) index in the tilemap (base or styled, selected above) that the object should
# be drawn with. May be a no-op if the object is never actually drawn.
getTile: ->
- # The following are optional callbacks, and thus no-ops by default.
- # It's not hard to implement more, but these are the ones currently used.
-
# Called after the object has been added to the Simulation, either through normal means or
# through the network code.
postInitialize: ->
@@ -61,34 +60,29 @@ class WorldObject
# or simulated on the client.
update: ->
- # The following govern serialization, and are normally not overridden.
-
# This method is called to serialize and deserialize an object's state. The parameter `p`
# is a function which should be repeatedly called for each property of the object. It takes as
- # it's first parameter a format specifier for `struct`, and as it's second parameter the current
- # value of the property. A special format specifier 'O' may be used to (de-)serialize a reference
- # to another WorldObject.
+ # its first parameter a format specifier for `struct`, and as it's second parameter the current
+ # value of the property. A special format specifier `O` may be used to (de-)serialize a reference
+ # to another WorldObject, and `T` may be used for a reference to a Tank.
#
# If the function is called to serialize, then parameters are collected to form a packet, and
# the return value is the same as the value parameter verbatim. If the function is called to
# deserialize, then the value parameter is ignored, and the return value is the received value.
serialization: (isCreate, p) ->
- # Static methods.
+ #### Static methods
# Find a type by character or character code.
@getType: (c) ->
c = String.fromCharCode(c) if typeof(c) != 'string'
types[c]
- # This should be called after a class is defined, as for example `MyObject.register()`.
- # FIXME: Would be neat if this were automagic somehow.
+ # This should be called after a class is defined, as for example `WorldObject.register MyObject`.
@register: (type) ->
- # Add to the index.
types[type::charId] = type
- # Set the character code, which is the network identifier.
type::charCodeId = type::charId.charCodeAt(0)
-# Exports.
+#### Exports
module.exports = WorldObject
Please sign in to comment.
Something went wrong with that request. Please try again.