summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--package.json10
-rw-r--r--require.d.ts5
-rw-r--r--src/app.coffee21
-rw-r--r--src/app.ts26
-rw-r--r--src/control/MapContext.coffee29
-rw-r--r--src/control/MapContext.ts34
-rw-r--r--src/model/Direction.coffee13
-rw-r--r--src/model/Direction.ts13
-rw-r--r--src/model/Entity.coffee8
-rw-r--r--src/model/Entity.ts6
-rw-r--r--src/model/EntityPosition.coffee8
-rw-r--r--src/model/EntityPosition.ts11
-rw-r--r--src/model/MapData.coffee9
-rw-r--r--src/model/MapData.ts20
-rw-r--r--src/model/Position.coffee10
-rw-r--r--src/model/Position.ts10
-rw-r--r--src/util.coffee13
-rw-r--r--src/util.ts13
-rw-r--r--src/view/MapView.coffee108
-rw-r--r--src/view/MapView.ts142
-rw-r--r--tsconfig.json12
-rw-r--r--tsd.json15
-rw-r--r--webpack.config.js6
24 files changed, 315 insertions, 228 deletions
diff --git a/.gitignore b/.gitignore
index 7d5b7a9..156885d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/build
/node_modules
+/typings
diff --git a/package.json b/package.json
index 15fd45b..771f0a0 100644
--- a/package.json
+++ b/package.json
@@ -4,16 +4,14 @@
"start": "webpack-dev-server -d --content-base static",
"build": "webpack"
},
- "devDependencies": {
- "coffee-loader": "^0.7.2",
- "coffee-script": "^1.10.0",
+ "dependencies": {
"css-loader": "^0.23.1",
"html-webpack-plugin": "^1.7.0",
+ "lodash": "^3.10.1",
"style-loader": "^0.13.0",
+ "ts-loader": "^0.7.2",
+ "typescript": "^1.7.5",
"webpack": "^1.12.9",
"webpack-dev-server": "^1.14.0"
- },
- "dependencies": {
- "lodash": "^3.10.1"
}
}
diff --git a/require.d.ts b/require.d.ts
new file mode 100644
index 0000000..6c6222d
--- /dev/null
+++ b/require.d.ts
@@ -0,0 +1,5 @@
+declare var require: {
+ <T>(path: string): T;
+ (paths: string[], callback: (...modules: any[]) => void): void;
+ ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
+};
diff --git a/src/app.coffee b/src/app.coffee
deleted file mode 100644
index ca3ddf8..0000000
--- a/src/app.coffee
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-require './style.css'
-
-window._ = require 'lodash'
-
-MapData = require './model/MapData'
-MapContext = require './control/MapContext'
-
-
-mapContext = null
-
-
-window.onload = ->
- xhr = new XMLHttpRequest()
- xhr.onload = ->
- mapDef = new MapData(JSON.parse this.responseText)
- mapContext = new MapContext mapDef
-
- xhr.open 'GET', 'resources/map/test.json', true
- xhr.send()
diff --git a/src/app.ts b/src/app.ts
new file mode 100644
index 0000000..d1ca3cd
--- /dev/null
+++ b/src/app.ts
@@ -0,0 +1,26 @@
+'use strict';
+
+
+require('./style.css');
+
+
+import * as lodash from 'lodash';
+_ = lodash;
+
+import MapContext from './control/MapContext';
+import MapData from './model/MapData';
+
+
+var mapContext: MapContext;
+
+window.onload = () => {
+ var xhr = new XMLHttpRequest();
+
+ xhr.onload = function() {
+ let mapDef = new MapData(JSON.parse(this.responseText));
+ mapContext = new MapContext(mapDef);
+ }
+
+ xhr.open('GET', 'resources/map/test.json', true);
+ xhr.send();
+};
diff --git a/src/control/MapContext.coffee b/src/control/MapContext.coffee
deleted file mode 100644
index df6efec..0000000
--- a/src/control/MapContext.coffee
+++ /dev/null
@@ -1,29 +0,0 @@
-'use strict'
-
-
-Direction = require '../model/Direction'
-Entity = require '../model/Entity'
-EntityPosition = require '../model/EntityPosition'
-Position = require '../model/Position'
-
-MapView = require '../view/MapView'
-
-
-class MapContext
- constructor: (@map) ->
- @entities = {}
-
- @playerEntity = new EntityPosition(
- new Entity('square'),
- new Position(8, 8),
- Direction.EAST)
-
- @addEntity(@playerEntity)
-
- @mavView = new MapView @map, @entities
-
- addEntity: (entity) =>
- @entities[entity.position.asString()] = entity
-
-
-module.exports = MapContext
diff --git a/src/control/MapContext.ts b/src/control/MapContext.ts
new file mode 100644
index 0000000..4bc75c7
--- /dev/null
+++ b/src/control/MapContext.ts
@@ -0,0 +1,34 @@
+'use strict';
+
+
+import Direction from '../model/Direction';
+import Entity from '../model/Entity';
+import EntityPosition from '../model/EntityPosition';
+import MapData from '../model/MapData';
+import Position from '../model/Position';
+
+import MapView from '../view/MapView';
+
+
+export default class MapContext {
+ view: MapView;
+
+ entities: {[key: string]: EntityPosition} = {};
+ playerEntity: EntityPosition;
+
+ constructor(public map: MapData) {
+ this.playerEntity = new EntityPosition(
+ new Entity('square'),
+ new Position(8, 8),
+ Direction.East
+ );
+
+ this.addEntity(this.playerEntity);
+
+ this.view = new MapView(map, this.entities);
+ }
+
+ addEntity(entity: EntityPosition) {
+ this.entities[entity.position.asString()] = entity;
+ }
+}
diff --git a/src/model/Direction.coffee b/src/model/Direction.coffee
deleted file mode 100644
index 5c49c80..0000000
--- a/src/model/Direction.coffee
+++ /dev/null
@@ -1,13 +0,0 @@
-'use strict'
-
-
-Direction =
- NORTH: 0
- EAST: 1
- SOUTH: 2
- WEST: 3
-
- reverse: (d) -> (d+2)%4
-
-
-module.exports = Direction
diff --git a/src/model/Direction.ts b/src/model/Direction.ts
new file mode 100644
index 0000000..a0cf45d
--- /dev/null
+++ b/src/model/Direction.ts
@@ -0,0 +1,13 @@
+'use strict';
+
+
+export enum Direction {
+ North,
+ East,
+ South,
+ West
+};
+
+export function reverse(r: Direction): Direction { return (r+2) % 4; }
+
+export default Direction;
diff --git a/src/model/Entity.coffee b/src/model/Entity.coffee
deleted file mode 100644
index 70c81fa..0000000
--- a/src/model/Entity.coffee
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict'
-
-
-class Entity
- constructor: (@name) ->
-
-
-module.exports = Entity
diff --git a/src/model/Entity.ts b/src/model/Entity.ts
new file mode 100644
index 0000000..b9a52eb
--- /dev/null
+++ b/src/model/Entity.ts
@@ -0,0 +1,6 @@
+'use strict';
+
+
+export default class Entity {
+ constructor(public name: string) {}
+}
diff --git a/src/model/EntityPosition.coffee b/src/model/EntityPosition.coffee
deleted file mode 100644
index aaf9531..0000000
--- a/src/model/EntityPosition.coffee
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict'
-
-
-class EntityPosition
- constructor: (@entity, @position, @direction) ->
-
-
-module.exports = EntityPosition
diff --git a/src/model/EntityPosition.ts b/src/model/EntityPosition.ts
new file mode 100644
index 0000000..815eceb
--- /dev/null
+++ b/src/model/EntityPosition.ts
@@ -0,0 +1,11 @@
+'use strict';
+
+
+import Direction from '../model/Direction';
+import Entity from './Entity';
+import Position from './Position';
+
+
+export default class EntityPosition {
+ constructor(public entity: Entity, public position: Position, public direction: Direction) {}
+}
diff --git a/src/model/MapData.coffee b/src/model/MapData.coffee
deleted file mode 100644
index 39b2140..0000000
--- a/src/model/MapData.coffee
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict'
-
-
-class MapData
- constructor: (data) ->
- {@tiles, @collition, @layers} = data
-
-
-module.exports = MapData
diff --git a/src/model/MapData.ts b/src/model/MapData.ts
new file mode 100644
index 0000000..54894c0
--- /dev/null
+++ b/src/model/MapData.ts
@@ -0,0 +1,20 @@
+'use strict';
+
+
+interface Input {
+ tiles: {[key: string]: {file: string}};
+ collision: string[];
+ layers: string[][][];
+}
+
+export default class MapData {
+ tiles: {[key: string]: {file: string}};
+ public collision: string[];
+ public layers: string[][][];
+
+ constructor(data: Input) {
+ this.tiles = data.tiles;
+ this.collision = data.collision;
+ this.layers = data.layers;
+ }
+}
diff --git a/src/model/Position.coffee b/src/model/Position.coffee
deleted file mode 100644
index 08bb999..0000000
--- a/src/model/Position.coffee
+++ /dev/null
@@ -1,10 +0,0 @@
-'use strict'
-
-
-class Position
- constructor: (@x, @y) ->
-
- asString: => "#{@x},#{@y}"
-
-
-module.exports = Position
diff --git a/src/model/Position.ts b/src/model/Position.ts
new file mode 100644
index 0000000..1db37af
--- /dev/null
+++ b/src/model/Position.ts
@@ -0,0 +1,10 @@
+'use strict';
+
+
+export default class Position {
+ constructor(public x: number, public y: number) {}
+
+ asString(): string {
+ return `${this.x},${this.y}`;
+ }
+}
diff --git a/src/util.coffee b/src/util.coffee
deleted file mode 100644
index 4e0cd76..0000000
--- a/src/util.coffee
+++ /dev/null
@@ -1,13 +0,0 @@
-'use strict'
-
-
-module.exports =
- mapPromises: (promises) ->
- p = []
- ret = {}
-
- for own k, v of promises
- do (k, v) ->
- p.push(v.then (r) -> ret[k] = r)
-
- Promise.all(p).then -> ret
diff --git a/src/util.ts b/src/util.ts
new file mode 100644
index 0000000..2292820
--- /dev/null
+++ b/src/util.ts
@@ -0,0 +1,13 @@
+'use strict';
+
+
+export function mapPromises<T>(promises: {[key: string]: Promise<T>}): Promise<{[key: string]: T}> {
+ var p: Promise<void>[] = []
+ var ret: {[key: string]: T} = {}
+
+ _.forOwn(promises, (v, k) => {
+ p.push(v.then(r => {ret[k] = r;}));
+ });
+
+ return Promise.all(p).then(() => ret);
+}
diff --git a/src/view/MapView.coffee b/src/view/MapView.coffee
deleted file mode 100644
index e051d48..0000000
--- a/src/view/MapView.coffee
+++ /dev/null
@@ -1,108 +0,0 @@
-'use strict'
-
-util = require '../util'
-
-
-tileSize = 32
-
-body = document.getElementsByTagName('body')[0]
-
-
-loadImage = (url) ->
- new Promise (resolve, reject) ->
- img = new Image()
- img.addEventListener 'load', -> resolve img
- img.addEventListener 'error', -> reject Error('Failed to load ' + url)
- img.src = url
-
-loadImages = (imgs) ->
- util.mapPromises(_.mapValues imgs, loadImage)
-
-loadTiles = (tiles) ->
- loadImages(_.mapValues tiles, (t) -> "resources/sprite/tile/#{t.file}.png")
-
-loadEntities = (entities) ->
- p = {}
- for e in entities
- do (e) ->
- p[e.entity.name] = loadImage "resources/sprite/entity/#{e.entity.name}.png"
-
- util.mapPromises p
-
-
-class MapView
- constructor: (@map, @entities) ->
- @redrawPending = false
-
- @canvas = document.createElement 'canvas'
- @canvas.style.position = 'absolute'
- body.appendChild @canvas
-
- @ctx = @canvas.getContext '2d'
-
- window.addEventListener 'resize', @setSize
- @setSize()
-
- tilesReady = loadTiles(@map.tiles).then (tiles) =>
- @tiles = tiles
-
- entitiesReady = loadEntities(_.values @entities).then (entities) =>
- @entitySprites = entities
-
- tilesReady.then(entitiesReady).then =>
- @redraw()
- return
-
- drawTile: (x, y, tile) =>
- return unless tile
-
- @ctx.drawImage tile, x, y
-
- drawEntity: (e) =>
- sprite = @entitySprites[e.entity.name]
- return unless sprite
-
- @ctx.drawImage(
- sprite,
- e.direction*tileSize, 0,
- tileSize, tileSize,
- e.position.x*tileSize, e.position.y*tileSize,
- tileSize, tileSize)
-
- draw: =>
- @redrawPending = false
-
- @ctx.clearRect 0, 0, @canvas.width, @canvas.height
-
- return unless @tiles and @entitySprites
-
- for layer in @map.layers
- y = 0
-
- for row in layer
- x = 0
-
- for tile in row
- @drawTile x, y, @tiles[tile]
- x += tileSize
-
- y += tileSize
-
- for e in _.values @entities
- @drawEntity e
-
- redraw: =>
- unless @redrawPending
- @redrawPending = true
- window.requestAnimationFrame @draw
-
- setSize: =>
- e = document.documentElement
- @canvas.width = window.innerWidth || e.clientWidth || body.clientWidth
- @canvas.height = window.innerHeight || e.clientHeight || body.clientHeight
-
- @redraw()
-
-
-
-module.exports = MapView
diff --git a/src/view/MapView.ts b/src/view/MapView.ts
new file mode 100644
index 0000000..b366d28
--- /dev/null
+++ b/src/view/MapView.ts
@@ -0,0 +1,142 @@
+'use strict';
+
+
+import * as util from '../util';
+import EntityPosition from '../model/EntityPosition';
+import MapData from '../model/MapData';
+
+
+const tileSize = 32;
+
+const body = document.getElementsByTagName('body')[0];
+
+
+function loadImage(url: string): Promise<HTMLImageElement> {
+ return new Promise(function(resolve, reject) {
+ var img = new Image();
+ img.addEventListener('load', () => { resolve(img); });
+ img.addEventListener('error', () => { reject(Error('Failed to load ' + url)); });
+ img.src = url;
+ });
+}
+
+function loadImages(imgs: {[key: string]: string}): Promise<{[key: string]: HTMLImageElement}> {
+ return util.mapPromises(_.mapValues(imgs, loadImage));
+}
+
+function loadTiles(tiles: {[key: string]: {file: string}}): Promise<{[key: string]: HTMLImageElement}> {
+ return loadImages(_.mapValues(tiles, (t) => `resources/sprite/tile/${t.file}.png`));
+}
+
+function loadEntities(entities: EntityPosition[]): Promise<{[key: string]: HTMLImageElement}> {
+ var p: {[key: string]: Promise<HTMLImageElement>} = {};
+
+ entities.forEach(e => {
+ p[e.entity.name] = loadImage(`resources/sprite/entity/${e.entity.name}.png`);
+ });
+
+ return util.mapPromises(p);
+}
+
+
+export default class MapView {
+ redrawPending: boolean = false;
+
+ canvas: HTMLCanvasElement;
+ ctx: CanvasRenderingContext2D;
+
+ tiles: {[key: string]: HTMLImageElement};
+ entitySprites: {[key: string]: HTMLImageElement};
+
+ constructor(private map: MapData, private entities: {[key: string]: EntityPosition}) {
+ this.canvas = document.createElement('canvas');
+ this.canvas.style.position = 'absolute';
+ body.appendChild(this.canvas);
+
+ this.ctx = this.canvas.getContext('2d');
+
+ window.addEventListener('resize', () => this.setSize());
+ this.setSize();
+
+ var tilesReady = loadTiles(map.tiles).then((tiles) => {
+ this.tiles = tiles;
+ });
+
+ var entitiesReady = loadEntities(this.getEntities()).then((entities) => {
+ this.entitySprites = entities;
+ });
+
+ Promise.all([tilesReady, entitiesReady]).then(() => {
+ this.redraw();
+ });
+ }
+
+ getEntities(): EntityPosition[] {
+ return _.valuesIn<EntityPosition>(this.entities);
+ }
+
+ setSize() {
+ var e = document.documentElement;
+ this.canvas.width = window.innerWidth || e.clientWidth || body.clientWidth;
+ this.canvas.height = window.innerHeight || e.clientHeight || body.clientHeight;
+
+ this.redraw()
+ }
+
+ drawTile(x: number, y: number, tile: HTMLImageElement) {
+ if (!tile)
+ return;
+
+ this.ctx.drawImage(tile, x, y);
+ }
+
+ drawEntity(e: EntityPosition) {
+ var sprite = this.entitySprites[e.entity.name];
+ if (!sprite)
+ return;
+
+ this.ctx.drawImage(
+ sprite,
+ e.direction*tileSize, 0,
+ tileSize, tileSize,
+ e.position.x*tileSize, e.position.y*tileSize,
+ tileSize, tileSize
+ );
+ }
+
+ draw() {
+ this.redrawPending = false;
+
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ if (!this.tiles || !this.entitySprites)
+ return;
+
+ this.map.layers.forEach((layer) => {
+ let y = 0;
+
+ layer.forEach((row) => {
+ let x = 0;
+
+ for (let tile in row) {
+ this.drawTile(x, y, this.tiles[row[tile]]);
+ x += tileSize;
+ }
+
+ y += tileSize;
+ });
+ });
+
+ this.getEntities().forEach(e => {
+ this.drawEntity(e);
+ });
+ }
+
+ redraw() {
+ if (this.redrawPending)
+ return;
+
+ this.redrawPending = true;
+ window.requestAnimationFrame(() => this.draw());
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..1aef94c
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "target": "es5",
+ "noImplicitAny": true,
+ "sourceMap": true
+ },
+ "files": [
+ "require.d.ts",
+ "typings/tsd.d.ts"
+ ]
+}
diff --git a/tsd.json b/tsd.json
new file mode 100644
index 0000000..854a888
--- /dev/null
+++ b/tsd.json
@@ -0,0 +1,15 @@
+{
+ "version": "v4",
+ "repo": "borisyankov/DefinitelyTyped",
+ "ref": "master",
+ "path": "typings",
+ "bundle": "typings/tsd.d.ts",
+ "installed": {
+ "lodash/lodash.d.ts": {
+ "commit": "f11e49cfb77f99678657ddfe5d43017849675c64"
+ },
+ "es6-promise/es6-promise.d.ts": {
+ "commit": "f11e49cfb77f99678657ddfe5d43017849675c64"
+ }
+ }
+}
diff --git a/webpack.config.js b/webpack.config.js
index d069bb6..1979538 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,7 +1,7 @@
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
- entry: './src/app.coffee',
+ entry: './src/app.ts',
output: {
path: './build',
filename: 'bundle.js'
@@ -14,10 +14,10 @@ module.exports = {
module: {
loaders: [
{ test: /\.css$/, loader: 'style-loader!css-loader' },
- { test: /\.coffee$/, loader: 'coffee-loader' }
+ { test: /\.ts$/, loader: 'ts-loader' }
]
},
resolve: {
- extensions: ['', '.js', '.json', '.coffee']
+ extensions: ['', '.ts']
}
};