renderer for rhombic maps
[isotilejs] / index.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       6, 6, 6, 6, 4, 4, 4, 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, 
22        6, 6, 6, 4, 4, 4, 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, 
23       5, 5, 5, 4, 4, 4, 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, 
24        5, 5, 4, 4, 4, 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, 
25       5, 5, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
26        5, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
27       5, 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       4, 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       4, 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       4, 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       5, 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       5, 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       5, 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       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, 
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       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, 
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       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, 
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       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, 
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       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, 
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       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, 
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     var my = (y / this.sh |0);
132     var mx = (x / this.sw |0);
133     
134     switch(((my % 2) << 1) + mx % 2) {
135       case 0: my += o = (y % this.sh * 2 > this.sw - x % this.sw);              break;
136       case 1: my += o = (y % this.sh * 2 >           x % this.sw); mx -= o;     break;
137       case 2: my += o = (y % this.sh * 2 >           x % this.sw);              break;
138       case 3: my += o = (y % this.sh * 2 > this.sw - x % this.sw); mx += o - 1; break;
139     }
140     mx -= x / this.tw |0;
141   
142     return this.cols * my + mx + (z |0) * this.rows * this.cols;
143   },
144
145   draw: function(){ // map.draw
146     var py = player.n / this.cols % this.rows |0;
147     var px = player.n % this.cols;
148     var x, y, z, n, tile, props;
149
150     for (y = 0; y < this.rows; ++y) {
151       for (z = 0; z < this.data.length / (this.rows * this.cols); ++z)
152       for (x = 0; x < this.cols; ++x) {
153         n = x + y * map.cols + z * map.rows * map.cols;
154         tile = ( n == ptr ) ? 1 : this.data[n];
155         props = this.tileprops[tile] || this.default_props;
156
157         canvas.globalAlpha = ( y > py &&
158                                (z > player.z + 1 || z == (player.z |0) && props.blocking) &&
159                                y < py + 6 &&
160                                x > px - 2 &&
161                                x < px + 2 &&
162                                !props.fluid
163                              ) ? .25 : 1;
164   
165         canvas.drawImage( this.tiles,
166                           this.tw * tile, 2 * this.th * ((props.animated * frame |0) % 8),
167                           this.tw, 2 * this.th,
168                           x * this.tw + y % 2 * this.sw - this.sw - this.offset_x,
169                           y * this.sh - z * this.th - 3 * this.sh - this.offset_y,
170                           this.tw, 2 * this.th
171                         );
172       }
173       if (py == y) player.draw();
174     }
175   } // end map.draw
176 } // end map
177
178 player = {
179   frame: 0, d: 's',
180   x: 40, y: 40, z: 1,
181   sprite: document.getElementById("character"),
182
183   init: function(){
184     this.w = this.sprite.getAttribute("width")  * 1 || map.tw || 32;
185     this.h = this.sprite.getAttribute("height") * 1 || map.sh * 6 || this.w * 1.5;
186     this.o = this.sprite.getAttribute("offset") * 1 || map.sh || this.w / 4;
187     this.ospeed = this.speed = this.sprite.getAttribute("speed") * 1|| this.w / 16;
188     this.n = map.tile_at(this.x, this.y, this.z);
189     map.offset_x = this.x - view.clientWidth / 2 |0;
190     map.offset_y = this.y - view.clientHeight / 2 |0;
191   },
192
193   move: function(){ // player.move
194     var dx = 0, dy = 0;
195   
196     switch(this.d){
197       case  'n': dy = -this.speed; break;
198       case  's': dy =  this.speed; break;
199       case  'w': dx = -this.speed; break;
200       case  'e': dx =  this.speed; break;
201       case 'nw': dy = -.45 * this.speed; dx = -.9 * this.speed; break;
202       case 'ne': dy = -.45 * this.speed; dx =  .9 * this.speed; break;
203       case 'sw': dy =  .45 * this.speed; dx = -.9 * this.speed; break;
204       case 'se': dy =  .45 * this.speed; dx =  .9 * this.speed; break;
205     }
206
207     if (player.frame % 6 > 2) { dx *= 1.375; dy *= 1.375; }
208     else { dx *= .625; dy *= .625; }
209   
210     var n = map.tile_at(this.x + dx, this.y + dy, this.z);
211     var prop = map.props_of(n), head = map.props_of(n + map.rows * map.cols);
212
213     if      (prop.fluid) { dx *= prop.fluid; dy *= prop.fluid; }
214     else if (head.fluid) { dx *= head.fluid; dy *= head.fluid; }
215
216     if (!prop.blocking && head.fluid) { 
217       this.x += dx; this.y += dy; this.n = n;
218     }
219
220     this.frame += this.frame < 255 ? 1 : -127;
221
222     map.offset_x = this.x - view.clientWidth / 2 |0;
223     map.offset_y = this.y - view.clientHeight / 2 |0;
224   }, // end player.move
225
226   zspeed: 0,
227   fall: function(){
228     var props = map.props_of(this.n);
229     var bottom = map.props_of(this.n - map.rows * map.cols);
230     var zbase = (this.n / (map.rows * map.cols) |0) + props.elevation;
231
232     this.z += this.zspeed -= map.gravity;
233
234     if (this.z > zbase) {
235       this.speed = this.ospeed * 2;
236     } else if (props.fluid && !bottom.blocking) {
237       this.n -= map.rows * map.cols;
238     } else {
239       this.speed = this.ospeed;
240       this.zspeed = 0;
241       this.z = zbase;
242     }
243
244   }, // end player.fall
245
246
247   draw: function(){ // player.draw
248     var face = 0, state = 0;
249   
250     switch (this.d){
251       case  's': face = 0; break;
252       case 'sw': face = 1; break;
253       case  'w': face = 2; break;
254       case 'nw': face = 3; break;
255       case  'n': face = 4; break;
256       case 'ne': face = 5; break;
257       case  'e': face = 6; break;
258       case 'se': face = 7; break;
259     }
260   
261     state = 
262       (this.frame > 11) ? frame / 16 % 2 |0 :
263       (this.frame < 12) ? this.frame / 3 + 2 |0 :
264       0;
265   
266     canvas.drawImage( this.sprite, this.w * face, this.h * state,
267                       this.w, this.h,
268                       this.x - this.w / 2 - map.offset_x,
269                       this.y - this.z * map.th - this.h + this.o - map.offset_y,
270                       this.w, this.h );
271    
272   } // end player.draw
273 };
274
275 frame = 0;
276 move = true;
277 keys = [];
278 ptr = 0;
279
280 function get_input(){
281   d = '';
282   if ( keys[87] || keys[38] ) d  = 'n';
283   if ( keys[83] || keys[40] ) d  = 's';
284   if ( keys[65] || keys[37] ) d += 'w';
285   if ( keys[68] || keys[39] ) d += 'e';
286
287   if ( d == '' ) player.frame = 12
288   else {
289     player.d = d;
290     if ( player.frame > 11 ) player.frame = 0;
291     player.move();
292   }
293
294   // jump
295   if (keys[32] && player.zspeed == 0) {player.zspeed += .75; player.z +=.0001;}
296 }
297
298 function script(){
299   map.init();
300   player.init();
301
302   setInterval(function(){
303     get_input();
304     player.fall();
305     map.draw();
306     frame += frame < 255 ? 1 : -255;
307   }, 1000 / fps);
308
309   window.addEventListener('keydown', function(x){ keys[x.keyCode] = true; }, false );
310   window.addEventListener('keyup',   function(x){ keys[x.keyCode] = false;}, false );
311
312   window.addEventListener('mousemove', function(e){
313     px = view.width  * (e.clientX - view.offsetLeft) / view.clientWidth |0;
314     py = view.height * (e.clientY - view.offsetTop) / view.clientHeight |0;
315
316     ptr = map.tile_at(px + map.offset_x, py + map.offset_y, 0);
317   })
318 }
319 </script></html>