├── .gitattributes
├── .gitignore
├── flappyBox.zip
├── index.html
└── index.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # =========================
18 | # Operating System Files
19 | # =========================
20 |
21 | # OSX
22 | # =========================
23 |
24 | .DS_Store
25 | .AppleDouble
26 | .LSOverride
27 |
28 | # Icon must end with two \r
29 | Icon
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear on external disk
35 | .Spotlight-V100
36 | .Trashes
37 |
38 | # Directories potentially created on remote AFP share
39 | .AppleDB
40 | .AppleDesktop
41 | Network Trash Folder
42 | Temporary Items
43 | .apdisk
44 |
--------------------------------------------------------------------------------
/flappyBox.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/towc/flappyBox/d0b618dde768e055f68698dca8071e4c49d3dd0b/flappyBox.zip
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | flappyBox by towc
5 |
6 |
7 |
50 |
51 |
52 |
53 | Please don't use landscape mode
54 |
55 |
56 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var game = {};
2 |
3 | game.init = function(){
4 |
5 | // unchanging variables
6 |
7 | game.player = {};
8 | game.screen = {};
9 | game.controls = {};
10 | game.logics = {};
11 | game.time = {};
12 |
13 | game.controls.interactKey = 32; //space
14 |
15 | game.screen.canvas = document.getElementById( 'c' );
16 | game.screen.ctx = game.screen.canvas.getContext( '2d' );
17 |
18 | var w = 320,
19 | h = 480,
20 |
21 | ww = window.innerWidth,
22 | wh = window.innerHeight,
23 |
24 | i = 1;
25 |
26 | //while( w * i <= ww && h * i <= wh ) ++i;
27 |
28 | game.screen.canvas.width = game.logics.width = game.screen.width = w * i;
29 | game.screen.canvas.height = game.logics.height = game.screen.height = h * i;
30 | game.screen.halfw = game.logics.halfw = game.screen.width / 2;
31 | game.screen.halfh = game.screen.height / 2;
32 |
33 | game.screen.colors = [ '#fff', '#000', '#f80808', 'rgba(120,120,120,.6)', '#eee' ];
34 | game.screen.fonts = [ '40px Verdana', '30px Verdana', '20px Verdana', '35px Verdana' ];
35 | game.screen.texts = [ 'jumps', 'Squashed at ', 'spacebar or touch to begin', 'highscore of ' ];
36 |
37 | game.screen.lengths = [];
38 |
39 | game.screen.ctx.font = game.screen.fonts[ 2 ];
40 | game.screen.lengths[ 0 ] = game.screen.ctx.measureText( game.screen.texts[ 0 ] ).width;
41 |
42 | game.screen.ctx.font = game.screen.fonts[ 2 ];
43 | game.screen.lengths[ 1 ] = game.screen.ctx.measureText( game.screen.texts[ 2 ] ).width;
44 |
45 | game.screen.midBezierPassingMultiplier = 2;
46 | game.screen.midBezierFriction = .8;
47 | game.screen.midBezierAccMultiplier = .1;
48 | game.screen.barSizeVel = .02;
49 |
50 | game.screen.pillarHeight = 6;
51 |
52 | game.logics.gravity = .3;
53 | game.logics.friction = .9;
54 | game.logics.pillars = [];
55 |
56 | game.logics.basePillarWidth = 35;
57 | game.logics.addedPillarWidth = 50;
58 | game.logics.basePillarWait = 90;
59 | game.logics.addedPillarWait = 30;
60 | game.logics.lastPillarInitialWaitDecrementer = 2;
61 |
62 | game.logics.playerThresholdVel = 6;
63 | game.logics.playerIncrementMultiplier = 1.01;
64 | game.logics.playerDecrementMultiplier = .992;
65 |
66 | game.logics.playerThresholdJumpVel = 2;
67 |
68 | game.time.updateMS = 16;
69 |
70 | game.reset(); // changing variables
71 |
72 | game.controls.menuing = true;
73 |
74 | // constants so that I don't have to calculate some stuff every time
75 | game.constants = [
76 | -game.player.size / 2,
77 | game.screen.halfw * 1.5 - game.screen.lengths[ 0 ] / 2,
78 | game.screen.height - 30,
79 | game.screen.halfw * 1.5 - game.screen.lengths[ 0 ] / 2 - 6,
80 | game.screen.height - 48,
81 | game.screen.lengths[ 0 ] + 10,
82 | game.screen.halfw - game.screen.lengths[ 1 ] / 2 ]
83 |
84 | game.anim(); // start
85 |
86 | //event listeners
87 |
88 | game.controls.interact = function(){
89 |
90 | if( game.controls.menuing )
91 | game.controls.menuing = false;
92 |
93 | if( game.player.dead ){
94 | game.reset();
95 | game.anim();
96 | } else if( game.controls.canInteract ) game.controls.interacted = true;
97 | }
98 |
99 | window.addEventListener( 'keydown', function( e ){
100 |
101 | if( e.keyCode === game.controls.interactKey )
102 | game.controls.interact();
103 | } );
104 | window.addEventListener( 'touchstart', game.controls.interact );
105 |
106 | if( !localStorage.game_highScore )
107 | localStorage.game_highScore = 0;
108 | }
109 | game.reset = function(){
110 |
111 | game.controls.canInteract = true;
112 | game.controls.interacted = false;
113 | game.controls.lastInteraction = 0;
114 | game.controls.menuing = false;
115 |
116 | game.player.dead = false;
117 |
118 | game.player.x = game.logics.halfw * 3 / 2;
119 | game.player.y = game.logics.height - 100;
120 | game.player.vx = 0;
121 | game.player.vy = -3;
122 | game.player.ax = 0;
123 | game.player.ay = -.0005;
124 |
125 | game.player.size = 18;
126 | game.player.side = 1;
127 | game.player.rotation = 0;
128 |
129 | game.player.usedJumps = 0;
130 | game.player.maxJumps = 5;
131 |
132 | game.logics.pillars.length = 0;
133 | game.logics.lastPillar = 300;
134 | game.logics.lastPillarSide = 1;
135 | game.logics.lastPillarInitialWait = 60;
136 |
137 | game.screen.midBezier = 0;
138 | game.screen.midBezierVel = 0;
139 |
140 | game.screen.barSize = 1;
141 |
142 | game.logics.score = 0;
143 |
144 | game.time.now = Date.now();
145 | game.time.leftOverMS = 0;
146 | }
147 | game.anim = function(){
148 |
149 | if( !game.player.dead ) window.requestAnimationFrame( game.anim );
150 | else return game.over();
151 |
152 | var now = Date.now(),
153 | elapsed = game.time.leftOverMS + ( now - game.time.now );
154 |
155 | if( elapsed > 50 )
156 | elapsed = 0;
157 |
158 | while( elapsed > game.time.updateMS && !game.player.dead ){
159 |
160 | game.updatePlayer();
161 | if( !game.controls.menuing ) game.updatePillars();
162 |
163 | elapsed -= game.time.updateMS;
164 | }
165 |
166 | if( game.player.dead )
167 | return game.over();
168 |
169 | game.time.leftOverMS = elapsed;
170 | game.time.now = now;
171 |
172 | game.drawBackground();
173 | game.drawPillars();
174 | game.drawPlayer();
175 | game.drawTexts();
176 | }
177 |
178 | game.over = function(){
179 |
180 | var ctx = game.screen.ctx;
181 |
182 | ctx.globalCompositeOperation = 'source-over';
183 |
184 | ctx.fillStyle = game.screen.colors[ 3 ];
185 | ctx.fillRect( 0, 0, game.screen.width, game.screen.height );
186 |
187 | ctx.fillStyle = game.screen.colors[ 4 ];
188 | ctx.font = game.screen.fonts[ 3 ];
189 | var text = game.screen.texts[ 1 ].replace( '', game.logics.score );
190 | ctx.fillText( text, game.screen.halfw - ctx.measureText( text ).width / 2, game.screen.halfh - 20 );
191 |
192 | var highscore = +localStorage.game_highScore;
193 | if( game.logics.score > highscore )
194 | localStorage.game_highScore = game.logics.score;
195 |
196 | ctx.font = game.screen.fonts[ 2 ];
197 | text = game.screen.texts[ 3 ].replace( '', localStorage.game_highScore );
198 | ctx.fillText( text, game.screen.halfw - ctx.measureText( text ).width / 2, game.screen.halfh + 20 );
199 | }
200 | game.updatePlayer = function(){
201 |
202 | var player = game.player;
203 |
204 | var didntWarp = false;
205 |
206 | if( player.x < -player.size ){
207 | player.x += game.logics.width + player.size;
208 | player.vx *= .8;
209 | } else if( player.x > game.logics.width + player.size ){
210 | player.x -= game.logics.width + player.size;
211 | player.vx *= .8;
212 | } else didntWarp = true;
213 |
214 | var newSide = player.x < game.logics.halfw ? 1 : -1;
215 |
216 | if( newSide !== player.side && didntWarp ){
217 |
218 | player.ax = 0;
219 | player.usedJumps = 0;
220 |
221 | game.screen.midBezierVel = player.vx * game.screen.midBezierPassingMultiplier;
222 | game.screen.midBezier = 0;
223 | }
224 |
225 | player.side = newSide;
226 |
227 | if( Math.abs( player.vx ) > game.logics.playerThresholdVel ) player.vx *= game.logics.playerDecrementMultiplier;
228 | else player.vx *= game.logics.playerIncrementMultiplier; // keep it constantish
229 |
230 | if( !game.controls.menuing ) player.vy += player.ay;
231 |
232 | player.x += player.vx += game.logics.gravity * player.side + ( player.ax *= game.logics.friction );
233 | player.rotation = Math.atan( player.vy / player.vx ); // it's symmetric so...
234 |
235 | if( --game.controls.lastInteraction && game.controls.interacted && player.usedJumps < player.maxJumps ){
236 |
237 | game.controls.lastInteraction = 10;
238 | game.controls.interacted = false;
239 |
240 | ++player.usedJumps;
241 |
242 | player.ax = -player.side / 3;
243 | player.vx -= player.side * 2;
244 | if( Math.sign( player.vx ) === player.side || Math.abs( player.vx ) < game.logics.playerThresholdJumpVel )
245 | player.vx = -player.side * 2;
246 |
247 | }
248 | }
249 | game.updatePillars = function(){
250 |
251 | var player = game.player;
252 |
253 | game.logics.lastPillar += player.vy;
254 |
255 | if( game.logics.lastPillar <= 0 ){
256 |
257 | var num = 0;
258 |
259 | do {
260 | if( Math.random() < .7 ) game.logics.lastPillarSide *= -1;
261 |
262 | var x = game.logics.halfw + ( Math.random() * ( game.logics.halfw ) * game.logics.lastPillarSide ) |0,
263 | width = ( game.logics.basePillarWidth + game.logics.addedPillarWidth * Math.random() / ( num + 1 ) ) |0,
264 | found = -1;
265 |
266 | for( var i = 0; i < game.logics.pillars.length; ++i )
267 | if( game.logics.pillars[ i ].dead )
268 | found = i;
269 |
270 | var pillar = found > -1 ? game.logics.pillars[ found ] : {};
271 | pillar.x = x;
272 | pillar.y = 0;
273 | pillar.warping = x + width > game.logics.width;
274 |
275 | if( pillar.warping ){
276 |
277 | pillar.w = game.logics.width - x;
278 | pillar.warpLeft = width - pillar.w;
279 | } else pillar.w = width;
280 |
281 | pillar.dead = false;
282 |
283 | if( found === -1 )
284 | game.logics.pillars.push( pillar );
285 |
286 | // just a smoothener so mplethat it's easier in the beginning
287 | if( game.logics.lastPillarInitialWait > 0 )
288 | game.logics.lastPillarInitialWait -= game.logics.lastPillarInitialWaitDecrementer;
289 | game.logics.lastPillar = game.logics.lastPillarInitialWait + ( game.logics.basePillarWait + game.logics.addedPillarWait * Math.random() ) |0;
290 |
291 | ++num;
292 | } while( Math.random() < .1 && num < 2 );
293 | }
294 | for( var i = 0; i < game.logics.pillars.length; ++i ){
295 |
296 | var pillar = game.logics.pillars[ i ];
297 |
298 | if( pillar.dead ) continue;
299 |
300 | pillar.y -= player.vy; // if you go towards something it's as if they went towards you
301 |
302 | if( pillar.y > game.logics.height ){
303 | pillar.dead = true;
304 |
305 | } else if( pillar.y > player.y && pillar.y + player.vy < player.y ){
306 |
307 |
308 | if( ( player.x > pillar.x && player.x < pillar.x + pillar.w ) || ( pillar.warping && ( player.x <= pillar.warpLeft ) ) ){
309 |
310 | player.dead = true;
311 | } else {
312 | ++game.logics.score
313 | }
314 | }
315 | }
316 | }
317 | game.drawBackground = function(){
318 |
319 | game.screen.midBezier += game.screen.midBezierVel -= game.screen.midBezier * game.screen.midBezierAccMultiplier;
320 | game.screen.midBezierVel *= game.screen.midBezierFriction;
321 |
322 | var ctx = game.screen.ctx;
323 |
324 | ctx.globalCompositeOperation = 'source-over';
325 |
326 | ctx.fillStyle = game.screen.colors[ 0 ];
327 | ctx.fillRect( 0, 0, game.screen.halfw + ( game.screen.midBezier > 0 ? ( game.screen.midBezier / 2 )|0 : 0 ), game.screen.height );
328 |
329 | ctx.fillStyle = game.screen.colors[ 1 ];
330 | ctx.beginPath();
331 | ctx.moveTo( game.screen.halfw, 0 );
332 | ctx.lineTo( game.screen.width, 0 );
333 | ctx.lineTo( game.screen.width, game.screen.height );
334 | ctx.lineTo( game.screen.halfw, game.screen.height );
335 | ctx.quadraticCurveTo( game.screen.halfw + game.screen.midBezier, game.player.y, game.screen.halfw, 0 );
336 | ctx.fill();
337 | }
338 | game.drawPillars = function(){
339 |
340 | var ctx = game.screen.ctx;
341 |
342 | ctx.globalCompositeOperation = 'source-over';
343 | ctx.fillStyle = game.screen.colors[ 2 ];
344 |
345 | for( var i = 0; i < game.logics.pillars.length; ++i ){
346 |
347 | var pillar = game.logics.pillars[ i ];
348 |
349 | if( !pillar.dead ){
350 | ctx.fillRect( pillar.x, pillar.y, pillar.w, game.screen.pillarHeight );
351 | if( pillar.warping )
352 | ctx.fillRect( 0, pillar.y, pillar.warpLeft, game.screen.pillarHeight );
353 | }
354 | }
355 | }
356 | game.drawPlayer = function(){
357 |
358 | var ctx = game.screen.ctx,
359 | player = game.player;
360 |
361 | ctx.globalCompositeOperation = 'difference';
362 |
363 | ctx.fillStyle = game.screen.colors[ 0 ];
364 | ctx.save();
365 | ctx.translate( player.x, player.y );
366 | ctx.rotate( player.rotation );
367 | ctx.fillRect( game.constants[ 0 ], game.constants[ 0 ], player.size, player.size ); // -player.size / 2;
368 | ctx.restore();
369 |
370 | }
371 | game.drawTexts = function(){
372 |
373 | var ctx = game.screen.ctx;
374 |
375 | ctx.globalCompositeOperation = 'difference';
376 |
377 | ctx.fillStyle = game.screen.colors[ 0 ];
378 |
379 | var prop = game.screen.barSize - ( 1 - game.player.usedJumps / game.player.maxJumps );
380 |
381 | if( prop < 0 )
382 | game.screen.barSize += game.screen.barSizeVel;
383 | else if( prop > game.screen.barSizeVel )
384 | game.screen.barSize -= game.screen.barSizeVel;
385 |
386 | ctx.font = game.screen.fonts[ 2 ];
387 |
388 | ctx.fillText( game.screen.texts[ 0 ], game.constants[ 1 ], game.constants[ 2 ] ); // game.screen.halfw * 1.5 - game.screen.lengths[ 0 ] / 2; game.screen.height - 30;
389 | ctx.fillRect( game.constants[ 3 ], game.constants[ 4 ], game.screen.barSize * game.constants[ 5 ], 25 ); // game.screen.halfw * 1.5 - game.screen.lenghts[ 0 ] / 2 - 5; game.screen.height - 48; game.screen.lengths[ 0 ] + 10
390 |
391 | ctx.font = game.screen.fonts[ 1 ];
392 |
393 | var text = game.logics.score;
394 | ctx.fillText( text, game.screen.halfw - ctx.measureText( text ).width / 2, 80 );
395 |
396 | if( game.controls.menuing ){
397 |
398 | ctx.font = game.screen.fonts[ 2 ];
399 | ctx.fillText( game.screen.texts[ 2 ], game.constants[ 6 ], game.screen.halfh ); // game.screen.halfw - game.screen.lengths[ 1 ] / 2
400 | }
401 | }
402 |
403 | game.init();
--------------------------------------------------------------------------------