renderer for rhombic maps
[isotilejs] / rhombic.html
1 <!DOCTYPE XHTML>
2 <html><head>
3   <title>Tilerender</title>
4   <meta charset="utf8">
5 </head><body onload="script()" style="width: 100%; max-height: 600px; overflow: hidden; padding: 0 auto;" >
6   <canvas id="view" width="1280" height="600" style="padding: 0 auto; max-height: 600px;">
7     Canvas not supported<br/>
8     <img id="maptiles" src="tileset.png" width="64" style="overflow: hidden;"  />
9     <tiles>
10       <tile position="0" name="air" fluid="1"></tile>
11       <tile position="1" name="cursor" animated=".125"></tile>
12       <tile position="2" name="grass" animated=".0625"></tile>
13       <tile position="3" name="parquet" elevation=".125"></tile>
14       <tile position="4" name="sand"></tile>
15       <tile position="5" name="dirt" blocking="1"></tile>
16       <tile position="6" name="brick" blocking="1"></tile>
17       <tile position="7" name="water" animated="1" fluid=".5"></tile>
18     </tiles>
19     <img id="character" src="character.png" speed="4"/>
20     <div id="map" columns="32" rows="32">
21       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
22       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
23       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
24       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
25       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
26       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
27       6, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
28       4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
29       6, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
30       4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
31       6, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
32       4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
33       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
34       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
35       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
36       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
37       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
38       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
39       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
40       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
41       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
42       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
43       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
44       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
45       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
46       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
47       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
48       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
49       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
50       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
51       6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 
52       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
53
54       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 
55       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 
56       2, 2, 2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
57       2, 2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
58       2, 2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
59       2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
60       2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
61       7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
62       7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
63       7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
64       7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
65       7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
66       7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
67       2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 6, 3, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
68       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
69       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
70       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 6, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
71       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
72       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
73       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
74       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
75       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
76       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
77       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
78       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
79       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
80       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
81       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
82       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
83       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
84       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
85       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
86     </div>
87   </canvas>
88 </body><script>
89 var gravity = 9.81, fps = 30;
90 view = document.getElementById("view");
91 canvas = document.getElementById("view").getContext("2d");
92
93 map = {
94   rows: document.getElementById("map").getAttribute("rows") * 1 || 1,
95   cols: document.getElementById("map").getAttribute("columns") * 1 || 1,
96   data: document.getElementById("map").textContent.split(',') || [],
97   tiles: document.getElementById("maptiles"),
98
99   default_props: {animated: false, elevation: 0, blocking: false, fluid: false},
100   tileprops: [],
101   tw: 32, th: 16, sw: 16, sh: 8,
102   offset_x: 0, offset_y: 0,
103
104   init: function(){
105     this.tw = this.tiles.getAttribute("width") * 1 || 32;
106     this.th = this.tiles.getAttribute("height") * 1 || this.tw / 2;
107     this.sw = this.tw / 2;
108     this.sh = this.th / 2;
109
110     this.gravity = gravity / fps / Math.sqrt(this.sw * this.sw + this.sh * this.sh) * this.sh;
111
112     var prop, i;
113
114     for (i in this.data) this.data[i] = this.data[i] * 1 || 0; // make numeric
115
116     for (prop of document.querySelectorAll("tiles > tile")) {
117       i = prop.getAttribute("position") * 1;
118       if (i || i == 0) this.tileprops[i] = {
119         animated:  prop.getAttribute("animated")      || this.default_props.animated,
120         elevation: prop.getAttribute("elevation") * 1 || this.default_props.elevation,
121         blocking:  prop.getAttribute("blocking")      || this.default_props.blocking,
122         fluid:     prop.getAttribute("fluid")         || this.default_props.fluid
123       }
124       if (!this.tileprops[0]) this.tileprops[0] = { animated: false, elevation: 0, blocking: false, fluid: 1 }
125     }
126   },
127
128   props_of: function(n) { return this.tileprops[this.data[n]] || this.tileprops[0]; },
129
130   tile_at: function(x, y, z) {
131     nx = (y - 48) / 32 + (x) / 64 |0;
132     ny = (y - 48) / 32 - (x) / 64 |0;
133
134     return ny * this.cols + nx + (z|0) * this.rows * this.cols;
135   },
136
137   /*
138   tile_at: function(x, y, z) {
139     var my = (y / this.sh |0);
140     var mx = (x / this.sw |0);
141     
142     switch(((my % 2) << 1) + mx % 2) {
143       case 0: my += o = (y % this.sh * 2 > this.sw - x % this.sw);              break;
144       case 1: my += o = (y % this.sh * 2 >           x % this.sw); mx -= o;     break;
145       case 2: my += o = (y % this.sh * 2 >           x % this.sw);              break;
146       case 3: my += o = (y % this.sh * 2 > this.sw - x % this.sw); mx += o - 1; break;
147     }
148     mx -= x / this.tw |0;
149   
150     return this.cols * my + mx + (z |0) * this.rows * this.cols;
151   },
152   */
153
154   draw: function(){
155     var px = player.n % this.cols;
156     var x, y, z = 0, n, tile, props;
157
158     for ( y = 0; y < this.cols * 2; ++y) {
159       xw = (y < this.cols) ? y : this.cols * 2 - y;
160       for (z = 0; z < this.data.length / (this.rows * this.cols); ++z)
161       for ( x = 0; x < xw; ++x) {
162         n = (y <= this.cols) ? x + (y - x) * map.cols : (this.rows - x) * this.cols + (y - this.cols) + x;
163         n = n - this.cols + z * this.cols * this.rows;
164         tile = ( n == ptr ) ? 1 : this.data[n];
165         props = this.tileprops[tile] || this.default_props;
166
167         canvas.drawImage( this.tiles,
168                           this.tw * tile, 2 * this.th * ((props.animated * frame |0) % 8),
169                           this.tw, 2 * this.th,
170                            - xw * this.sw + x * this.tw - this.offset_x,
171                           y * this.sh - this.offset_y - z * this.th,
172                           this.tw, 2 * this.th
173                         );
174         if (player.n == n) player.draw();
175       }
176     }
177   }
178 /*
179   draw: function(){ // map.draw
180     var py = player.n / this.cols % this.rows |0;
181     var px = player.n % this.cols;
182     var x, y, z, n, tile, props;
183
184     for (y = 0; y < this.rows; ++y) {
185       for (z = 0; z < this.data.length / (this.rows * this.cols); ++z)
186       for (x = 0; x < this.cols; ++x) {
187         n = x + y * map.cols + z * map.rows * map.cols;
188         tile = ( n == ptr ) ? 1 : this.data[n];
189         props = this.tileprops[tile] || this.default_props;
190
191         canvas.globalAlpha = ( y > py &&
192                                (z > player.z + 1 || z == (player.z |0) && props.blocking) &&
193                                y < py + 6 &&
194                                x > px - 2 &&
195                                x < px + 2 &&
196                                !props.fluid
197                              ) ? .25 : 1;
198   
199         canvas.drawImage( this.tiles,
200                           this.tw * tile, 2 * this.th * ((props.animated * frame |0) % 8),
201                           this.tw, 2 * this.th,
202                           x * this.tw + y % 2 * this.sw - this.sw - this.offset_x,
203                           y * this.sh - z * this.th - 3 * this.sh - this.offset_y,
204                           this.tw, 2 * this.th
205                         );
206       }
207     }
208     player.draw();
209   } // end map.draw
210 */
211 } // end map
212
213 player = {
214   frame: 0, d: 's',
215   x: 0, y: 17, z: 4,
216   sprite: document.getElementById("character"),
217
218   init: function(){
219     this.w = this.sprite.getAttribute("width")  * 1 || map.tw || 32;
220     this.h = this.sprite.getAttribute("height") * 1 || map.sh * 6 || this.w * 1.5;
221     this.o = this.sprite.getAttribute("offset") * 1 || map.sh || this.w / 4;
222     this.ospeed = this.speed = this.sprite.getAttribute("speed") * 1|| this.w / 16;
223     this.n = map.tile_at(this.x, this.y, this.z);
224     map.offset_x = this.x - view.clientWidth / 2 |0;
225     map.offset_y = this.y - view.clientHeight / 2 |0;
226   },
227
228   move: function(){ // player.move
229     var dx = 0, dy = 0;
230   
231     switch(this.d){
232       case  'n': dy = -this.speed; break;
233       case  's': dy =  this.speed; break;
234       case  'w': dx = -this.speed; break;
235       case  'e': dx =  this.speed; break;
236       case 'nw': dy = -.45 * this.speed; dx = -.9 * this.speed; break;
237       case 'ne': dy = -.45 * this.speed; dx =  .9 * this.speed; break;
238       case 'sw': dy =  .45 * this.speed; dx = -.9 * this.speed; break;
239       case 'se': dy =  .45 * this.speed; dx =  .9 * this.speed; break;
240     }
241
242     if (player.frame % 6 > 2) { dx *= 1.375; dy *= 1.375; }
243     else { dx *= .625; dy *= .625; }
244   
245     var n = map.tile_at(this.x + dx, this.y + dy, this.z);
246     var prop = map.props_of(n), head = map.props_of(n + map.rows * map.cols);
247
248     if      (prop.fluid) { dx *= prop.fluid; dy *= prop.fluid; }
249     else if (head.fluid) { dx *= head.fluid; dy *= head.fluid; }
250
251     if (!prop.blocking && head.fluid) { 
252       this.x += dx; this.y += dy; this.n = n;
253     }
254
255     this.frame += this.frame < 255 ? 1 : -127;
256
257     map.offset_x = this.x - view.clientWidth / 2 |0;
258     map.offset_y = this.y - view.clientHeight / 2 |0;
259   }, // end player.move
260
261   zspeed: 0,
262   fall: function(){
263     var props = map.props_of(this.n);
264     var bottom = map.props_of(this.n - map.rows * map.cols);
265     var zbase = (this.n / (map.rows * map.cols) |0) + props.elevation;
266
267     this.z += this.zspeed -= map.gravity;
268
269     if (this.z > zbase) {
270       this.speed = this.ospeed * 2;
271     } else if (props.fluid && !bottom.blocking) {
272       this.n -= map.rows * map.cols;
273     } else {
274       this.speed = this.ospeed;
275       this.zspeed = 0;
276       this.z = zbase;
277     }
278
279   }, // end player.fall
280
281
282   draw: function(){ // player.draw
283     var face = 0, state = 0;
284   
285     switch (this.d){
286       case  's': face = 0; break;
287       case 'sw': face = 1; break;
288       case  'w': face = 2; break;
289       case 'nw': face = 3; break;
290       case  'n': face = 4; break;
291       case 'ne': face = 5; break;
292       case  'e': face = 6; break;
293       case 'se': face = 7; break;
294     }
295   
296     state = 
297       (this.frame > 11) ? frame / 16 % 2 |0 :
298       (this.frame < 12) ? this.frame / 3 + 2 |0 :
299       0;
300   
301     canvas.drawImage( this.sprite, this.w * face, this.h * state,
302                       this.w, this.h,
303                       this.x - this.w / 2 - map.offset_x,
304                       this.y - this.h + this.o - map.offset_y - this.z * map.th,
305                       this.w, this.h );
306    
307   } // end player.draw
308 };
309
310 frame = 0;
311 move = true;
312 keys = [];
313 ptr = 0;
314
315 function get_input(){
316   d = '';
317   if ( keys[87] || keys[38] ) d  = 'n';
318   if ( keys[83] || keys[40] ) d  = 's';
319   if ( keys[65] || keys[37] ) d += 'w';
320   if ( keys[68] || keys[39] ) d += 'e';
321
322   if ( d == '' ) player.frame = 12
323   else {
324     player.d = d;
325     if ( player.frame > 11 ) player.frame = 0;
326     player.move();
327   }
328
329   // jump
330   if (keys[32] && player.zspeed == 0) {player.zspeed += .75; player.z +=.0001;}
331 }
332
333 function script(){
334   map.init();
335   player.init();
336
337   setInterval(function(){
338     get_input();
339     player.fall();
340     map.draw();
341     frame += frame < 255 ? 1 : -255;
342   }, 1000 / fps);
343
344   window.addEventListener('keydown', function(x){ keys[x.keyCode] = true; }, false );
345   window.addEventListener('keyup',   function(x){ keys[x.keyCode] = false;}, false );
346
347   window.addEventListener('mousemove', function(e){
348     px = view.width  * (e.clientX - view.offsetLeft) / view.clientWidth |0;
349     py = view.height * (e.clientY - view.offsetTop) / view.clientHeight |0;
350
351     ptr = map.tile_at(px + map.offset_x, py + map.offset_y, 0);
352   })
353 }
354 </script></html>