├── .gitignore
├── INSTALL.md
├── README.md
├── app
├── .meteor
│ ├── .gitignore
│ └── packages
├── client
│ ├── css
│ │ ├── libs
│ │ │ └── normalize.css
│ │ └── project.css
│ ├── index.html
│ ├── js
│ │ └── game
│ │ │ ├── App.js
│ │ │ ├── Game.js
│ │ │ ├── Menu.js
│ │ │ ├── MenuDashboard.js
│ │ │ ├── MenuGameover.js
│ │ │ ├── MenuProjects.js
│ │ │ ├── MenuWebgl.js
│ │ │ ├── SoundTrack.js
│ │ │ ├── Stats.js
│ │ │ └── resources
│ │ │ ├── Branch.js
│ │ │ ├── GamepadSupport.js
│ │ │ └── Player.js
│ ├── lib
│ │ ├── jquery.js
│ │ ├── lodash.js
│ │ ├── modernizr.js
│ │ └── webgl
│ │ │ ├── Stats.js
│ │ │ ├── THREEx.KeyboardState.js
│ │ │ ├── THREEx.WindowResize.js
│ │ │ ├── core
│ │ │ └── three
│ │ │ │ ├── Detector.js
│ │ │ │ └── three.js
│ │ │ └── tween
│ │ │ └── tween.js
│ ├── scss
│ │ ├── _mixins.scss
│ │ └── project.scss
│ └── templates
│ │ ├── choose.html
│ │ ├── game
│ │ ├── dashboard.html
│ │ ├── level.html
│ │ └── life.html
│ │ ├── gamover.html
│ │ ├── partial
│ │ ├── about.html
│ │ ├── help.html
│ │ ├── projects.html
│ │ ├── recentScores.html
│ │ └── topScores.html
│ │ ├── tutorial.html
│ │ ├── webgl.html
│ │ └── welcome.html
├── public
│ ├── img
│ │ ├── bg.png
│ │ ├── crOrangeMCode.png
│ │ ├── crOrangePCode.png
│ │ ├── crPR.png
│ │ ├── crPurpleMCode.png
│ │ ├── crPurplePCode.png
│ │ ├── crStar.png
│ │ ├── crTealMCode.png
│ │ ├── crTealPCode.png
│ │ ├── gamepad-map.png
│ │ ├── player0.png
│ │ ├── player1.png
│ │ ├── player2.png
│ │ ├── poster.png
│ │ ├── tutorial-bad.png
│ │ └── tutorial-good.png
│ └── music
│ │ ├── 0.ogg
│ │ ├── 1.ogg
│ │ └── 2.ogg
├── server
│ └── server.js
└── shared.js
├── config.rb
├── misc
├── assets.psd
└── bg.psd
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | .sass_cache
15 | .sass-cache
16 | .idea
17 | node_modules
18 | npm-debug.log
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/INSTALL.md:
--------------------------------------------------------------------------------
1 | # The Core Committer Installation Guide
2 |
3 | ## Dependencies
4 | * Meteor (http://meteor.com)
5 |
6 | ## Running the source of the game
7 | * clone the source, make sure you have Meteor 0.5.2
8 | * ```cd app``` and ```meteor run```
9 |
10 | ## Installation Notes
11 | * This game can save player's name to show off in the leader board, you need to configure GitHub OAuth. To do this,
12 | play a single game and in the Gameover screen, click on 'configure GitHub', follow the steps in the pop-up.
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Core Committer - The Game
2 |
3 | [ [WATCH GAME TRAILER](http://www.youtube.com/watch?v=BDPUvtY8Lr0 "Core Committer Game Trailer") ]
4 |
5 | 
6 |
7 | ## Instructions & Story
8 | * __You are the core committer.__
9 | * Choose an open source project and help that project by sorting code to proper branches.
10 | * Collect stars to make your project more popular.
11 |
12 | * allow the code blocks to hit the related branch color
13 | * good: 
14 | * bad: 
15 | * destroy the blocks that do not match the branch color using your attack lasers ([SPACE])
16 | * branches change if you destroy matching blocks or a block
17 | * when the branch changes, it lights up and the code starts flowing from a different direction
18 |
19 | * __you lose health if you mismatch the code & branch colors__ or __destroy good code blocks__
20 | * when stars get to the branch, collect then with your committer
21 | * use branch teleporting ([TAB]) and 3D view ([E]) to your advantage
22 | * the game gets harder over time, be prepared!
23 |
24 | ## Controls
25 |
26 | ### Keyboard Controls
27 |
28 | * __arrow keys__ - move
29 | * __q / w__ - < , > teleport
30 | * __TAB__ - clockwise tele
31 | * __SPACE__ - attack
32 | * __e__ - enter or exit 3D
33 |
34 |
35 | ### GamePad Controls
36 | 
37 | * Plug in your controller, smart pressing buttons when you get into game mode (after the menus).
38 | 'Gamepad' in the bottom right corner should say 'on'
39 | * If you can't get it to work, make sure your controller works with the
40 | [HTML5 Rocks Tester](http://www.html5rocks.com/en/tutorials/doodles/gamepad/gamepad-tester/tester.html).
41 | Make sure to close the tester tab, because the controller can access only one browser tab at a time
42 | * Controllers tested: XBOX360, Logitech F310 GamePad & Attack3 Joystick, PS3.
43 |
44 | ## Features
45 |
46 | * 2D & 3D Game Modes
47 | * Compatible with WebGL enabled browsers (three.js support).
48 | * Tested in Chrome & Firefox, HTML5 GamePad support in Chrome
49 | * Top & Recent Scores
50 | * GitHub Auth to save your game score
51 | * 3 amazing wub wub wub music tracks (you can also turn the music off, if you are sick of the wub wub)
52 |
53 | ## Tech Used
54 |
55 | * Meteor (http://meteor.com)
56 | * three.js (WebGL) (http://mrdoob.github.com/three.js/)
57 | * Compass / SASS
58 | * Modernizr
59 | * Lo-dash
60 | * jQuery
61 | * HTML5 GamePad API
62 |
63 | ## Notes
64 |
65 | * All project names & trademarks are the property of their respective owners
66 | * Game music used under Creative Commons License.
67 | Thanks to [Flembaz](http://soundcloud.com/flembaz/sets/indigo/) (Written, produced, mixed, mastered by João Bandarra & Pedro R. Artur)
68 | * Source Installation instructions are in ```INSTALL.md```
69 |
--------------------------------------------------------------------------------
/app/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 | meteorite
3 |
--------------------------------------------------------------------------------
/app/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | #
3 | # 'meteor add' and 'meteor remove' will edit this file for you,
4 | # but you can also edit it by hand.
5 |
6 | #autopublish
7 | accounts-base
8 | accounts-oauth2-helper
9 | accounts-ui
10 | accounts-github
11 |
--------------------------------------------------------------------------------
/app/client/css/libs/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v2.0.1 | MIT License | git.io/normalize */
2 |
3 | /* ==========================================================================
4 | HTML5 display definitions
5 | ========================================================================== */
6 |
7 | /*
8 | * Corrects `block` display not defined in IE 8/9.
9 | */
10 |
11 | article,
12 | aside,
13 | details,
14 | figcaption,
15 | figure,
16 | footer,
17 | header,
18 | hgroup,
19 | nav,
20 | section,
21 | summary {
22 | display: block;
23 | }
24 |
25 | /*
26 | * Corrects `inline-block` display not defined in IE 8/9.
27 | */
28 |
29 | audio,
30 | canvas,
31 | video {
32 | display: inline-block;
33 | }
34 |
35 | /*
36 | * Prevents modern browsers from displaying `audio` without controls.
37 | * Remove excess height in iOS 5 devices.
38 | */
39 |
40 | audio:not([controls]) {
41 | display: none;
42 | height: 0;
43 | }
44 |
45 | /*
46 | * Addresses styling for `hidden` attribute not present in IE 8/9.
47 | */
48 |
49 | [hidden] {
50 | display: none;
51 | }
52 |
53 | /* ==========================================================================
54 | Base
55 | ========================================================================== */
56 |
57 | /*
58 | * 1. Sets default font family to sans-serif.
59 | * 2. Prevents iOS text size adjust after orientation change, without disabling
60 | * user zoom.
61 | */
62 |
63 | html {
64 | font-family: sans-serif; /* 1 */
65 | -webkit-text-size-adjust: 100%; /* 2 */
66 | -ms-text-size-adjust: 100%; /* 2 */
67 | }
68 |
69 | /*
70 | * Removes default margin.
71 | */
72 |
73 | body {
74 | margin: 0;
75 | }
76 |
77 | /* ==========================================================================
78 | Links
79 | ========================================================================== */
80 |
81 | /*
82 | * Addresses `outline` inconsistency between Chrome and other browsers.
83 | */
84 |
85 | a:focus {
86 | outline: thin dotted;
87 | }
88 |
89 | /*
90 | * Improves readability when focused and also mouse hovered in all browsers.
91 | */
92 |
93 | a:active,
94 | a:hover {
95 | outline: 0;
96 | }
97 |
98 | /* ==========================================================================
99 | Typography
100 | ========================================================================== */
101 |
102 | /*
103 | * Addresses `h1` font sizes within `section` and `article` in Firefox 4+,
104 | * Safari 5, and Chrome.
105 | */
106 |
107 | h1 {
108 | font-size: 2em;
109 | }
110 |
111 | /*
112 | * Addresses styling not present in IE 8/9, Safari 5, and Chrome.
113 | */
114 |
115 | abbr[title] {
116 | border-bottom: 1px dotted;
117 | }
118 |
119 | /*
120 | * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
121 | */
122 |
123 | b,
124 | strong {
125 | font-weight: bold;
126 | }
127 |
128 | /*
129 | * Addresses styling not present in Safari 5 and Chrome.
130 | */
131 |
132 | dfn {
133 | font-style: italic;
134 | }
135 |
136 | /*
137 | * Addresses styling not present in IE 8/9.
138 | */
139 |
140 | mark {
141 | background: #ff0;
142 | color: #000;
143 | }
144 |
145 |
146 | /*
147 | * Corrects font family set oddly in Safari 5 and Chrome.
148 | */
149 |
150 | code,
151 | kbd,
152 | pre,
153 | samp {
154 | font-family: monospace, serif;
155 | font-size: 1em;
156 | }
157 |
158 | /*
159 | * Improves readability of pre-formatted text in all browsers.
160 | */
161 |
162 | pre {
163 | white-space: pre;
164 | white-space: pre-wrap;
165 | word-wrap: break-word;
166 | }
167 |
168 | /*
169 | * Sets consistent quote types.
170 | */
171 |
172 | q {
173 | quotes: "\201C" "\201D" "\2018" "\2019";
174 | }
175 |
176 | /*
177 | * Addresses inconsistent and variable font size in all browsers.
178 | */
179 |
180 | small {
181 | font-size: 80%;
182 | }
183 |
184 | /*
185 | * Prevents `sub` and `sup` affecting `line-height` in all browsers.
186 | */
187 |
188 | sub,
189 | sup {
190 | font-size: 75%;
191 | line-height: 0;
192 | position: relative;
193 | vertical-align: baseline;
194 | }
195 |
196 | sup {
197 | top: -0.5em;
198 | }
199 |
200 | sub {
201 | bottom: -0.25em;
202 | }
203 |
204 | /* ==========================================================================
205 | Embedded content
206 | ========================================================================== */
207 |
208 | /*
209 | * Removes border when inside `a` element in IE 8/9.
210 | */
211 |
212 | img {
213 | border: 0;
214 | }
215 |
216 | /*
217 | * Corrects overflow displayed oddly in IE 9.
218 | */
219 |
220 | svg:not(:root) {
221 | overflow: hidden;
222 | }
223 |
224 | /* ==========================================================================
225 | Figures
226 | ========================================================================== */
227 |
228 | /*
229 | * Addresses margin not present in IE 8/9 and Safari 5.
230 | */
231 |
232 | figure {
233 | margin: 0;
234 | }
235 |
236 | /* ==========================================================================
237 | Forms
238 | ========================================================================== */
239 |
240 | /*
241 | * Define consistent border, margin, and padding.
242 | */
243 |
244 | fieldset {
245 | border: 1px solid #c0c0c0;
246 | margin: 0 2px;
247 | padding: 0.35em 0.625em 0.75em;
248 | }
249 |
250 | /*
251 | * 1. Corrects color not being inherited in IE 8/9.
252 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
253 | */
254 |
255 | legend {
256 | border: 0; /* 1 */
257 | padding: 0; /* 2 */
258 | }
259 |
260 | /*
261 | * 1. Corrects font family not being inherited in all browsers.
262 | * 2. Corrects font size not being inherited in all browsers.
263 | * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome
264 | */
265 |
266 | button,
267 | input,
268 | select,
269 | textarea {
270 | font-family: inherit; /* 1 */
271 | font-size: 100%; /* 2 */
272 | margin: 0; /* 3 */
273 | }
274 |
275 | /*
276 | * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in
277 | * the UA stylesheet.
278 | */
279 |
280 | button,
281 | input {
282 | line-height: normal;
283 | }
284 |
285 | /*
286 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
287 | * and `video` controls.
288 | * 2. Corrects inability to style clickable `input` types in iOS.
289 | * 3. Improves usability and consistency of cursor style between image-type
290 | * `input` and others.
291 | */
292 |
293 | button,
294 | html input[type="button"], /* 1 */
295 | input[type="reset"],
296 | input[type="submit"] {
297 | -webkit-appearance: button; /* 2 */
298 | cursor: pointer; /* 3 */
299 | }
300 |
301 | /*
302 | * Re-set default cursor for disabled elements.
303 | */
304 |
305 | button[disabled],
306 | input[disabled] {
307 | cursor: default;
308 | }
309 |
310 | /*
311 | * 1. Addresses box sizing set to `content-box` in IE 8/9.
312 | * 2. Removes excess padding in IE 8/9.
313 | */
314 |
315 | input[type="checkbox"],
316 | input[type="radio"] {
317 | box-sizing: border-box; /* 1 */
318 | padding: 0; /* 2 */
319 | }
320 |
321 | /*
322 | * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome.
323 | * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome
324 | * (include `-moz` to future-proof).
325 | */
326 |
327 | input[type="search"] {
328 | -webkit-appearance: textfield; /* 1 */
329 | -moz-box-sizing: content-box;
330 | -webkit-box-sizing: content-box; /* 2 */
331 | box-sizing: content-box;
332 | }
333 |
334 | /*
335 | * Removes inner padding and search cancel button in Safari 5 and Chrome
336 | * on OS X.
337 | */
338 |
339 | input[type="search"]::-webkit-search-cancel-button,
340 | input[type="search"]::-webkit-search-decoration {
341 | -webkit-appearance: none;
342 | }
343 |
344 | /*
345 | * Removes inner padding and border in Firefox 4+.
346 | */
347 |
348 | button::-moz-focus-inner,
349 | input::-moz-focus-inner {
350 | border: 0;
351 | padding: 0;
352 | }
353 |
354 | /*
355 | * 1. Removes default vertical scrollbar in IE 8/9.
356 | * 2. Improves readability and alignment in all browsers.
357 | */
358 |
359 | textarea {
360 | overflow: auto; /* 1 */
361 | vertical-align: top; /* 2 */
362 | }
363 |
364 | /* ==========================================================================
365 | Tables
366 | ========================================================================== */
367 |
368 | /*
369 | * Remove most spacing between table cells.
370 | */
371 |
372 | table {
373 | border-collapse: collapse;
374 | border-spacing: 0;
375 | }
--------------------------------------------------------------------------------
/app/client/css/project.css:
--------------------------------------------------------------------------------
1 | /* line 4, ../scss/project.scss */
2 | a {
3 | color: #000011;
4 | font-weight: bold;
5 | text-decoration: none;
6 | }
7 | /* line 18, ../../../../../.rvm/gems/ruby-1.9.3-p194/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/typography/links/_link-colors.scss */
8 | a:visited {
9 | color: #000011;
10 | }
11 | /* line 21, ../../../../../.rvm/gems/ruby-1.9.3-p194/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/typography/links/_link-colors.scss */
12 | a:focus {
13 | color: silver;
14 | }
15 | /* line 24, ../../../../../.rvm/gems/ruby-1.9.3-p194/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/typography/links/_link-colors.scss */
16 | a:hover {
17 | color: silver;
18 | }
19 | /* line 27, ../../../../../.rvm/gems/ruby-1.9.3-p194/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/typography/links/_link-colors.scss */
20 | a:active {
21 | color: #000011;
22 | }
23 |
24 | /* line 10, ../scss/project.scss */
25 | * {
26 | font-family: 'Gudea', sans-serif;
27 | text-transform: lowercase;
28 | }
29 |
30 | /* line 15, ../scss/project.scss */
31 | h3 {
32 | margin: 0px;
33 | }
34 |
35 | /* line 19, ../scss/project.scss */
36 | ul, li {
37 | list-style-type: none;
38 | margin: 0px;
39 | padding: 0px;
40 | }
41 |
42 | /* line 25, ../scss/project.scss */
43 | body {
44 | background-color: #222222;
45 | background: url("/img/bg.png");
46 | overflow: hidden;
47 | }
48 |
49 | /* line 32, ../scss/project.scss */
50 | button, .topper-info {
51 | position: relative;
52 | overflow: visible;
53 | display: inline-block;
54 | padding: 0.5em 1em;
55 | margin: 0;
56 | text-decoration: none;
57 | text-align: center;
58 | text-shadow: 1px 1px 0 #fff;
59 | font-size: 20px;
60 | color: #333;
61 | }
62 | /* line 46, ../scss/project.scss */
63 | button.new-game, button.continue, .topper-info.new-game, .topper-info.continue {
64 | font-weight: bold;
65 | margin: 30px 0px 30px 275px;
66 | width: 350px;
67 | padding: 10px 20px;
68 | }
69 |
70 | /* line 55, ../scss/project.scss */
71 | button, .topper-info, .ossprojects li, .view-gamepad {
72 | border: 1px solid #d4d4d4;
73 | white-space: nowrap;
74 | cursor: pointer;
75 | outline: none;
76 | background-color: #ececec;
77 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f4f4f4), to(#ececec));
78 | background-image: -moz-linear-gradient(#f4f4f4, #ececec);
79 | background-image: -ms-linear-gradient(#f4f4f4, #ececec);
80 | background-image: -o-linear-gradient(#f4f4f4, #ececec);
81 | background-image: linear-gradient(#f4f4f4, #ececec);
82 | -moz-background-clip: padding;
83 | /* for Firefox 3.6 */
84 | background-clip: padding-box;
85 | border-radius: 0.2em;
86 | }
87 |
88 | /* line 72, ../scss/project.scss */
89 | .view-gamepad {
90 | display: block;
91 | text-align: center;
92 | padding: 2px;
93 | margin-top: 5px;
94 | font-weight: normal;
95 | }
96 |
97 | /* line 80, ../scss/project.scss */
98 | button:hover, .ossprojects li:hover {
99 | background-color: #ffffff;
100 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f4f4f4), to(white));
101 | background-image: -moz-linear-gradient(#f4f4f4, white);
102 | background-image: -ms-linear-gradient(#f4f4f4, white);
103 | background-image: -o-linear-gradient(#f4f4f4, white);
104 | background-image: linear-gradient(#f4f4f4, #ffffff);
105 | }
106 |
107 | /* line 89, ../scss/project.scss */
108 | .topper-info {
109 | color: #FFF;
110 | text-transform: lowercase;
111 | border-radius: 0;
112 | cursor: none;
113 | width: 100%;
114 | font-size: 10px;
115 | color: #000011;
116 | }
117 |
118 | /* line 99, ../scss/project.scss */
119 | .control-help {
120 | font-size: 10px;
121 | color: #FFF;
122 | width: 100px;
123 | position: absolute;
124 | bottom: 0px;
125 | right: 0px;
126 | width: 100px;
127 | }
128 |
129 | /* line 109, ../scss/project.scss */
130 | .gamepad-status {
131 | position: absolute;
132 | bottom: 100px;
133 | right: 0px;
134 | font-size: 12px;
135 | width: 100px;
136 | color: #FFF;
137 | }
138 | /* line 116, ../scss/project.scss */
139 | .gamepad-status .connected {
140 | background: #baff72;
141 | }
142 |
143 | /* line 121, ../scss/project.scss */
144 | .req-webgl .continue {
145 | margin: 85px 0px 30px 170px;
146 | width: 600px;
147 | font-size: 23px;
148 | }
149 |
150 | /* line 127, ../scss/project.scss */
151 | .player-list li {
152 | display: inline;
153 | }
154 |
155 | /* line 132, ../scss/project.scss */
156 | .req-welcome h3 {
157 | color: #333333;
158 | margin-left: 6px;
159 | }
160 |
161 | /* line 139, ../scss/project.scss */
162 | .req-gameover h1 {
163 | margin-lefT: 75px;
164 | }
165 | /* line 142, ../scss/project.scss */
166 | .req-gameover .window p {
167 | margin-left: 35px;
168 | }
169 |
170 | /* line 148, ../scss/project.scss */
171 | .req-project aside {
172 | font-size: 20px;
173 | margin: 20px 0px 20px 35px;
174 | }
175 |
176 | /* line 154, ../scss/project.scss */
177 | .frames {
178 | width: 990px;
179 | margin: 0 auto;
180 | position: relative;
181 | }
182 |
183 | /* line 160, ../scss/project.scss */
184 | .life {
185 | height: 20px;
186 | width: 100%;
187 | background-color: #cdeb8e;
188 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #cdeb8e), color-stop(100%, #a5c956));
189 | background-image: -webkit-linear-gradient(top, #cdeb8e 0%, #a5c956 100%);
190 | background-image: -moz-linear-gradient(top, #cdeb8e 0%, #a5c956 100%);
191 | background-image: -o-linear-gradient(top, #cdeb8e 0%, #a5c956 100%);
192 | background-image: linear-gradient(top, #cdeb8e 0%, #a5c956 100%);
193 | text-transform: lowercase;
194 | }
195 |
196 | /* line 172, ../scss/project.scss */
197 | .frame {
198 | position: absolute;
199 | width: 990px;
200 | top: -1000px;
201 | margin: 0 auto;
202 | }
203 | /* line 177, ../scss/project.scss */
204 | .frame h1 {
205 | font-weight: normal;
206 | font-size: 60px;
207 | text-shadow: 2px 1px 4px #272626;
208 | height: 90px;
209 | color: #F3F5F7;
210 | margin: 0px 0px 0px 45px;
211 | padding: 0px;
212 | text-transform: lowercase;
213 | }
214 | /* line 187, ../scss/project.scss */
215 | .frame .window {
216 | -webkit-box-shadow: "inset 0px 1px 0px rgba(255,255,255, 0.25), 0px 10px 20px rgba(0,0,0, 0.7)";
217 | -moz-box-shadow: "inset 0px 1px 0px rgba(255,255,255, 0.25), 0px 10px 20px rgba(0,0,0, 0.7)";
218 | box-shadow: "inset 0px 1px 0px rgba(255,255,255, 0.25), 0px 10px 20px rgba(0,0,0, 0.7)";
219 | width: 900px;
220 | overflow: hidden;
221 | background: #FFF;
222 | position: relative;
223 | min-height: 250px;
224 | max-height: 460px;
225 | margin: 0 auto;
226 | }
227 | /* line 196, ../scss/project.scss */
228 | .frame .window .part {
229 | width: 25%;
230 | float: left;
231 | }
232 | /* line 199, ../scss/project.scss */
233 | .frame .window .part h3 {
234 | margin: 20px 0px 0px 0px;
235 | }
236 | /* line 203, ../scss/project.scss */
237 | .frame .window .part-large {
238 | float: left;
239 | width: 70%;
240 | padding-right: 4%;
241 | }
242 | /* line 207, ../scss/project.scss */
243 | .frame .window .part-large ul {
244 | margin-left: 5%;
245 | }
246 | /* line 210, ../scss/project.scss */
247 | .frame .window .part-large li {
248 | font-size: 18px;
249 | margin: 10px 0px 10px 0px;
250 | list-style-type: square;
251 | }
252 | /* line 216, ../scss/project.scss */
253 | .frame .window h1 {
254 | margin: 0px;
255 | text-align: center;
256 | font-weight: bold;
257 | text-transform: uppercase;
258 | color: #c0c0c0;
259 | }
260 | /* line 222, ../scss/project.scss */
261 | .frame .window h1.logo span {
262 | color: #000011;
263 | }
264 | /* line 226, ../scss/project.scss */
265 | .frame .window .under-logo {
266 | position: absolute;
267 | top: 47px;
268 | left: 350px;
269 | }
270 |
271 | /* line 234, ../scss/project.scss */
272 | .plays {
273 | clear: both;
274 | }
275 | /* line 236, ../scss/project.scss */
276 | .plays .play {
277 | overflow: hidden;
278 | float: left;
279 | width: 9%;
280 | font-size: 10px;
281 | border-left: 1px solid grey;
282 | padding: 0.7%;
283 | margin: 0.7%;
284 | white-space: nowrap;
285 | }
286 |
287 | /* line 248, ../scss/project.scss */
288 | .progress {
289 | display: none;
290 | }
291 |
292 | /* line 252, ../scss/project.scss */
293 | .ossprojects {
294 | overflow: hidden;
295 | margin: 0px 0px 20px 25px;
296 | }
297 | /* line 253, ../scss/project.scss */
298 | .ossprojects li {
299 | cursor: pointer;
300 | float: left;
301 | width: 20%;
302 | margin: 1%;
303 | padding: 1%;
304 | height: 100px;
305 | overflow: hidden;
306 | }
307 | /* line 261, ../scss/project.scss */
308 | .ossprojects li span {
309 | display: block;
310 | }
311 | /* line 265, ../scss/project.scss */
312 | .ossprojects li .name {
313 | font-weight: bold;
314 | text-align: center;
315 | font-size: 24px;
316 | margin-bottom: 30px;
317 | }
318 |
319 | /* line 279, ../scss/project.scss */
320 | .about {
321 | position: absolute;
322 | color: #FFF;
323 | left: 0px;
324 | bottom: 0px;
325 | font-size: 10px;
326 | }
327 | /* line 285, ../scss/project.scss */
328 | .about a {
329 | color: #FFF;
330 | }
331 |
332 | /* line 290, ../scss/project.scss */
333 | .again {
334 | position: absolute;
335 | top: 40px;
336 | right: 36px;
337 | width: 200px;
338 | }
339 |
340 | /* line 297, ../scss/project.scss */
341 | .g-on {
342 | color: green;
343 | }
344 |
345 | /* line 301, ../scss/project.scss */
346 | .level {
347 | filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70);
348 | opacity: 0.7;
349 | display: none;
350 | background-color: #fc4e1e;
351 | border-radius: 10px;
352 | height: 100px;
353 | width: 10%;
354 | top: 80px;
355 | margin-left: -10%;
356 | left: 50%;
357 | text-align: center;
358 | padding: 20px;
359 | position: absolute;
360 | }
361 | /* line 314, ../scss/project.scss */
362 | .level div {
363 | margin-top: 10px;
364 | font-size: 24px;
365 | }
366 | /* line 317, ../scss/project.scss */
367 | .level div span {
368 | font-size: 45px;
369 | display: block;
370 | font-weight: bold;
371 | margin: 0auto;
372 | }
373 |
374 | /* line 326, ../scss/project.scss */
375 | .window button.music {
376 | padding: 2px;
377 | font-size: 15px;
378 | margin-top: 5px;
379 | }
380 |
381 | /* line 331, ../scss/project.scss */
382 | body > .control-help .music {
383 | font-size: 12px;
384 | padding: 0px 5px;
385 | margin: 0px;
386 | border: 0px;
387 | text-align: left;
388 | text-shadow: none;
389 | }
390 |
--------------------------------------------------------------------------------
/app/client/index.html:
--------------------------------------------------------------------------------
1 |
2 | Core Committer - The Game
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {{> gameover }}
11 |
12 |
13 |
16 |
17 | {{> tutorial }}
18 | {{> welcome }}
19 | {{> webgl }}
20 |
21 |
22 |
23 | {{> dashboard}}
24 | {{> life}}
25 | {{> level}}
26 |
27 |
28 |
31 |
32 | {{> about}}
33 |
34 |
--------------------------------------------------------------------------------
/app/client/js/game/App.js:
--------------------------------------------------------------------------------
1 | var PX_HIDE = -1500,
2 | PX_SHOW = 0,
3 | PX_SPEED = 300,
4 | MUSIC;
5 |
6 | var RecentScores = new Meteor.Collection("recent_scores"),
7 | TopScores = new Meteor.Collection("top_scores");
8 |
9 |
10 | // shim layer with setTimeout fallback
11 | window.requestAnimFrame = (function(){
12 | return window.requestAnimationFrame ||
13 | window.webkitRequestAnimationFrame ||
14 | window.mozRequestAnimationFrame ||
15 | window.oRequestAnimationFrame ||
16 | window.msRequestAnimationFrame ||
17 | function( callback ){
18 | window.setTimeout(callback, 1000 / 60);
19 | };
20 | })();
21 |
22 | Meteor.subscribe('projects');
23 | Meteor.subscribe("recent_scores");
24 | Meteor.subscribe("top_scores");
25 |
26 |
27 | /**
28 | * Meteor startup!
29 | */
30 | Meteor.startup(function () {
31 | Session.set('gameOn', false);
32 | Session.set('sessionLevel', 0);
33 | Session.set('sessionStars', 0);
34 | Session.set('sessionCommits', 0);
35 | Session.set('pid', null);
36 | Session.set('stats', null);
37 | Session.set('gamepadStatus', 'off');
38 |
39 | if (! Session.get('musicStatus')) Session.set('musicStatus', 'on');
40 |
41 | if (Modernizr.audio) {
42 | MUSIC = new SoundTrack();
43 | }
44 | //if (Modernizr.webgl){
45 | if ( Detector.webgl ) {
46 | //$('.req-webgl').animate({ top: PX_SHOW });
47 | $('.req-welcome').animate({ top: PX_SHOW });
48 | //startGame(); // sup debug
49 |
50 | } else {
51 | $('.req-webgl').animate({ top: PX_SHOW });
52 | }
53 | });
54 |
55 |
56 | /**
57 | * Meteor autorun
58 | */
59 | Meteor.autorun(function() {
60 | if (Meteor.user() && Session.equals("gameOver", true)) {
61 | Meteor.call('userUpdate', { data: Session.get('st') });
62 | Session.set('gameOver', false);
63 | }
64 | });
65 |
66 | /**
67 | * GitHub Login setup
68 | */
69 | Meteor.loginWithGithub({
70 | requestPermissions: ['user', 'public_repo']
71 | }, function (err) {
72 | if (err) {
73 | Session.set('errorMessage', err.reason || 'Unknown error');
74 | }
75 | });
76 |
77 |
78 | /**
79 | * Let the games begin
80 | */
81 | function startGame() {
82 |
83 | var cc;
84 | var $lifeBar = $('.life'),
85 | $progress = $('.progress');
86 |
87 |
88 | cc = new CoreCommit(Session.get("pid"));
89 | cc.addEventListener('decreaseLife', function (e) {
90 | $lifeBar.css('width', e.data + '%');
91 | });
92 |
93 | cc.addEventListener('decreaseLife', function (e) {
94 | $lifeBar.css('width', e.data + '%');
95 | });
96 |
97 | cc.addEventListener('start', function (e) {
98 | $progress.fadeIn();
99 | });
100 |
101 | cc.addEventListener('session', function (e) {
102 | Session.set('sessionCommits', e.detail.COMMITS);
103 | Session.set('sessionStars', e.detail.STARS);
104 | Meteor.call('sessionUpdate', { data: e.detail });
105 | });
106 |
107 | cc.addEventListener('gamepadConnected', function (e) {
108 | Session.set('gamepadStatus', 'on');
109 | });
110 |
111 | cc.addEventListener('gamepadDisconnected', function (e) {
112 | Session.set('gamepadStatus', 'off');
113 | });
114 |
115 | cc.addEventListener('levelUpdate', function (e) {
116 | Session.set("sessionLevel", e.detail);
117 | });
118 |
119 | cc.addEventListener('gameOver', function (e) {
120 | $('.req-gameover').animate({ top: PX_SHOW });
121 | Session.set("gameOver", true);
122 | if (e.detail.LEVEL == 0 && e.detail.COMMITS == 0 && e.detail.STARS == 0) {
123 | e.detail.EPIC_FAIL = true;
124 | }
125 | Session.set('stats', e.detail);
126 | Session.set('st', e.detail.START_TIME);
127 | $progress.slideUp();
128 | Session.set('gameOn', false);
129 | });
130 |
131 | cc.start();
132 | Session.set('gameOn', true);
133 | if (Session.get('musicStatus') == 'on') {
134 | MUSIC.play();
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/app/client/js/game/Game.js:
--------------------------------------------------------------------------------
1 | (function (exports) {
2 |
3 | var CoreCommit = function (project) {
4 | // standard global variables
5 | var container, scene, camera, stats, self = this;
6 |
7 | this.setGameVariables(project);
8 | // enable events for this object
9 | this.extendAsEventDispatcher();
10 | // add custom events
11 | this.addCustomEvents();
12 |
13 | // CAMERA
14 | var VIEW_ANGLE = 45, ASPECT = this.SCREEN_WIDTH / this.SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
15 | camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
16 | camera.position.set(1200, 0, 4000);
17 |
18 | this.camera = camera;
19 | this.camera.up.set(0,0,0);
20 |
21 | // SCENE
22 | scene = new THREE.Scene();
23 | scene.position.set(0, 0, 0);
24 | this.scene = scene;
25 | scene.add(camera);
26 |
27 | // ROTATOR
28 | var crateMaterial = new THREE.MeshBasicMaterial({ color:0xff4747, transparent:true, opacity:0 });
29 | this.__rotator = new THREE.Mesh(THREE.GeometryUtils.clone(new THREE.CubeGeometry(60, 25, 25)), crateMaterial);
30 | this.__rotator.position.set(0,0,0);
31 | this.scene.add(this.__rotator);
32 |
33 | // RENDERER
34 | this.renderer = new THREE.WebGLRenderer({antialias:false});
35 | this.renderer.setSize(this.SCREEN_WIDTH, this.SCREEN_HEIGHT);
36 |
37 | container = document.createElement('div');
38 | document.body.appendChild(container);
39 | container.appendChild(this.renderer.domElement);
40 |
41 | // EVENTS
42 | THREEx.WindowResize(this.renderer, this.camera);
43 | //THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
44 | // CONTROLS
45 | //controls = new THREE.TrackballControls( camera );
46 |
47 | // STATS
48 | stats = new Stats();
49 | stats.domElement.style.position = 'absolute';
50 | stats.domElement.style.bottom = '0px';
51 | stats.domElement.style.zIndex = 100;
52 | this.stats = stats;
53 | //container.appendChild(stats.domElement);
54 |
55 | // Create git branches
56 | this.generateBranches();
57 | // Load Textures
58 | this.loadTextures();
59 |
60 | // GAMEPAD SUPPORT
61 | // Add gamepad support
62 | this.prevRawGamepadTypes = [];
63 | this.gamepad = new GamepadSupport();
64 |
65 | // Add a new player
66 | this.player = new Player();
67 | // set the current view
68 | this.player.view = 4;
69 | scene.add(this.player.mesh);
70 | };
71 |
72 |
73 | /**
74 | * Start the game
75 | */
76 | CoreCommit.prototype.start = function () {
77 | var self = this;
78 | this.dispatchEvent({type:'start'});
79 | var endAnim = new TWEEN.Tween(this.camera.position)
80 | .onUpdate(function(){
81 | self.camera.lookAt(self.scene.position);
82 | })
83 | .to({ x:0, z:2200 }, 1500)
84 | .easing(TWEEN.Easing.Sinusoidal.In).start();
85 |
86 |
87 |
88 | this.animate(); // keep last
89 |
90 | this.addEventListener('handleCollision', function (e) {
91 | self.handleCollision(e.data);
92 | });
93 | };
94 |
95 |
96 | /**
97 | * Animate the game
98 | */
99 | CoreCommit.prototype.animate = function () {
100 | // support gamepads
101 | this.gamepad.checkGamepadSupport();
102 |
103 | // game frame update
104 | this.update();
105 |
106 | // animates tweens
107 | TWEEN.update();
108 |
109 | // increase frames
110 | this.FRAME++;
111 |
112 | // game over
113 | if (!this.PAUSED) window.requestAnimFrame(this.animate.bind(this));
114 | };
115 |
116 |
117 | CoreCommit.prototype.sendSession = function (s) {
118 | this.dispatchEvent(this.sendSessionEvent);
119 | };
120 |
121 |
122 | /**
123 | * increase game level, change difficulty and speeds
124 | */
125 | CoreCommit.prototype.trackGameLevel = function () {
126 | var level,
127 | minSpeed = 15000;
128 |
129 | if (this.FRAME > 1000) {
130 | level = parseInt(this.FRAME / 1000, 10);
131 | if (level > this.SESSION.LEVEL) {
132 | // up level!
133 | this.SESSION.LEVEL = level;
134 | this.dispatchEvent(new CustomEvent('levelUpdate', { 'detail':this.SESSION.LEVEL }));
135 |
136 | if (this.__CRATE_RATE > 65) this.__CRATE_RATE -= 8;
137 | // Increase speed here too.
138 | if (this.SPEED > minSpeed) { this.SPEED -= 700 } else { this.speed -=300 };
139 | }
140 | }
141 | };
142 |
143 |
144 | /**
145 | * update frame
146 | */
147 | CoreCommit.prototype.update = function () {
148 |
149 | this.renderer.render(this.scene, this.camera);
150 |
151 | var self = this,
152 | kb = this.keyboard; // keyboard
153 |
154 |
155 | if (this.LIFE <= 0) {
156 | this.endGame();
157 | }
158 |
159 | // up the speeds, show notifications
160 | this.trackGameLevel();
161 |
162 | if (this.gamepad.GAMEPADS && this.gamepad.GAMEPADS.length > 0) {
163 | if (! this.gamepadConnected) {
164 | this.gamepadConnected = true;
165 | this.dispatchEvent(new CustomEvent('gamepadConnected'));
166 | }
167 | for (var i in this.gamepad.GAMEPADS) {
168 | var gamepad = this.gamepad.GAMEPADS[i];
169 | if (gamepad.buttons[0] && this.AMMO) { // A - attack
170 | this.AMMO = false;
171 | this.NEW_BULLET = this.FRAME + 20;
172 | self.playerShoot();
173 | }
174 |
175 | if (gamepad.buttons[8] || gamepad.buttons[9] || gamepad.buttons[4] || gamepad.buttons[5]) {
176 | if (!this.SWITCHING) {
177 | if (this.player.view == this.VIEW.TOP) {
178 | self.switchMode('3d');
179 | } else {
180 | self.switchMode('top');
181 | }
182 | }
183 | }
184 |
185 | if (gamepad.buttons[2]) {
186 | if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
187 | self.rotateMode('left', true);
188 | } else if (!this._teleporting) {
189 | self.teleportPlayer(null, 'left');
190 | }
191 | }
192 |
193 | if (gamepad.buttons[3]) {
194 | if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
195 | self.rotateMode('right', true);
196 | } else if (!this._teleporting) {
197 | self.teleportPlayer();
198 | }
199 | }
200 |
201 | // feature disabled, always true
202 | if (gamepad.buttons[6]) {
203 | if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
204 | self.rotateMode('left', true);
205 | } else if (!this._teleporting) {
206 | self.teleportPlayer(null, 'left');
207 | }
208 | }
209 |
210 | if (gamepad.buttons[7] || gamepad.buttons[3]) {
211 | if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
212 | self.rotateMode('right', true);
213 | } else if (!this._teleporting) {
214 | self.teleportPlayer();
215 | }
216 | }
217 |
218 | if (gamepad.buttons[1]) {
219 | if (!this._teleporting) {
220 | self.teleportPlayer();
221 | }
222 | }
223 |
224 | if (gamepad.buttons[12] || gamepad.axes[1] < -0.25 || gamepad.axes[3] < -0.25) { // up
225 | this.player.moveUpLeft(this.player.branch, this.VIEW);
226 | }
227 | if (gamepad.buttons[13] || gamepad.axes[1] > 0.25 || gamepad.axes[3] > 0.25) { // down
228 | this.player.moveDownRight(this.player.branch, this.VIEW);
229 | }
230 | if (gamepad.buttons[14] || gamepad.axes[0] < -0.25 || gamepad.axes[2] < -0.25) { // left
231 | this.player.moveUpLeft(this.player.branch, this.VIEW);
232 | }
233 | if (gamepad.buttons[15] || gamepad.axes[0] > 0.25 || gamepad.axes[2] > 0.25) { // right
234 | this.player.moveDownRight(this.player.branch, this.VIEW);
235 | }
236 | }
237 | } else {
238 | if (this.gamepadConnected) {
239 | this.gamepadConnected = false;
240 | this.dispatchEvent('gamepadDisconnected');
241 | }
242 | }
243 |
244 | // teleport between branches
245 | if (kb.pressed('tab')) {
246 | if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
247 | self.rotateMode('right', true);
248 | } else if (!this._teleporting) {
249 | self.teleportPlayer();
250 | }
251 | }
252 |
253 | if (( kb.pressed('up') || kb.pressed('left') )) {
254 | this.player.moveUpLeft(this.player.branch, this.VIEW);
255 | }
256 |
257 | if (kb.pressed('down') || kb.pressed('right')) {
258 | this.player.moveDownRight(this.player.branch, this.VIEW);
259 | }
260 |
261 |
262 | if (kb.pressed('space') && (this.AMMO)) {
263 | this.AMMO = false;
264 | this.NEW_BULLET = this.FRAME + 20;
265 | self.playerShoot();
266 | }
267 |
268 | if ((this.NEW_BULLET == this.FRAME)) {
269 | this.AMMO = true;
270 | }
271 |
272 | if (kb.pressed('e')) {
273 | if (!this.SWITCHING) {
274 | if (this.player.view == this.VIEW.TOP) {
275 | self.switchMode('3d');
276 | } else {
277 | self.switchMode('top');
278 | }
279 | }
280 | }
281 |
282 |
283 | if (kb.pressed('q')) {
284 | if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
285 | self.rotateMode('left', true);
286 | } else if (!this._teleporting) {
287 | self.teleportPlayer(null, 'left');
288 | }
289 | }
290 |
291 | if (kb.pressed('w')) {
292 | if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
293 | self.rotateMode('right', true);
294 | } else if (!this._teleporting) {
295 | self.teleportPlayer();
296 | }
297 | }
298 |
299 | // generate game grates
300 | if (this.NEW_CRATE_TIMER == this.FRAME) {
301 | this.NEW_CRATE_TIMER = this.FRAME + this.__CRATE_RATE;
302 | self.generateCrates();
303 | }
304 |
305 | _.each(self.BULLETS, function (bullet) {
306 | // detect bullet collisions
307 | self.detectCollision(bullet);
308 |
309 | });
310 |
311 | var timer = ( Date.now() * 0.04 );
312 | if (self.CRATES_GENERATING) {
313 | _.each(self.CRATES, function (crate) {
314 |
315 | crate.rotation.y = 0.01 * timer;
316 | crate.rotation.x = 0.01 * timer;
317 | });
318 | }
319 |
320 | // STATS
321 | //this.stats.update();
322 | };
323 |
324 |
325 | /**
326 | * detect collision
327 | * @param bullet
328 | */
329 | CoreCommit.prototype.detectCollision = function (bullet) {
330 | var self = this,
331 | cObj,
332 | originPoint = bullet.position.clone();
333 |
334 | // strange issue here, .intersectObjects(objects) used to report a lot of false collisions.
335 | _.each(self.CRATES, function (crate) {
336 | for (var vertexIndex = 0; vertexIndex < bullet.geometry.vertices.length; vertexIndex++) {
337 | var localVertex = bullet.geometry.vertices[vertexIndex].clone();
338 | //var globalVertex = bullet.matrix.multiplyVector3(localVertex);
339 | //var directionVector = globalVertex.subSelf(bullet.position);
340 |
341 | var ray = new THREE.Ray(originPoint, localVertex.clone().normalize());
342 | var collisionResults = ray.intersectObject(crate);
343 | if (collisionResults.length > 0 ) {
344 | cObj = collisionResults[0].object;
345 | break;
346 | }
347 | }
348 | });
349 |
350 | if (cObj) {
351 | self.scene.remove(cObj);
352 | self.scene.remove(bullet);
353 | cObj.dead = true;
354 | bullet.tween.stop();
355 | self.BULLETS = _.without(self.BULLETS, bullet);
356 | self.CRATES = _.without(self.CRATES, cObj);
357 |
358 | // TODO: this works, but wrong. fix later
359 | var e = {type:'handleCollision', data:cObj };
360 | self.dispatchEvent(e);
361 | }
362 | };
363 |
364 |
365 | /**
366 | * switch to a different branch
367 | */
368 | CoreCommit.prototype.gameSwitchBranch = function () {
369 | var newBranch = this.GAME_BRANCH;
370 | while (newBranch == this.GAME_BRANCH) {
371 | newBranch = parseInt(Math.random() * 3, 10); // choose a branch from 0 to 2
372 | }
373 | this.GAME_BRANCH = newBranch;
374 | _.each(this.branches, function (branch) {
375 | branch.unsetCurrent();
376 | });
377 | this.branches[this.GAME_BRANCH].setCurrent();
378 | };
379 |
380 |
381 | /**
382 | * handleCollision for the crates
383 | * @param crate
384 | */
385 | CoreCommit.prototype.handleCollision = function (crate) {
386 | var crateType = crate.type;
387 | if (crate.regularCrate) {
388 | // switch branch if you killed a good code crate :(
389 | if (crate.goodCrate) {
390 | this.decreaseLife();
391 | if (this.GAME_BRANCH == crate.targetBranch) {
392 | this.gameSwitchBranch();
393 | }
394 | }
395 | } else {
396 | switch (crateType) {
397 | case 0: // changeBranch
398 | this.gameSwitchBranch();
399 | break;
400 | case 1: // star
401 | this.sendSession(this.SESSION);
402 | break;
403 | default:
404 | this.sendSession(this.SESSION);
405 | break
406 | }
407 | }
408 | };
409 |
410 |
411 | /**
412 | * endGame
413 | */
414 | CoreCommit.prototype.endGame = function () {
415 | var self = this;
416 |
417 | if (! self._gameover_anim) {
418 | self._gameover_anim = true;
419 | this.SESSION.END_TIME = Date.now();
420 | this.SESSION.GAMEOVER = true;
421 | var endAnim = new TWEEN.Tween(self.camera.position)
422 | .to({ z:25000 }, 4000)
423 | .easing(TWEEN.Easing.Sinusoidal.In).start();
424 |
425 | endAnim.onComplete(function () {
426 | self.PAUSED = true;
427 | });
428 |
429 | this.dispatchEvent(this.gameOverEvent);
430 | this.dispatchEvent(this.sendSessionEvent);
431 | }
432 | };
433 |
434 |
435 | /**
436 | * rotate 3d view;
437 | * @param type , type of rotation
438 | */
439 | CoreCommit.prototype.rotateMode = function (type, teleport) {
440 | this.SWITCHING = true;
441 | var self = this;
442 | // TODO: this can be optimized.
443 | var poses = [
444 | new THREE.Vector3(0, -1600, 900),
445 | new THREE.Vector3(-1600, 0, 900),
446 | new THREE.Vector3(0, 1600, 900)
447 | ];
448 |
449 | if (type == 'left') {
450 | this.player.view = (this.player.view < 2) ? ++this.player.view : 0;
451 | } else {
452 | this.player.view = (this.player.view > 0) ? --this.player.view : 2;
453 | }
454 |
455 | var anim2 = new TWEEN.Tween(this.camera.position).to(poses[this.player.view], 500)
456 | .easing(TWEEN.Easing.Back.Out)
457 | .onUpdate(function () {
458 | self.camera.lookAt(self.__rotator.position);
459 | })
460 | .onComplete(function(){
461 | self.SWITCHING = false;
462 | })
463 | .start();
464 |
465 | if (teleport) {
466 | this.teleportPlayer(this.player.view);
467 | }
468 | };
469 |
470 |
471 | /**
472 | * switch view mode
473 | * @param direction
474 | */
475 | CoreCommit.prototype.switchMode = function (direction) {
476 | var self = this,
477 | animPos,
478 | cameraLookAt;
479 |
480 | this.SWITCHING = true;
481 |
482 | // switch mode between top and 3d
483 | if(direction == 'top') {
484 | this.camera.up.set(0,0,0);
485 | this.player.view = this.VIEW.TOP;
486 | animPos = new THREE.Vector3(0, 0 , 2200);
487 | } else {
488 | animPos = this.branches[this.player.branch]._cameraPos;
489 | }
490 |
491 | if(direction == '3d') {
492 | this.camera.up.set(0,0,1);
493 | // if we are entering 3D, go to the player branch
494 | animPos = this.branches[this.player.branch]._cameraPos;
495 | this.player.view = this.player.branch;
496 |
497 | }
498 |
499 | var anim2 = new TWEEN.Tween(this.camera.position).to(animPos, 250)
500 | .easing(TWEEN.Easing.Linear.None)
501 | .onUpdate(function () {
502 | self.camera.lookAt(self.__rotator.position);
503 | })
504 | .start();
505 |
506 | anim2.onComplete(function () {
507 | self.SWITCHING = false;
508 | });
509 | };
510 |
511 |
512 | /**
513 | * handle shooting
514 | */
515 | CoreCommit.prototype.playerShoot = function () {
516 | var self = this,
517 | shootRate = 1200,
518 | shootAt,
519 | geom;
520 |
521 | // TODO: fix this
522 | var crateMaterial = new THREE.MeshBasicMaterial({ color:0xff4747, transparent:true, opacity:1 });
523 |
524 | if (this.player.branch == 0 || this.player.branch == 2) {
525 | geom = new THREE.CubeGeometry(25, 60, 25)
526 | } else {
527 | geom = new THREE.CubeGeometry(60, 25, 25)
528 | }
529 |
530 | var bullet = new THREE.Mesh(THREE.GeometryUtils.clone(geom), crateMaterial);
531 |
532 | bullet.position.set(this.player.mesh.position.x, this.player.mesh.position.y, 0);
533 | bullet.bulletId = self.BULLETS.length;
534 | this.scene.add(bullet);
535 |
536 |
537 | switch (this.player.branch) {
538 | case 0:
539 | shootAt = { y:950 };
540 | break;
541 | case 1:
542 | shootAt = { x:950 };
543 | break;
544 | case 2:
545 | shootAt = { y:-950 };
546 | break;
547 | }
548 |
549 | bullet.tween = new TWEEN.Tween(bullet.position).to(shootAt, shootRate)
550 | .easing(TWEEN.Easing.Linear.None).start();
551 |
552 | bullet.tween.onComplete(function () {
553 | if (bullet) {
554 | self.BULLETS = _.without(self.BULLETS, bullet);
555 | self.scene.remove(bullet);
556 | }
557 | });
558 |
559 | self.BULLETS.push(bullet);
560 | };
561 |
562 |
563 | /**
564 | * Generate game crates
565 | */
566 | CoreCommit.prototype.generateCrates = function () {
567 | var self = this,
568 | textureFile,
569 | regularCrate = false,
570 | crateType,
571 | cStartDistance = 3100,
572 | extraDistance = 0;
573 |
574 | this.CRATES_GENERATING = true;
575 |
576 | // decide if we want to create a special crate
577 | var lucky = parseInt(Math.random() * 50, 10); // random between 0 - 5
578 | if (lucky < 10) {
579 | // set the lucky crate type
580 | crateType = parseInt(Math.random() * 2, 10); // random between 0 =>< 3
581 | textureFile = self.otherCrateList[crateType];
582 | regularCrate = false;
583 | if (crateType == 1) { // if it is a star
584 | extraDistance = 95;
585 | }
586 | } else {
587 | // create a branch create
588 | regularCrate = true;
589 | crateType = parseInt(Math.random() * 5, 10); // random between 0 - 5
590 | textureFile = self.branchCrateList[crateType];
591 | }
592 |
593 | this.__CRATE_SIZE = (this.__CRATE_SIZE >= 50) ? --this.__CRATE_SIZE : 50;
594 | var size = this.__CRATE_SIZE;
595 | // crate mesh
596 | var crateMaterial = new THREE.MeshBasicMaterial({ map:textureFile }),
597 | crate = new THREE.Mesh(THREE.GeometryUtils.clone(new THREE.CubeGeometry(size, size, size)), crateMaterial);
598 |
599 | // crate points
600 | var landingPointTween,
601 | startingP = Math.floor(Math.random() * 931) - 465, // random starting point
602 | landingRandomPoint = Math.floor(Math.random() * 931) - 465; // random landing point
603 |
604 | // depending on the branch, the starting point should be different
605 | // also define the tween to fly properly
606 | if (this.GAME_BRANCH == 0) { // from the right
607 | crate.position.set(startingP, cStartDistance, 0);
608 | landingPointTween = { x:landingRandomPoint, y:-485 - extraDistance };
609 | }
610 | else if (this.GAME_BRANCH == 1) { // from the top
611 | crate.position.set(cStartDistance, startingP, 0);
612 | landingPointTween = { x:-485 - extraDistance, y:landingRandomPoint };
613 | }
614 | else if (this.GAME_BRANCH == 2) { // from the bottom
615 | crate.position.set(startingP, -cStartDistance, 0);
616 | landingPointTween = { x:landingRandomPoint, y:485 + extraDistance };
617 | }
618 |
619 | crate.regularCrate = regularCrate;
620 | crate.type = crateType;
621 | crate.dead = false;
622 | crate.targetPosition = landingPointTween;
623 |
624 | // set the targetBranch
625 | var tb;
626 | if ((crate.type == 4) || (crate.type == 5)) tb = 0;
627 | if ((crate.type == 2) || (crate.type == 3)) tb = 1;
628 | if ((crate.type == 0) || (crate.type == 1)) tb = 2;
629 |
630 | crate.branch = tb;
631 | crate.targetBranch = this.GAME_BRANCH;
632 | crate.goodCrate = !!((this.GAME_BRANCH == tb));
633 | this.scene.add(crate);
634 |
635 | crate.animation = new TWEEN.Tween(crate.position)
636 | .to(landingPointTween, this.SPEED).start();
637 |
638 | crate.animation.onComplete(function () { // the crate is landing
639 | if (crate) {
640 | self.scene.remove(crate);
641 | self.CRATES = _.without(self.CRATES, crate);
642 | self.checkCrateLanding(crate);
643 | }
644 | });
645 |
646 | this.CRATES.push(crate);
647 | };
648 |
649 |
650 | /**
651 | * Checking if the landed crate is in the the right branch
652 | * checking if the player captured the crate
653 | */
654 | CoreCommit.prototype.checkCrateLanding = function (crate) {
655 | var pl = this.player.mesh;
656 |
657 | // branch switcher
658 | if (!crate.regularCrate && crate.type == 0) {
659 | this.gameSwitchBranch();
660 | }
661 |
662 | // star
663 | if (!crate.regularCrate && crate.type == 1) {
664 | if (pl.position.x) {
665 | var originPoint = pl.position.clone();
666 |
667 | for (var vertexIndex = 0; vertexIndex < pl.geometry.vertices.length; vertexIndex++) {
668 | var localVertex = pl.geometry.vertices[vertexIndex].clone();
669 | var globalVertex = pl.matrix.multiplyVector3(localVertex);
670 | var directionVector = globalVertex.subSelf(pl.position);
671 |
672 | var ray = new THREE.Ray(originPoint, directionVector.clone().normalize());
673 | var collisionResults = ray.intersectObject(crate);
674 |
675 | // if the player position is close to a crate, the player captures it.
676 | if (collisionResults.length > 0 &&
677 | collisionResults[0].distance < directionVector.length()) {
678 | this.SESSION.STARS++;
679 | this.dispatchEvent(this.sendSessionEvent);
680 | this.branches[crate.targetBranch].commit();
681 | this.collectStar(crate);
682 | break;
683 | }
684 | }
685 | }
686 | }
687 |
688 | // regular crates
689 | if ((!crate.dead) && crate.regularCrate) {
690 | if ((crate.targetBranch != crate.branch)) {
691 | // if the crate is not dead, and if it does not match a proper branch
692 | this.decreaseLife();
693 | // bad collision, add effects to this branch
694 | this.branches[crate.targetBranch].hit();
695 | } else {
696 | this.SESSION.COMMITS++;
697 | this.dispatchEvent(this.sendSessionEvent);
698 | this.collectStar(crate);
699 | }
700 | }
701 | };
702 |
703 |
704 | /**
705 | * decreaseLife
706 | */
707 | CoreCommit.prototype.decreaseLife = function () {
708 | this.LIFE -= 10;
709 | // TODO: fix this.
710 | var e = {type:'decreaseLife', data:this.LIFE };
711 | this.dispatchEvent(e);
712 | };
713 |
714 |
715 | /**
716 | * collectStar
717 | */
718 | CoreCommit.prototype.collectStar = function (crate) {
719 | var self = this,
720 | starMesh = crate.material,
721 | starCollect = new THREE.Mesh(THREE.GeometryUtils.clone(new THREE.CubeGeometry(50, 50, 50)), starMesh);
722 |
723 | starCollect.position.set(crate.targetPosition.x, crate.targetPosition.y, 0);
724 | this.scene.add(starCollect);
725 | var cP = this.camera.position;
726 | var cameraPos = new THREE.Vector3(cP.x, cP.y, cP.z);
727 | cameraPos.x -= 200;
728 | starCollect.animation = new TWEEN.Tween(starCollect.position)
729 | .to(cameraPos, 500)
730 | .easing(TWEEN.Easing.Quadratic.Out)
731 | .start();
732 |
733 | starCollect.animation.onComplete(function () {
734 | if (starCollect) {
735 | self.scene.remove(starCollect);
736 | }
737 | });
738 | };
739 |
740 |
741 | /**
742 | * teleportPlayer between branch positions
743 | */
744 | CoreCommit.prototype.teleportPlayer = function (branch, direction) {
745 | var self = this;
746 |
747 | this._teleporting = true;
748 | // depending on which branch you are on, clockwise teleport between branches
749 | if (branch != null) {
750 | this.player.branch = branch;
751 | } else {
752 | if (direction == "left") {
753 | this.player.branch = (this.player.branch == 0) ? 2 : this.player.branch - 1;
754 | } else {
755 | this.player.branch = (this.player.branch == 2) ? 0 : this.player.branch + 1;
756 | }
757 | }
758 | var r = new TWEEN.Tween(this.player.mesh.position)
759 | .to(this.branches[this.player.branch].getCenter(), 300)
760 | .easing(TWEEN.Easing.Back.InOut).start();
761 |
762 | r.onComplete(function () {
763 | self.player.changeTexture(self.player.branch);
764 | self._teleporting = false;
765 | });
766 | };
767 |
768 |
769 |
770 | /**
771 | * Create Game Branches
772 | */
773 | CoreCommit.prototype.generateBranches = function () {
774 | this.branches = [
775 | // posX, posY, posZ, color, cameraPos, cameraLookAtPos, playerShift
776 | new Branch(0, -480, 50, 0xd23aa1, new THREE.Vector3(0, -1600, 900), new THREE.Vector3(0, 1000, -100), -75), // purple
777 | new Branch(-480, 0, 50, 0xffb139, new THREE.Vector3(-1600, 0, 900), new THREE.Vector3(1000, 0, -100), -75), // orange
778 | new Branch(0, 480, 50, 0x2bc3db, new THREE.Vector3(0, 1600, 900), new THREE.Vector3(0, -1000, 220), 75) // teal
779 | ];
780 |
781 | this.branches[0].mesh.rotation.z = 90 * Math.PI / 180;
782 | this.branches[2].mesh.rotation.z = 90 * Math.PI / 180;
783 |
784 | this.branches[this.GAME_BRANCH].setCurrent();
785 |
786 | this.scene.add(this.branches[0].mesh);
787 | this.scene.add(this.branches[1].mesh);
788 | this.scene.add(this.branches[2].mesh);
789 |
790 | };
791 |
792 |
793 | /**
794 | * Load crate textures
795 | */
796 | CoreCommit.prototype.loadTextures = function () {
797 |
798 | // Code crate textures
799 | this.branchCrateList = [
800 | new THREE.ImageUtils.loadTexture('img/crTealPCode.png'), // 0
801 | new THREE.ImageUtils.loadTexture('img/crTealMCode.png'), // 1
802 | new THREE.ImageUtils.loadTexture('img/crOrangePCode.png'), // 2
803 | new THREE.ImageUtils.loadTexture('img/crOrangeMCode.png'), // 3
804 | new THREE.ImageUtils.loadTexture('img/crPurplePCode.png'), // 4
805 | new THREE.ImageUtils.loadTexture('img/crPurplePCode.png') // 5
806 | ];
807 |
808 | // Other crate textures
809 | this.otherCrateList = [
810 | new THREE.ImageUtils.loadTexture('img/crPR.png'), // 0
811 | new THREE.ImageUtils.loadTexture('img/crStar.png') // 1
812 | ];
813 | };
814 |
815 |
816 | /**
817 | * Setup custom events
818 | */
819 | CoreCommit.prototype.addCustomEvents = function () {
820 | this.sendSessionEvent = new CustomEvent('session', { 'detail':this.SESSION });
821 | this.gameOverEvent = new CustomEvent('gameOver', { 'detail':this.SESSION });
822 | };
823 |
824 |
825 | /**
826 | * Setup custom events
827 | */
828 | CoreCommit.prototype.setGameVariables = function (project) {
829 | // game session
830 | this.SESSION = {
831 | START_TIME:Date.now(), END_TIME:Date.now(), LEVEL:0, STARS:0, COMMITS:0, GAMEOVER:false,
832 | SWITCHED_BRANCH:0, PROJECT:project
833 | };
834 |
835 | // types of views
836 | this.VIEW = {TOP:4, CENTER:1, LEFT:2, RIGHT:0};
837 |
838 | // game branch
839 | this.GAME_BRANCH = 1; // current git branch bottom - 0, left - 1, top - 2
840 |
841 | // create a counter for frames
842 | this.FRAME = 0;
843 | this.SPEED = 25000;
844 | this.__CRATE_RATE = 145;
845 | this.__CRATE_SIZE = 100;
846 |
847 | // a timer for crates
848 | this.NEW_CRATE_TIMER = 0;
849 | // a timer for bullets
850 | this.NEW_BULLET = 0;
851 | this.AMMO = true;
852 |
853 | // paused state
854 | this.PAUSED = false;
855 |
856 | // enable keyboard plugin
857 | this.keyboard = new THREEx.KeyboardState();
858 |
859 | // setup player life level
860 | this.LIFE = 100;
861 |
862 | // CAMERA
863 | this.SCREEN_WIDTH = window.innerWidth;
864 | this.SCREEN_HEIGHT = window.innerHeight;
865 |
866 |
867 | this.BULLETS = []; // track bullets
868 | this.CRATES = []; // track crates
869 | };
870 |
871 |
872 | /**
873 | * Object that during their initialization can call this function
874 | * This will extend the calling object with basic
875 | * Event Dispatching functionality
876 | *
877 | */
878 | CoreCommit.prototype.extendAsEventDispatcher = function () {
879 | if (this._listeners == null) {
880 | this._listeners = [];
881 | }
882 | this.isEventDispatcher = true;
883 | if (typeof(this.dispatchEvent) == 'undefined') {
884 | this.dispatchEvent = function (eventObject) {
885 | for (var i = 0; i < this._listeners.length; i++) {
886 | var test = this._listeners[i];
887 | if (test.type === eventObject.type) {
888 | test.callback(eventObject);
889 | break;
890 | }
891 | }
892 | };
893 | }
894 | if (typeof(this.addEventListener) == 'undefined') {
895 | this.addEventListener = function (type, callback, capture) {
896 | // no dupes
897 | var declared = false;
898 | for (var i = 0; i < this._listeners.length; i++) {
899 | var test = this._listeners[i];
900 | if (test.type === type && test.callback === callback) {
901 | declared = true;
902 | break;
903 | }
904 | }
905 | if (!declared) {
906 | this._listeners.push({'type':type, 'callback':callback, 'capture':capture});
907 | }
908 | };
909 | }
910 | };
911 |
912 | exports.CoreCommit = CoreCommit;
913 |
914 | })(window);
915 |
--------------------------------------------------------------------------------
/app/client/js/game/Menu.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome Notice
3 | */
4 | Template.welcome.events({
5 | 'click .continue': function () {
6 | $('.req-welcome').animate({ top: PX_HIDE }, PX_SPEED, function() {
7 | $('.req-tutorial').animate({ top: PX_SHOW });
8 | });
9 | }
10 | });
11 |
12 |
13 | /**
14 | * Project Choice
15 | */
16 | Template.choose.events({
17 | 'click .project': function (event, template) {
18 | Session.set("pid", this._id);
19 |
20 | $('.req-project').animate({ top: PX_HIDE }, PX_SPEED, function() { });
21 | startGame();
22 |
23 | return false;
24 | }
25 | });
26 |
27 |
28 | /**
29 | * Welcome Notice
30 | */
31 | Template.tutorial.events({
32 | 'click .continue': function () {
33 | $('.req-tutorial').animate({ top: PX_HIDE }, PX_SPEED, function() {
34 | $('.req-project').animate({ top: PX_SHOW });
35 | });
36 | }
37 | });
38 |
39 | Template.help.status = function () {
40 | return Session.get('gamepadStatus');
41 | };
42 |
43 | Template.help.musicStatus = function () {
44 | return Session.get('musicStatus');
45 | };
46 |
47 |
48 | /**
49 | * Project Choice
50 | */
51 | Template.help.events({
52 | 'click .music': function (event, template) {
53 | if (Session.equals('musicStatus', 'on')) {
54 | Session.set('musicStatus', 'off');
55 | MUSIC.pause();
56 | } else {
57 | Session.set('musicStatus', 'on');
58 | if (Session.get('gameOn')) {
59 | MUSIC.play();
60 | }
61 | }
62 | }
63 | });
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/client/js/game/MenuDashboard.js:
--------------------------------------------------------------------------------
1 | Template.dashboard.stars = function () {
2 | var stars = Session.get('sessionStars');
3 | return (stars) ? stars : 0;
4 | };
5 |
6 |
7 | Template.dashboard.project = function () {
8 | var p = Projects.findOne({_id:Session.get('pid')});
9 | if (p && p.name) {
10 | return p.name
11 | } else {
12 | return 'a project'
13 | }
14 | };
15 |
16 |
17 | Template.dashboard.commits = function () {
18 | var commits = Session.get('sessionCommits');
19 | return (commits) ? commits : 0;
20 | };
21 |
22 |
23 | Template.dashboard.level = function () {
24 | var lvl = Session.get('sessionLevel');
25 | return (lvl) ? lvl : 0;
26 |
27 | };
28 |
29 | Template.dashboard.rendered = function(){
30 | // quick hack.
31 | var s = Session.get('sessionLevel'),
32 | b = Session.get('sessionLevelBackup');
33 |
34 | if (s != b) {
35 | Session.set("sessionLevelBackup", s);
36 | $('.level').fadeIn(300).delay(500).fadeOut(400);
37 | }
38 | };
39 |
40 |
41 | Template.level.count = function () {
42 | var lvl = Session.get('sessionLevel');
43 | return (lvl) ? lvl : 0;
44 |
45 | };
46 |
47 |
--------------------------------------------------------------------------------
/app/client/js/game/MenuGameover.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Return currently logged in user
3 | */
4 | Template.gameover.user = function() {
5 | return Meteor.user();
6 | };
7 |
8 |
9 | /**
10 | * Show game stats
11 | */
12 | Template.gameover.stats = function() {
13 | return Session.get('stats');
14 | };
15 |
16 |
17 | /**
18 | * List the projects for the gameover menu
19 | */
20 | Template.gameover.list = function() {
21 | return Projects.find();
22 | };
23 |
24 |
25 | /**
26 | * Game Over Notice
27 | */
28 | Template.gameover.events({
29 | 'click .again': function () {
30 | window.location.reload();
31 | }
32 | });
33 |
--------------------------------------------------------------------------------
/app/client/js/game/MenuProjects.js:
--------------------------------------------------------------------------------
1 | /**
2 | * List the project for the choosing menu
3 | */
4 | Template.projects.list = function() {
5 | return Projects.find();
6 | };
7 |
8 | /**
9 | * Chosen project id
10 | */
11 | Template.projects.selected = function() {
12 | return Session.get('pid');
13 | };
14 |
15 |
--------------------------------------------------------------------------------
/app/client/js/game/MenuWebgl.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * WebGl Notice
4 | */
5 | Template.webgl.events({
6 | 'click .continue': function () {
7 | $('.req-webgl').animate({ top: PX_HIDE }, PX_SPEED, function() {
8 | $('.req-welcome').animate({ top: PX_SHOW });
9 | });
10 | }
11 | });
--------------------------------------------------------------------------------
/app/client/js/game/SoundTrack.js:
--------------------------------------------------------------------------------
1 | (function (exports) {
2 |
3 | var SoundTrack = function () {
4 | var self = this;
5 | this.audio = new Audio();
6 | var tracks = [
7 | "music/0.ogg",
8 | "music/1.ogg",
9 | "music/2.ogg"
10 | ];
11 | this.audio.src = tracks[parseInt(Math.random() * 3, 10)];
12 | this.audio.volume = 0.1;
13 | this.audio.addEventListener('ended', function() {
14 | self.audio.src = tracks[parseInt(Math.random() * 3, 10)];
15 | self.play();
16 | }, false);
17 | };
18 |
19 | SoundTrack.prototype.play = function() {
20 | this.audio.play();
21 | };
22 |
23 | SoundTrack.prototype.pause = function() {
24 | this.audio.pause();
25 | };
26 |
27 | exports.SoundTrack = SoundTrack;
28 | })(window);
29 |
--------------------------------------------------------------------------------
/app/client/js/game/Stats.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Show game stats
3 | */
4 | Template.recentScores.list = function() {
5 | // the server controls the limit, but we are forcing it here as well.
6 | return RecentScores.find().fetch().slice(0,8);
7 | };
8 |
9 |
10 | /**
11 | * Show top scores
12 | */
13 | Template.topScores.list = function() {
14 | return TopScores.find().fetch().slice(0,8);
15 | };
--------------------------------------------------------------------------------
/app/client/js/game/resources/Branch.js:
--------------------------------------------------------------------------------
1 | (function (exports) {
2 |
3 | /**
4 | * Game Branch
5 | * @param posX
6 | * @param posY
7 | * @param posZ
8 | * @param color
9 | * @param cameraPos
10 | * @param cameraLookAtPos
11 | * @constructor
12 | */
13 | var Branch = function (posX, posY, posZ, color, cameraPos, cameraLookAtPos, playerShift) {
14 | this._posX = posX;
15 | this._posY = posY;
16 | this._posZ = posZ;
17 | this._cameraPos = cameraPos;
18 | this._cameraLookAtPos = cameraLookAtPos;
19 | this._orientation = (posY == 0) ? 'x' : 'y';
20 | this._playerShift = playerShift;
21 |
22 | // branch 1 - left
23 | this.mesh = new THREE.Mesh(
24 | THREE.GeometryUtils.clone(new THREE.CubeGeometry(60, 900, 120)),
25 | new THREE.MeshBasicMaterial({ color:color, transparent:true, opacity:0.35 }));
26 | this.mesh.position.set(posX, posY, posZ);
27 | };
28 |
29 |
30 | /**
31 | * Branch hit by an object
32 | */
33 | Branch.prototype.hit = function () {
34 | if (!this._animated) {
35 | this._animated = true;
36 | this._end = new Date(Date.now() + 500);
37 | this._anim();
38 | }
39 | };
40 |
41 |
42 | /**
43 | * Set this branch as current
44 | */
45 | Branch.prototype.setCurrent = function () {
46 | this.current = true;
47 | this.mesh.material.opacity = 1.0;
48 | };
49 |
50 |
51 | /**
52 | * Unset this branch as current
53 | */
54 | Branch.prototype.unsetCurrent = function () {
55 | this.current = false;
56 | this.mesh.material.opacity = 0.35;
57 | };
58 |
59 |
60 | /**
61 | * Animate the branch hit
62 | * @private
63 | */
64 | Branch.prototype._anim = function () {
65 | var self = this;
66 |
67 | var timer = Date.now() * 0.01; // SPEED
68 | var cos = Math.cos(timer); // Amp
69 | //this.mesh.position.x += (cos > 0) ? -0.3 : 0.3;
70 | this.mesh.material.opacity = Math.abs(cos);
71 | if (this._end < Date.now()) {
72 | this._animated = false;
73 |
74 | this.mesh.material.opacity = (this.current) ? 1.0 : 0.35 ;
75 | }
76 |
77 | if (this._animated) window.requestAnimFrame(this._anim.bind(this));
78 | };
79 |
80 |
81 | Branch.prototype.commit = function () {
82 | // opacity up?
83 | };
84 |
85 |
86 | /**
87 | * Get the center position for the player teleport
88 | * @return {Object}
89 | */
90 | Branch.prototype.getCenter = function () {
91 | // TODO: patch this.
92 | if (this._orientation == 'y') {
93 | return {x: this._posX, y: this._posY + this._playerShift, z: this._posZ};
94 | } else {
95 | return {x: this._posX + this._playerShift, y: this._posY, z: this._posZ};
96 | }
97 | };
98 |
99 | exports.Branch = Branch;
100 | })(window);
101 |
--------------------------------------------------------------------------------
/app/client/js/game/resources/GamepadSupport.js:
--------------------------------------------------------------------------------
1 | (function (exports) {
2 |
3 |
4 | var GamepadSupport = function () {
5 |
6 | window.addEventListener('MozGamepadConnected', this.onGamepadConnect, false);
7 | window.addEventListener('MozGamepadDisconnected', this.onGamepadDisconnect, false);
8 | this.prevRawGamepadTypes = []
9 | };
10 |
11 | /**
12 | * Enable gamepad support if available
13 | */
14 | GamepadSupport.prototype.checkGamepadSupport = function () {
15 |
16 | if (Modernizr.gamepads) {
17 | var rawGamepads =
18 | (navigator.webkitGetGamepads && navigator.webkitGetGamepads()) || navigator.webkitGamepads;
19 |
20 | if (rawGamepads) {
21 | this.GAMEPADS = [];
22 | if (typeof rawGamepads[i] != this.prevRawGamepadTypes[i]) {
23 | //this.dispatchEvent('gamepadConnected');
24 | //console.log('gamepadConnected');
25 | for (var i = 0; i < rawGamepads.length; i++) {
26 | if (rawGamepads[i]) {
27 | this.GAMEPADS.push(rawGamepads[i]);
28 | }
29 | }
30 | }
31 | }
32 | }
33 | };
34 |
35 |
36 | /**
37 | * onGamepadConnect
38 | * @type {Function}
39 | */
40 | GamepadSupport.prototype.onGamepadConnect = function (event) {
41 | this.dispatchEvent('gamepadConnected');
42 | this.GAMEPADS.push(event.gamepad);
43 | };
44 |
45 |
46 | /**
47 | * onGamepadConnect
48 | * @param event
49 | */
50 | GamepadSupport.prototype.onGamepadDisconnect = function (event) {
51 | for (var i in this.GAMEPADS) {
52 | if (this.GAMEPADS[i].index == event.gamepad.index) {
53 | this.GAMEPADS.splice(i, 1);
54 | break;
55 | }
56 | }
57 | //console.log('gamepadDisconnected');
58 | //this.dispatchEvent('gamepadDisconnected');
59 | };
60 |
61 | exports.GamepadSupport = GamepadSupport;
62 | })(window);
63 |
--------------------------------------------------------------------------------
/app/client/js/game/resources/Player.js:
--------------------------------------------------------------------------------
1 | (function (exports) {
2 |
3 | /**
4 | * Setup the game player
5 | * @constructor
6 | */
7 | var Player = function () {
8 | this.branch = 1;
9 | this.branchTexture = [
10 | new THREE.ImageUtils.loadTexture('img/player0.png'),
11 | new THREE.ImageUtils.loadTexture('img/player1.png'),
12 | new THREE.ImageUtils.loadTexture('img/player2.png')
13 | ]
14 | var crateTexture = this.branchTexture[1];
15 | this.mesh = new THREE.Mesh(
16 | THREE.GeometryUtils.clone( new THREE.CubeGeometry(90, 90, 90) ),
17 | new THREE.MeshBasicMaterial({ map:crateTexture })
18 | );
19 | this.mesh.position.set(-550, 0, 50);
20 | };
21 |
22 | // TODO: clean this up;
23 | /**
24 | * Move player up / left
25 | * @type {Function}
26 | */
27 | Player.prototype.moveUpLeft = function (branch, view) {
28 | var pl = this.mesh,
29 | axis;
30 | axis = (branch == 1) ? pl.position.y : pl.position.x;
31 |
32 | if (axis > -435 && axis < 435) {
33 | if (branch == 1) {
34 | if (axis != 420 ) pl.position.y += 15
35 | } else {
36 | // TODO: fix quick hack here
37 |
38 | if (this.view == 2 && this.branch == 2 && axis != 420) {
39 | pl.position.x += 15;
40 | } else if (axis != -420) {
41 | pl.position.x -= 15;
42 | }
43 | }
44 | }
45 | };
46 |
47 |
48 | /**
49 | * Move player down / right
50 | */
51 | Player.prototype.moveDownRight = function (branch, view) {
52 | var pl = this.mesh,
53 | axis;
54 | axis = (branch == 1) ? pl.position.y : pl.position.x;
55 |
56 |
57 | if (axis > -435 && axis < 435) {
58 | if (branch == 1) {
59 | if (axis != -420 ) pl.position.y -= 15
60 | } else {
61 | // TODO: fix quick hack here
62 |
63 | if (this.view == 2 && this.branch == 2 && axis != -420) {
64 | pl.position.x -= 15;
65 | } else if (axis != 420 ) {
66 | pl.position.x += 15;
67 | }
68 | }
69 | }
70 | };
71 |
72 | /**
73 | * Player change texture
74 | * @type {Function}
75 | */
76 | Player.prototype.changeTexture = function (branch) {
77 | this.mesh.material.map = this.branchTexture[branch];
78 | };
79 |
80 | exports.Player = Player;
81 | })(window);
82 |
--------------------------------------------------------------------------------
/app/client/lib/lodash.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Lo-Dash 0.8.2 lodash.com/license
3 | Underscore.js 1.4.2 underscorejs.org/LICENSE
4 | */
5 | ;(function(e,t){function s(e){if(e&&e.__wrapped__)return e;if(!(this instanceof s))return new s(e);this.__wrapped__=e}function o(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||H),s=i?{}:e;if(i)for(n=t-1;++nn||e===t)return 1;if(es;s++)i+="i='"+e.o[s]+"';if(","constructor"==e.o[s]&&(i+="!(g&&g.prototype===j)&&"),i+="h.call(j,i)){A=j[i];"+
9 | e.l.h+"}"}if(e.c||e.m)i+="}"}return i+=e.e+";return t",Function("D,E,F,I,e,f,J,h,M,O,Q,S,T,X,Y,l,q,v,w,y,z","var G=function("+t+"){"+i+"};return G")(Dt,_,L,u,Q,f,en,Z,T,v,$t,m,Jt,mt,Ht,ut,tt,nt,yt,rt)}function c(e){return"\\"+Bt[e]}function h(e){return Qt[e]}function p(){}function d(e){return Gt[e]}function v(e){return rt.call(e)==ct}function m(e){return"function"==typeof e}function g(e){var t=i;if(!e||"object"!=typeof e||v(e))return t;var n=e.constructor;return(!Lt||"function"==typeof e.toString||"string"!=typeof
10 | (e+""))&&(!m(n)||n instanceof n)?xt?(en(e,function(e,n,r){return t=!Z.call(r,n),i}),t===i):(en(e,function(e,n){t=n}),t===i||Z.call(e,t)):t}function y(e,t,n,s,o){if(e==r)return e;n&&(t=i);if(n=Ht[typeof e]){var u=rt.call(e);if(!Pt[u]||Nt&&v(e))return e;var a=u==ht,n=a||(u==mt?Jt(e):n)}if(!n||!t)return n?a?nt.call(e):Zt({},e):e;n=e.constructor;switch(u){case pt:case dt:return new n(+e);case vt:case yt:return new n(e);case gt:return n(e.source,U.exec(e))}s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[
11 | u]==e)return o[u];var f=a?n(e.length):{};return s.push(e),o.push(f),(a?mn:tn)(e,function(e,n){f[n]=y(e,t,r,s,o)}),f}function b(e,t,s,o){if(e==r||t==r)return e===t;if(e===t)return 0!==e||1/e==1/t;if(Ht[typeof e]||Ht[typeof t])e=e.__wrapped__||e,t=t.__wrapped__||t;var u=rt.call(e);if(u!=rt.call(t))return i;switch(u){case pt:case dt:return+e==+t;case vt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case gt:case yt:return e==t+""}var a=Dt[u];if(Nt&&!a&&(a=v(e))&&!v(t)||!a&&(u!=mt||Lt&&("function"!=typeof e.
12 | toString&&"string"==typeof (e+"")||"function"!=typeof t.toString&&"string"==typeof (t+""))))return i;s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var u=-1,f=n,l=0;s.push(e),o.push(t);if(a){l=e.length;if(f=l==t.length)for(;l--&&(f=b(e[l],t[l],s,o)););return f}a=e.constructor,f=t.constructor;if(a!=f&&(!m(a)||!(a instanceof a&&m(f)&&f instanceof f)))return i;for(var c in e)if(Z.call(e,c)&&(l++,!Z.call(t,c)||!b(e[c],t[c],s,o)))return i;for(c in t)if(Z.call(t,c)&&!(l--))return i;if(
13 | Et)for(;7>++u;)if(c=J[u],Z.call(e,c)&&(!Z.call(t,c)||!b(e[c],t[c],s,o)))return i;return n}function w(e,t,n){var r=-Infinity,i=-1,s=e?e.length:0,o=r;if(t||s!==+s)t=f(t,n),mn(e,function(e,n,i){n=t(e,n,i),n>r&&(r=n,o=e)});else for(;++io&&(o=e[i]);return o}function E(e,t,n,r){var s=e,o=e?e.length:0,u=3>arguments.length;if(o!==+o)var a=sn(e),o=a.length;else kt&&rt.call(e)==yt&&(s=e.split(""));return mn(e,function(e,f,l){f=a?a[--o]:--o,n=u?(u=i,s[f]):t.call(r,n,s[f],f,l)}),n}function S(e,t,n){
14 | if(e)return t==r||n?e[0]:nt.call(e,0,t)}function x(e,t){for(var n=-1,r=e?e.length:0,i=[];++nn?at(0,i+n):n||0)-1;else if(n)return r=C(e,t),e[r]===t?r:-1;for(;++r>>1,n(e[r])>>1,e[r]T(a,r))a.push(r),u.push(e[s]);return u}function L(e,t){return Ot||it&&2|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,F=/&(?:amp|lt|gt|quot|#x27);/g,I=/\b__p\+='';/g,q=/\b(__p\+=)''\+/g,R=/(__e\(.*?\)|\b__t\))\+'';/g,U=/\w*$/,z=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,W=RegExp("^"+(D.valueOf+""
17 | ).replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),X=/($^)/,V=/[&<>"']/g,$=/['\n\r\t\u2028\u2029\\]/g,J="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),K=Math.ceil,Q=_.concat,G=Math.floor,Y=W.test(Y=Object.getPrototypeOf)&&Y,Z=D.hasOwnProperty,et=_.push,tt=D.propertyIsEnumerable,nt=_.slice,rt=D.toString,it=W.test(it=nt.bind)&&it,st=W.test(st=Array.isArray)&&st,ot=e.isFinite,ut=W.test(ut=Object.keys)&&ut
18 | ,at=Math.max,ft=Math.min,lt=Math.random,ct="[object Arguments]",ht="[object Array]",pt="[object Boolean]",dt="[object Date]",vt="[object Number]",mt="[object Object]",gt="[object RegExp]",yt="[object String]",bt=e.clearTimeout,wt=e.setTimeout,Et,St,xt,Tt=n;(function(){function e(){this.x=1}var t={0:1,length:1},n=[];e.prototype={valueOf:1,y:1};for(var r in new e)n.push(r);for(r in arguments)Tt=!r;Et=4>(n+"").length,xt="x"!=n[0],St=(n.splice.call(t,0,1),t[0])})(1);var Nt=!v(arguments),Ct="x"!=nt.call("x"
19 | )[0],kt="xx"!="x"[0]+Object("x")[0];try{var Lt=("[object Object]",rt.call(e.document||0)==mt)}catch(At){}var Ot=it&&/\n|Opera/.test(it+rt.call(e.opera)),Mt=ut&&/^.+$|true/.test(ut+!!e.attachEvent),_t=!Ot,Dt={};Dt[pt]=Dt[dt]=Dt["[object Function]"]=Dt[vt]=Dt[mt]=Dt[gt]=i,Dt[ct]=Dt[ht]=Dt[yt]=n;var Pt={};Pt[ct]=Pt["[object Function]"]=i,Pt[ht]=Pt[pt]=Pt[dt]=Pt[vt]=Pt[mt]=Pt[gt]=Pt[yt]=n;var Ht={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},Bt={"\\":"\\","'":"'","\n":"n"
20 | ,"\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};s.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""};var jt={a:"d,c,x",p:"c=f(c,x)",h:"if(c(A,i,d)===false)return t"},Ft={i:"{}",p:"c=f(c,x)",h:"var p=c(A,i,d);(h.call(t,p)?t[p]++:t[p]=1)"},It={i:"true",h:"if(!c(A,i,d))return!t"},qt={q:i,r:i,a:"m",p:"for(var a=1,b=arguments.length;a":">",'"':""","'":"'"},Gt=Vt(Qt),Yt=l(qt,{h:"if(t[i]==null)"+qt.h}),Zt=l(qt),en=l(jt,Ut,zt,{q:i}),tn=l(jt,Ut,zt),nn=l({q:i,a:"m",i:"[]",h:"S(A)&&t.push(i)",e:"t.sort()"}),rn=l({a:"A",i:"true",p:"var H=y.call(A),k=A.length;if(D[H]"+(Nt?"||O(A)":"")+"||(H==X&&k===+k&&S(A.splice)))return!k",h:{k:"return false"}}),sn=ut?function(
23 | e){var t=typeof e;return"function"==t&&tt.call(e,"prototype")?Kt(e):e&&Ht[t]?ut(e):[]}:Kt,on=l(qt,{a:"m,dd,N",p:"var P,C=arguments,a=0;if(N==I){var b=2,ee=C[3],ff=C[4]}else var b=C.length,ee=[],ff=[];while(++a-1"},h:"if(A===hh)return true"}),hn=l(jt,Ft),pn=l(jt,It),dn=l(jt,Rt),vn=l(jt,Ut,{i:"z",h:"if(c(A,i,d))return A"}),mn=l(jt,Ut),gn=l(jt,Ft,{h:"var p=c(A,i,d);(h.call(t,p)?t[p]:t[p]=[]).push(A)"}),yn=l(Wt,{a:"d,U"
25 | ,p:"var C=v.call(arguments,2),R=typeof U=='function'",h:{b:"t[i]=(R?U:A[U]).apply(A,C)",k:"t"+(Mt?"[n]=":".push")+"((R?U:A[U]).apply(A,C))"}}),bn=l(jt,Wt),wn=l(Wt,{a:"d,bb",h:{b:"t[i]=A[bb]",k:"t"+(Mt?"[n]=":".push")+"(A[bb])"}}),En=l({a:"d,c,B,x",i:"B",p:"var V=arguments.length<3;c=f(c,x)",d:{b:"if(V)t=j[++i]"},h:{b:"t=c(t,A,i,d)",k:"t=V?(V=false,A):c(t,A,i,d)"}}),Sn=l(jt,Rt,{h:"!"+Rt.h}),xn=l(jt,It,{i:"false",h:It.h.replace("!","")}),Tn=l(jt,Ft,Wt,{h:{b:"t[i]={a:c(A,i,d),b:i,c:A}",k:"t"+(Mt?"[n]="
26 | :".push")+"({a:c(A,i,d),b:i,c:A})"},e:"t.sort(I);k=t.length;while(k--)t[k]=t[k].c"}),Nn=l(Rt,{a:"d,aa",p:"var s=[];J(aa,function(A,p){s.push(p)});var cc=s.length",h:"for(var Z=true,r=0;r1){while(++ie?t():function(){if(1>--e)return t.apply(this,arguments)}},s.bind=L,s.bindAll=
27 | Cn,s.chain=function(e){return e=new s(e),e.__chain__=n,e},s.clone=y,s.compact=function(e){for(var t=-1,n=e?e.length:0,r=[];++tT(s,u)){for(var a=1;an?at(0,r+n):ft(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},s.lateBind=function(e,t){return a(t,e,nt.call(arguments,2))},s.map=bn,s.max=w,s.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return Z.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},s.merge=on,s.min=function(e,t,n){var r=
32 | Infinity,i=-1,s=e?e.length:0,o=r;if(t||s!==+s)t=f(t,n),mn(e,function(e,n,i){n=t(e,n,i),n=f?(bt(u),a=r,s=e.apply(o,i)):u||(u=wt(n,f)),s}},s.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++rT(r,i)&&r.push(i)}return r},s.uniq=k,s.uniqueId=function(e){var t=P++;return e?e+t:t},s.values=ln,s.where=Nn,s.without=function(e){for(var t=-1,n=e?e.length:0,r=o(arguments,1,20),i=[];++t', rule, ''].join('');
67 | div.id = mod;
68 | (body ? div : fakeBody).innerHTML += style;
69 | fakeBody.appendChild(div);
70 | if ( !body ) {
71 | fakeBody.style.background = '';
72 | fakeBody.style.overflow = 'hidden';
73 | docOverflow = docElement.style.overflow;
74 | docElement.style.overflow = 'hidden';
75 | docElement.appendChild(fakeBody);
76 | }
77 |
78 | ret = callback(div, rule);
79 | if ( !body ) {
80 | fakeBody.parentNode.removeChild(fakeBody);
81 | docElement.style.overflow = docOverflow;
82 | } else {
83 | div.parentNode.removeChild(div);
84 | }
85 |
86 | return !!ret;
87 |
88 | },
89 |
90 |
91 |
92 | isEventSupported = (function() {
93 |
94 | var TAGNAMES = {
95 | 'select': 'input', 'change': 'input',
96 | 'submit': 'form', 'reset': 'form',
97 | 'error': 'img', 'load': 'img', 'abort': 'img'
98 | };
99 |
100 | function isEventSupported( eventName, element ) {
101 |
102 | element = element || document.createElement(TAGNAMES[eventName] || 'div');
103 | eventName = 'on' + eventName;
104 |
105 | var isSupported = eventName in element;
106 |
107 | if ( !isSupported ) {
108 | if ( !element.setAttribute ) {
109 | element = document.createElement('div');
110 | }
111 | if ( element.setAttribute && element.removeAttribute ) {
112 | element.setAttribute(eventName, '');
113 | isSupported = is(element[eventName], 'function');
114 |
115 | if ( !is(element[eventName], 'undefined') ) {
116 | element[eventName] = undefined;
117 | }
118 | element.removeAttribute(eventName);
119 | }
120 | }
121 |
122 | element = null;
123 | return isSupported;
124 | }
125 | return isEventSupported;
126 | })(),
127 |
128 |
129 | _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
130 |
131 | if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
132 | hasOwnProp = function (object, property) {
133 | return _hasOwnProperty.call(object, property);
134 | };
135 | }
136 | else {
137 | hasOwnProp = function (object, property) {
138 | return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
139 | };
140 | }
141 |
142 |
143 | if (!Function.prototype.bind) {
144 | Function.prototype.bind = function bind(that) {
145 |
146 | var target = this;
147 |
148 | if (typeof target != "function") {
149 | throw new TypeError();
150 | }
151 |
152 | var args = slice.call(arguments, 1),
153 | bound = function () {
154 |
155 | if (this instanceof bound) {
156 |
157 | var F = function(){};
158 | F.prototype = target.prototype;
159 | var self = new F();
160 |
161 | var result = target.apply(
162 | self,
163 | args.concat(slice.call(arguments))
164 | );
165 | if (Object(result) === result) {
166 | return result;
167 | }
168 | return self;
169 |
170 | } else {
171 |
172 | return target.apply(
173 | that,
174 | args.concat(slice.call(arguments))
175 | );
176 |
177 | }
178 |
179 | };
180 |
181 | return bound;
182 | };
183 | }
184 |
185 | function setCss( str ) {
186 | mStyle.cssText = str;
187 | }
188 |
189 | function setCssAll( str1, str2 ) {
190 | return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
191 | }
192 |
193 | function is( obj, type ) {
194 | return typeof obj === type;
195 | }
196 |
197 | function contains( str, substr ) {
198 | return !!~('' + str).indexOf(substr);
199 | }
200 |
201 | function testProps( props, prefixed ) {
202 | for ( var i in props ) {
203 | var prop = props[i];
204 | if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
205 | return prefixed == 'pfx' ? prop : true;
206 | }
207 | }
208 | return false;
209 | }
210 |
211 | function testDOMProps( props, obj, elem ) {
212 | for ( var i in props ) {
213 | var item = obj[props[i]];
214 | if ( item !== undefined) {
215 |
216 | if (elem === false) return props[i];
217 |
218 | if (is(item, 'function')){
219 | return item.bind(elem || obj);
220 | }
221 |
222 | return item;
223 | }
224 | }
225 | return false;
226 | }
227 |
228 | function testPropsAll( prop, prefixed, elem ) {
229 |
230 | var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
231 | props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
232 |
233 | if(is(prefixed, "string") || is(prefixed, "undefined")) {
234 | return testProps(props, prefixed);
235 |
236 | } else {
237 | props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
238 | return testDOMProps(props, prefixed, elem);
239 | }
240 | } tests['flexbox'] = function() {
241 | return testPropsAll('flexWrap');
242 | }; tests['canvas'] = function() {
243 | var elem = document.createElement('canvas');
244 | return !!(elem.getContext && elem.getContext('2d'));
245 | };
246 |
247 | tests['canvastext'] = function() {
248 | return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
249 | };
250 |
251 |
252 |
253 | tests['webgl'] = function() {
254 | return !!window.WebGLRenderingContext;
255 | };
256 |
257 |
258 | tests['touch'] = function() {
259 | var bool;
260 |
261 | if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
262 | bool = true;
263 | } else {
264 | injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
265 | bool = node.offsetTop === 9;
266 | });
267 | }
268 |
269 | return bool;
270 | };
271 |
272 |
273 |
274 | tests['geolocation'] = function() {
275 | return 'geolocation' in navigator;
276 | };
277 |
278 |
279 | tests['postmessage'] = function() {
280 | return !!window.postMessage;
281 | };
282 |
283 |
284 | tests['websqldatabase'] = function() {
285 | return !!window.openDatabase;
286 | };
287 |
288 | tests['indexedDB'] = function() {
289 | return !!testPropsAll("indexedDB", window);
290 | };
291 |
292 | tests['hashchange'] = function() {
293 | return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
294 | };
295 |
296 | tests['history'] = function() {
297 | return !!(window.history && history.pushState);
298 | };
299 |
300 | tests['draganddrop'] = function() {
301 | var div = document.createElement('div');
302 | return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
303 | };
304 |
305 | tests['websockets'] = function() {
306 | return 'WebSocket' in window || 'MozWebSocket' in window;
307 | };
308 |
309 |
310 | tests['rgba'] = function() {
311 | setCss('background-color:rgba(150,255,150,.5)');
312 |
313 | return contains(mStyle.backgroundColor, 'rgba');
314 | };
315 |
316 | tests['hsla'] = function() {
317 | setCss('background-color:hsla(120,40%,100%,.5)');
318 |
319 | return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
320 | };
321 |
322 | tests['multiplebgs'] = function() {
323 | setCss('background:url(https://),url(https://),red url(https://)');
324 |
325 | return (/(url\s*\(.*?){3}/).test(mStyle.background);
326 | }; tests['backgroundsize'] = function() {
327 | return testPropsAll('backgroundSize');
328 | };
329 |
330 | tests['borderimage'] = function() {
331 | return testPropsAll('borderImage');
332 | };
333 |
334 |
335 |
336 | tests['borderradius'] = function() {
337 | return testPropsAll('borderRadius');
338 | };
339 |
340 | tests['boxshadow'] = function() {
341 | return testPropsAll('boxShadow');
342 | };
343 |
344 | tests['textshadow'] = function() {
345 | return document.createElement('div').style.textShadow === '';
346 | };
347 |
348 |
349 | tests['opacity'] = function() {
350 | setCssAll('opacity:.55');
351 |
352 | return (/^0.55$/).test(mStyle.opacity);
353 | };
354 |
355 |
356 | tests['cssanimations'] = function() {
357 | return testPropsAll('animationName');
358 | };
359 |
360 |
361 | tests['csscolumns'] = function() {
362 | return testPropsAll('columnCount');
363 | };
364 |
365 |
366 | tests['cssgradients'] = function() {
367 | var str1 = 'background-image:',
368 | str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
369 | str3 = 'linear-gradient(left top,#9f9, white);';
370 |
371 | setCss(
372 | (str1 + '-webkit- '.split(' ').join(str2 + str1) +
373 | prefixes.join(str3 + str1)).slice(0, -str1.length)
374 | );
375 |
376 | return contains(mStyle.backgroundImage, 'gradient');
377 | };
378 |
379 |
380 | tests['cssreflections'] = function() {
381 | return testPropsAll('boxReflect');
382 | };
383 |
384 |
385 | tests['csstransforms'] = function() {
386 | return !!testPropsAll('transform');
387 | };
388 |
389 |
390 | tests['csstransforms3d'] = function() {
391 |
392 | var ret = !!testPropsAll('perspective');
393 |
394 | if ( ret && 'webkitPerspective' in docElement.style ) {
395 |
396 | injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
397 | ret = node.offsetLeft === 9 && node.offsetHeight === 3;
398 | });
399 | }
400 | return ret;
401 | };
402 |
403 |
404 | tests['csstransitions'] = function() {
405 | return testPropsAll('transition');
406 | };
407 |
408 |
409 |
410 | tests['fontface'] = function() {
411 | var bool;
412 |
413 | injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
414 | var style = document.getElementById('smodernizr'),
415 | sheet = style.sheet || style.styleSheet,
416 | cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
417 |
418 | bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
419 | });
420 |
421 | return bool;
422 | };
423 |
424 | tests['generatedcontent'] = function() {
425 | var bool;
426 |
427 | injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) {
428 | bool = node.offsetHeight >= 3;
429 | });
430 |
431 | return bool;
432 | };
433 | tests['video'] = function() {
434 | var elem = document.createElement('video'),
435 | bool = false;
436 |
437 | try {
438 | if ( bool = !!elem.canPlayType ) {
439 | bool = new Boolean(bool);
440 | bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,'');
441 |
442 | bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
443 |
444 | bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
445 | }
446 |
447 | } catch(e) { }
448 |
449 | return bool;
450 | };
451 |
452 | tests['audio'] = function() {
453 | var elem = document.createElement('audio'),
454 | bool = false;
455 |
456 | try {
457 | if ( bool = !!elem.canPlayType ) {
458 | bool = new Boolean(bool);
459 | bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
460 | bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,'');
461 |
462 | bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,'');
463 | bool.m4a = ( elem.canPlayType('audio/x-m4a;') ||
464 | elem.canPlayType('audio/aac;')) .replace(/^no$/,'');
465 | }
466 | } catch(e) { }
467 |
468 | return bool;
469 | };
470 |
471 |
472 | tests['localstorage'] = function() {
473 | try {
474 | localStorage.setItem(mod, mod);
475 | localStorage.removeItem(mod);
476 | return true;
477 | } catch(e) {
478 | return false;
479 | }
480 | };
481 |
482 | tests['sessionstorage'] = function() {
483 | try {
484 | sessionStorage.setItem(mod, mod);
485 | sessionStorage.removeItem(mod);
486 | return true;
487 | } catch(e) {
488 | return false;
489 | }
490 | };
491 |
492 |
493 | tests['webworkers'] = function() {
494 | return !!window.Worker;
495 | };
496 |
497 |
498 | tests['applicationcache'] = function() {
499 | return !!window.applicationCache;
500 | };
501 |
502 |
503 | tests['svg'] = function() {
504 | return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
505 | };
506 |
507 | tests['inlinesvg'] = function() {
508 | var div = document.createElement('div');
509 | div.innerHTML = '';
510 | return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
511 | };
512 |
513 | tests['smil'] = function() {
514 | return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
515 | };
516 |
517 |
518 | tests['svgclippaths'] = function() {
519 | return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
520 | };
521 |
522 | function webforms() {
523 | Modernizr['input'] = (function( props ) {
524 | for ( var i = 0, len = props.length; i < len; i++ ) {
525 | attrs[ props[i] ] = !!(props[i] in inputElem);
526 | }
527 | if (attrs.list){
528 | attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
529 | }
530 | return attrs;
531 | })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
532 | Modernizr['inputtypes'] = (function(props) {
533 |
534 | for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
535 |
536 | inputElem.setAttribute('type', inputElemType = props[i]);
537 | bool = inputElem.type !== 'text';
538 |
539 | if ( bool ) {
540 |
541 | inputElem.value = smile;
542 | inputElem.style.cssText = 'position:absolute;visibility:hidden;';
543 |
544 | if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
545 |
546 | docElement.appendChild(inputElem);
547 | defaultView = document.defaultView;
548 |
549 | bool = defaultView.getComputedStyle &&
550 | defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
551 | (inputElem.offsetHeight !== 0);
552 |
553 | docElement.removeChild(inputElem);
554 |
555 | } else if ( /^(search|tel)$/.test(inputElemType) ){
556 | } else if ( /^(url|email)$/.test(inputElemType) ) {
557 | bool = inputElem.checkValidity && inputElem.checkValidity() === false;
558 |
559 | } else {
560 | bool = inputElem.value != smile;
561 | }
562 | }
563 |
564 | inputs[ props[i] ] = !!bool;
565 | }
566 | return inputs;
567 | })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
568 | }
569 | for ( var feature in tests ) {
570 | if ( hasOwnProp(tests, feature) ) {
571 | featureName = feature.toLowerCase();
572 | Modernizr[featureName] = tests[feature]();
573 |
574 | classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
575 | }
576 | }
577 |
578 | Modernizr.input || webforms();
579 |
580 |
581 | Modernizr.addTest = function ( feature, test ) {
582 | if ( typeof feature == 'object' ) {
583 | for ( var key in feature ) {
584 | if ( hasOwnProp( feature, key ) ) {
585 | Modernizr.addTest( key, feature[ key ] );
586 | }
587 | }
588 | } else {
589 |
590 | feature = feature.toLowerCase();
591 |
592 | if ( Modernizr[feature] !== undefined ) {
593 | return Modernizr;
594 | }
595 |
596 | test = typeof test == 'function' ? test() : test;
597 |
598 | if (typeof enableClasses !== "undefined" && enableClasses) {
599 | docElement.className += ' ' + (test ? '' : 'no-') + feature;
600 | }
601 | Modernizr[feature] = test;
602 |
603 | }
604 |
605 | return Modernizr;
606 | };
607 |
608 |
609 | setCss('');
610 | modElem = inputElem = null;
611 |
612 | ;(function(window, document) {
613 | var options = window.html5 || {};
614 |
615 | var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
616 |
617 | var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
618 |
619 | var supportsHtml5Styles;
620 |
621 | var expando = '_html5shiv';
622 |
623 | var expanID = 0;
624 |
625 | var expandoData = {};
626 |
627 | var supportsUnknownElements;
628 |
629 | (function() {
630 | try {
631 | var a = document.createElement('a');
632 | a.innerHTML = '';
633 | supportsHtml5Styles = ('hidden' in a);
634 |
635 | supportsUnknownElements = a.childNodes.length == 1 || (function() {
636 | (document.createElement)('a');
637 | var frag = document.createDocumentFragment();
638 | return (
639 | typeof frag.cloneNode == 'undefined' ||
640 | typeof frag.createDocumentFragment == 'undefined' ||
641 | typeof frag.createElement == 'undefined'
642 | );
643 | }());
644 | } catch(e) {
645 | supportsHtml5Styles = true;
646 | supportsUnknownElements = true;
647 | }
648 |
649 | }()); function addStyleSheet(ownerDocument, cssText) {
650 | var p = ownerDocument.createElement('p'),
651 | parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
652 |
653 | p.innerHTML = 'x';
654 | return parent.insertBefore(p.lastChild, parent.firstChild);
655 | }
656 |
657 | function getElements() {
658 | var elements = html5.elements;
659 | return typeof elements == 'string' ? elements.split(' ') : elements;
660 | }
661 |
662 | function getExpandoData(ownerDocument) {
663 | var data = expandoData[ownerDocument[expando]];
664 | if (!data) {
665 | data = {};
666 | expanID++;
667 | ownerDocument[expando] = expanID;
668 | expandoData[expanID] = data;
669 | }
670 | return data;
671 | }
672 |
673 | function createElement(nodeName, ownerDocument, data){
674 | if (!ownerDocument) {
675 | ownerDocument = document;
676 | }
677 | if(supportsUnknownElements){
678 | return ownerDocument.createElement(nodeName);
679 | }
680 | if (!data) {
681 | data = getExpandoData(ownerDocument);
682 | }
683 | var node;
684 |
685 | if (data.cache[nodeName]) {
686 | node = data.cache[nodeName].cloneNode();
687 | } else if (saveClones.test(nodeName)) {
688 | node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
689 | } else {
690 | node = data.createElem(nodeName);
691 | }
692 |
693 | return node.canHaveChildren && !reSkip.test(nodeName) ? data.frag.appendChild(node) : node;
694 | }
695 |
696 | function createDocumentFragment(ownerDocument, data){
697 | if (!ownerDocument) {
698 | ownerDocument = document;
699 | }
700 | if(supportsUnknownElements){
701 | return ownerDocument.createDocumentFragment();
702 | }
703 | data = data || getExpandoData(ownerDocument);
704 | var clone = data.frag.cloneNode(),
705 | i = 0,
706 | elems = getElements(),
707 | l = elems.length;
708 | for(;ip+1E3)l=Math.round(o*1E3/(i-p)),q=Math.min(q,l),r=Math.max(r,l),j.textContent=l+" FPS ("+q+"-"+r+")",a=Math.min(30,30-l/
7 | 100*30),f.appendChild(f.firstChild).style.height=a+"px",p=i,o=0}}};
8 |
--------------------------------------------------------------------------------
/app/client/lib/webgl/THREEx.KeyboardState.js:
--------------------------------------------------------------------------------
1 | // THREEx.KeyboardState.js keep the current state of the keyboard.
2 | // It is possible to query it at any time. No need of an event.
3 | // This is particularly convenient in loop driven case, like in
4 | // 3D demos or games.
5 | //
6 | // # Usage
7 | //
8 | // **Step 1**: Create the object
9 | //
10 | // ```var keyboard = new THREEx.KeyboardState();```
11 | //
12 | // **Step 2**: Query the keyboard state
13 | //
14 | // This will return true if shift and A are pressed, false otherwise
15 | //
16 | // ```keyboard.pressed("shift+A")```
17 | //
18 | // **Step 3**: Stop listening to the keyboard
19 | //
20 | // ```keyboard.destroy()```
21 | //
22 | // NOTE: this library may be nice as standaline. independant from three.js
23 | // - rename it keyboardForGame
24 | //
25 | // # Code
26 | //
27 |
28 | /** @namespace */
29 | var THREEx = THREEx || {};
30 |
31 | /**
32 | * - NOTE: it would be quite easy to push event-driven too
33 | * - microevent.js for events handling
34 | * - in this._onkeyChange, generate a string from the DOM event
35 | * - use this as event name
36 | */
37 | THREEx.KeyboardState = function()
38 | {
39 | // to store the current state
40 | this.keyCodes = {};
41 | this.modifiers = {};
42 |
43 | // create callback to bind/unbind keyboard events
44 | var self = this;
45 | this._onKeyDown = function(event){
46 | event.preventDefault();
47 | self._onKeyChange(event, true);
48 | };
49 | this._onKeyUp = function(event){
50 | event.preventDefault();
51 | self._onKeyChange(event, false);
52 | };
53 |
54 | // bind keyEvents
55 | document.addEventListener("keydown", this._onKeyDown, false);
56 | document.addEventListener("keyup", this._onKeyUp, false);
57 | };
58 |
59 | /**
60 | * To stop listening of the keyboard events
61 | */
62 | THREEx.KeyboardState.prototype.destroy = function()
63 | {
64 | // unbind keyEvents
65 | document.removeEventListener("keydown", this._onKeyDown, false);
66 | document.removeEventListener("keyup", this._onKeyUp, false);
67 | };
68 |
69 | THREEx.KeyboardState.MODIFIERS = ['shift', 'ctrl', 'alt', 'meta'];
70 | THREEx.KeyboardState.ALIAS = {
71 | 'left' : 37,
72 | 'up' : 38,
73 | 'right' : 39,
74 | 'down' : 40,
75 | 'space' : 32,
76 | 'pageup' : 33,
77 | 'pagedown' : 34,
78 | 'tab' : 9
79 | };
80 |
81 | /**
82 | * to process the keyboard dom event
83 | */
84 | THREEx.KeyboardState.prototype._onKeyChange = function(event, pressed)
85 | {
86 | // log to debug
87 | //console.log("onKeyChange", event, pressed, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)
88 |
89 | // update this.keyCodes
90 | var keyCode = event.keyCode;
91 | this.keyCodes[keyCode] = pressed;
92 |
93 | // update this.modifiers
94 | this.modifiers['shift']= event.shiftKey;
95 | this.modifiers['ctrl'] = event.ctrlKey;
96 | this.modifiers['alt'] = event.altKey;
97 | this.modifiers['meta'] = event.metaKey;
98 | };
99 |
100 | /**
101 | * query keyboard state to know if a key is pressed of not
102 | *
103 | * @param {String} keyDesc the description of the key. format : modifiers+key e.g shift+A
104 | * @returns {Boolean} true if the key is pressed, false otherwise
105 | */
106 | THREEx.KeyboardState.prototype.pressed = function(keyDesc)
107 | {
108 | var keys = keyDesc.split("+");
109 | for(var i = 0; i < keys.length; i++){
110 | var key = keys[i];
111 | var pressed;
112 | if( THREEx.KeyboardState.MODIFIERS.indexOf( key ) !== -1 ){
113 | pressed = this.modifiers[key];
114 | }else if( Object.keys(THREEx.KeyboardState.ALIAS).indexOf( key ) != -1 ){
115 | pressed = this.keyCodes[ THREEx.KeyboardState.ALIAS[key] ];
116 | }else {
117 | pressed = this.keyCodes[key.toUpperCase().charCodeAt(0)]
118 | }
119 | if( !pressed) return false;
120 | }
121 | return true;
122 | };
--------------------------------------------------------------------------------
/app/client/lib/webgl/THREEx.WindowResize.js:
--------------------------------------------------------------------------------
1 | // This THREEx helper makes it easy to handle window resize.
2 | // It will update renderer and camera when window is resized.
3 | //
4 | // # Usage
5 | //
6 | // **Step 1**: Start updating renderer and camera
7 | //
8 | // ```var windowResize = THREEx.WindowResize(aRenderer, aCamera)```
9 | //
10 | // **Step 2**: Start updating renderer and camera
11 | //
12 | // ```windowResize.stop()```
13 | // # Code
14 |
15 | //
16 |
17 | /** @namespace */
18 | var THREEx = THREEx || {};
19 |
20 | /**
21 | * Update renderer and camera when the window is resized
22 | *
23 | * @param {Object} renderer the renderer to update
24 | * @param {Object} Camera the camera to update
25 | */
26 | THREEx.WindowResize = function(renderer, camera){
27 | var callback = function(){
28 | // notify the renderer of the size change
29 | renderer.setSize( window.innerWidth, window.innerHeight );
30 | // update the camera
31 | camera.aspect = window.innerWidth / window.innerHeight;
32 | camera.updateProjectionMatrix();
33 | }
34 | // bind the resize event
35 | window.addEventListener('resize', callback, false);
36 | // return .stop() the function to stop watching window resize
37 | return {
38 | /**
39 | * Stop watching window resize
40 | */
41 | stop : function(){
42 | window.removeEventListener('resize', callback);
43 | }
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/app/client/lib/webgl/core/three/Detector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author alteredq / http://alteredqualia.com/
3 | * @author mr.doob / http://mrdoob.com/
4 | */
5 |
6 | var Detector = {
7 |
8 | canvas: !! window.CanvasRenderingContext2D,
9 | webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(),
10 | workers: !! window.Worker,
11 | fileapi: window.File && window.FileReader && window.FileList && window.Blob,
12 |
13 | getWebGLErrorMessage: function () {
14 |
15 | var element = document.createElement( 'div' );
16 | element.id = 'webgl-error-message';
17 | element.style.fontFamily = 'monospace';
18 | element.style.fontSize = '13px';
19 | element.style.fontWeight = 'normal';
20 | element.style.textAlign = 'center';
21 | element.style.background = '#fff';
22 | element.style.color = '#000';
23 | element.style.padding = '1.5em';
24 | element.style.width = '400px';
25 | element.style.margin = '5em auto 0';
26 |
27 | if ( ! this.webgl ) {
28 |
29 | element.innerHTML = window.WebGLRenderingContext ? [
30 | 'Your graphics card does not seem to support WebGL.
',
31 | 'Find out how to get it here.'
32 | ].join( '\n' ) : [
33 | 'Your browser does not seem to support WebGL.
',
34 | 'Find out how to get it here.'
35 | ].join( '\n' );
36 |
37 | }
38 |
39 | return element;
40 |
41 | },
42 |
43 | addGetWebGLMessage: function ( parameters ) {
44 |
45 | var parent, id, element;
46 |
47 | parameters = parameters || {};
48 |
49 | parent = parameters.parent !== undefined ? parameters.parent : document.body;
50 | id = parameters.id !== undefined ? parameters.id : 'oldie';
51 |
52 | element = Detector.getWebGLErrorMessage();
53 | element.id = id;
54 |
55 | parent.appendChild( element );
56 |
57 | }
58 |
59 | };
--------------------------------------------------------------------------------
/app/client/lib/webgl/tween/tween.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author sole / http://soledadpenades.com
3 | * @author mrdoob / http://mrdoob.com
4 | * @author Robert Eisele / http://www.xarg.org
5 | * @author Philippe / http://philippe.elsass.me
6 | * @author Robert Penner / http://www.robertpenner.com/easing_terms_of_use.html
7 | * @author Paul Lewis / http://www.aerotwist.com/
8 | * @author lechecacharro
9 | * @author Josh Faul / http://jocafa.com/
10 | * @author egraether / http://egraether.com/
11 | */
12 |
13 | var TWEEN = TWEEN || ( function () {
14 |
15 | var _tweens = [];
16 |
17 | return {
18 |
19 | REVISION: '7',
20 |
21 | getAll: function () {
22 |
23 | return _tweens;
24 |
25 | },
26 |
27 | removeAll: function () {
28 |
29 | _tweens = [];
30 |
31 | },
32 |
33 | add: function ( tween ) {
34 |
35 | _tweens.push( tween );
36 |
37 | },
38 |
39 | remove: function ( tween ) {
40 |
41 | var i = _tweens.indexOf( tween );
42 |
43 | if ( i !== -1 ) {
44 |
45 | _tweens.splice( i, 1 );
46 |
47 | }
48 |
49 | },
50 |
51 | update: function ( time ) {
52 |
53 | if ( _tweens.length === 0 ) return false;
54 |
55 | var i = 0, l = _tweens.length;
56 |
57 | time = time !== undefined ? time : Date.now();
58 |
59 | while ( i < l ) {
60 |
61 | if ( _tweens[ i ].update( time ) ) {
62 |
63 | i ++;
64 |
65 | } else {
66 |
67 | _tweens.splice( i, 1 );
68 |
69 | l --;
70 |
71 | }
72 |
73 | }
74 |
75 | return true;
76 |
77 | }
78 |
79 | };
80 |
81 | } )();
82 |
83 | TWEEN.Tween = function ( object ) {
84 |
85 | var _object = object;
86 | var _valuesStart = {};
87 | var _valuesEnd = {};
88 | var _duration = 1000;
89 | var _delayTime = 0;
90 | var _startTime = null;
91 | var _easingFunction = TWEEN.Easing.Linear.None;
92 | var _interpolationFunction = TWEEN.Interpolation.Linear;
93 | var _chainedTweens = [];
94 | var _onStartCallback = null;
95 | var _onStartCallbackFired = false;
96 | var _onUpdateCallback = null;
97 | var _onCompleteCallback = null;
98 |
99 | this.to = function ( properties, duration ) {
100 |
101 | if ( duration !== undefined ) {
102 |
103 | _duration = duration;
104 |
105 | }
106 |
107 | _valuesEnd = properties;
108 |
109 | return this;
110 |
111 | };
112 |
113 | this.start = function ( time ) {
114 |
115 | TWEEN.add( this );
116 |
117 | _onStartCallbackFired = false;
118 |
119 | _startTime = time !== undefined ? time : Date.now();
120 | _startTime += _delayTime;
121 |
122 | for ( var property in _valuesEnd ) {
123 |
124 | // This prevents the engine from interpolating null values
125 | if ( _object[ property ] === null ) {
126 |
127 | continue;
128 |
129 | }
130 |
131 | // check if an Array was provided as property value
132 | if ( _valuesEnd[ property ] instanceof Array ) {
133 |
134 | if ( _valuesEnd[ property ].length === 0 ) {
135 |
136 | continue;
137 |
138 | }
139 |
140 | // create a local copy of the Array with the start value at the front
141 | _valuesEnd[ property ] = [ _object[ property ] ].concat( _valuesEnd[ property ] );
142 |
143 | }
144 |
145 | _valuesStart[ property ] = _object[ property ];
146 |
147 | }
148 |
149 | return this;
150 |
151 | };
152 |
153 | this.stop = function () {
154 |
155 | TWEEN.remove( this );
156 | return this;
157 |
158 | };
159 |
160 | this.delay = function ( amount ) {
161 |
162 | _delayTime = amount;
163 | return this;
164 |
165 | };
166 |
167 | this.easing = function ( easing ) {
168 |
169 | _easingFunction = easing;
170 | return this;
171 |
172 | };
173 |
174 | this.interpolation = function ( interpolation ) {
175 |
176 | _interpolationFunction = interpolation;
177 | return this;
178 |
179 | };
180 |
181 | this.chain = function () {
182 |
183 | _chainedTweens = arguments;
184 | return this;
185 |
186 | };
187 |
188 | this.onStart = function ( callback ) {
189 |
190 | _onStartCallback = callback;
191 | return this;
192 |
193 | };
194 |
195 | this.onUpdate = function ( callback ) {
196 |
197 | _onUpdateCallback = callback;
198 | return this;
199 |
200 | };
201 |
202 | this.onComplete = function ( callback ) {
203 |
204 | _onCompleteCallback = callback;
205 | return this;
206 |
207 | };
208 |
209 | this.update = function ( time ) {
210 |
211 | if ( time < _startTime ) {
212 |
213 | return true;
214 |
215 | }
216 |
217 | if ( _onStartCallbackFired === false ) {
218 |
219 | if ( _onStartCallback !== null ) {
220 |
221 | _onStartCallback.call( _object );
222 |
223 | }
224 |
225 | _onStartCallbackFired = true;
226 |
227 | }
228 |
229 | var elapsed = ( time - _startTime ) / _duration;
230 | elapsed = elapsed > 1 ? 1 : elapsed;
231 |
232 | var value = _easingFunction( elapsed );
233 |
234 | for ( var property in _valuesStart ) {
235 |
236 | var start = _valuesStart[ property ];
237 | var end = _valuesEnd[ property ];
238 |
239 | if ( end instanceof Array ) {
240 |
241 | _object[ property ] = _interpolationFunction( end, value );
242 |
243 | } else {
244 |
245 | _object[ property ] = start + ( end - start ) * value;
246 |
247 | }
248 |
249 | }
250 |
251 | if ( _onUpdateCallback !== null ) {
252 |
253 | _onUpdateCallback.call( _object, value );
254 |
255 | }
256 |
257 | if ( elapsed == 1 ) {
258 |
259 | if ( _onCompleteCallback !== null ) {
260 |
261 | _onCompleteCallback.call( _object );
262 |
263 | }
264 |
265 | for ( var i = 0, l = _chainedTweens.length; i < l; i ++ ) {
266 |
267 | _chainedTweens[ i ].start( time );
268 |
269 | }
270 |
271 | return false;
272 |
273 | }
274 |
275 | return true;
276 |
277 | };
278 |
279 | };
280 |
281 | TWEEN.Easing = {
282 |
283 | Linear: {
284 |
285 | None: function ( k ) {
286 |
287 | return k;
288 |
289 | }
290 |
291 | },
292 |
293 | Quadratic: {
294 |
295 | In: function ( k ) {
296 |
297 | return k * k;
298 |
299 | },
300 |
301 | Out: function ( k ) {
302 |
303 | return k * ( 2 - k );
304 |
305 | },
306 |
307 | InOut: function ( k ) {
308 |
309 | if ( ( k *= 2 ) < 1 ) return 0.5 * k * k;
310 | return - 0.5 * ( --k * ( k - 2 ) - 1 );
311 |
312 | }
313 |
314 | },
315 |
316 | Cubic: {
317 |
318 | In: function ( k ) {
319 |
320 | return k * k * k;
321 |
322 | },
323 |
324 | Out: function ( k ) {
325 |
326 | return --k * k * k + 1;
327 |
328 | },
329 |
330 | InOut: function ( k ) {
331 |
332 | if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k;
333 | return 0.5 * ( ( k -= 2 ) * k * k + 2 );
334 |
335 | }
336 |
337 | },
338 |
339 | Quartic: {
340 |
341 | In: function ( k ) {
342 |
343 | return k * k * k * k;
344 |
345 | },
346 |
347 | Out: function ( k ) {
348 |
349 | return 1 - ( --k * k * k * k );
350 |
351 | },
352 |
353 | InOut: function ( k ) {
354 |
355 | if ( ( k *= 2 ) < 1) return 0.5 * k * k * k * k;
356 | return - 0.5 * ( ( k -= 2 ) * k * k * k - 2 );
357 |
358 | }
359 |
360 | },
361 |
362 | Quintic: {
363 |
364 | In: function ( k ) {
365 |
366 | return k * k * k * k * k;
367 |
368 | },
369 |
370 | Out: function ( k ) {
371 |
372 | return --k * k * k * k * k + 1;
373 |
374 | },
375 |
376 | InOut: function ( k ) {
377 |
378 | if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k * k * k;
379 | return 0.5 * ( ( k -= 2 ) * k * k * k * k + 2 );
380 |
381 | }
382 |
383 | },
384 |
385 | Sinusoidal: {
386 |
387 | In: function ( k ) {
388 |
389 | return 1 - Math.cos( k * Math.PI / 2 );
390 |
391 | },
392 |
393 | Out: function ( k ) {
394 |
395 | return Math.sin( k * Math.PI / 2 );
396 |
397 | },
398 |
399 | InOut: function ( k ) {
400 |
401 | return 0.5 * ( 1 - Math.cos( Math.PI * k ) );
402 |
403 | }
404 |
405 | },
406 |
407 | Exponential: {
408 |
409 | In: function ( k ) {
410 |
411 | return k === 0 ? 0 : Math.pow( 1024, k - 1 );
412 |
413 | },
414 |
415 | Out: function ( k ) {
416 |
417 | return k === 1 ? 1 : 1 - Math.pow( 2, - 10 * k );
418 |
419 | },
420 |
421 | InOut: function ( k ) {
422 |
423 | if ( k === 0 ) return 0;
424 | if ( k === 1 ) return 1;
425 | if ( ( k *= 2 ) < 1 ) return 0.5 * Math.pow( 1024, k - 1 );
426 | return 0.5 * ( - Math.pow( 2, - 10 * ( k - 1 ) ) + 2 );
427 |
428 | }
429 |
430 | },
431 |
432 | Circular: {
433 |
434 | In: function ( k ) {
435 |
436 | return 1 - Math.sqrt( 1 - k * k );
437 |
438 | },
439 |
440 | Out: function ( k ) {
441 |
442 | return Math.sqrt( 1 - ( --k * k ) );
443 |
444 | },
445 |
446 | InOut: function ( k ) {
447 |
448 | if ( ( k *= 2 ) < 1) return - 0.5 * ( Math.sqrt( 1 - k * k) - 1);
449 | return 0.5 * ( Math.sqrt( 1 - ( k -= 2) * k) + 1);
450 |
451 | }
452 |
453 | },
454 |
455 | Elastic: {
456 |
457 | In: function ( k ) {
458 |
459 | var s, a = 0.1, p = 0.4;
460 | if ( k === 0 ) return 0;
461 | if ( k === 1 ) return 1;
462 | if ( !a || a < 1 ) { a = 1; s = p / 4; }
463 | else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
464 | return - ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
465 |
466 | },
467 |
468 | Out: function ( k ) {
469 |
470 | var s, a = 0.1, p = 0.4;
471 | if ( k === 0 ) return 0;
472 | if ( k === 1 ) return 1;
473 | if ( !a || a < 1 ) { a = 1; s = p / 4; }
474 | else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
475 | return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
476 |
477 | },
478 |
479 | InOut: function ( k ) {
480 |
481 | var s, a = 0.1, p = 0.4;
482 | if ( k === 0 ) return 0;
483 | if ( k === 1 ) return 1;
484 | if ( !a || a < 1 ) { a = 1; s = p / 4; }
485 | else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
486 | if ( ( k *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
487 | return a * Math.pow( 2, -10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1;
488 |
489 | }
490 |
491 | },
492 |
493 | Back: {
494 |
495 | In: function ( k ) {
496 |
497 | var s = 1.70158;
498 | return k * k * ( ( s + 1 ) * k - s );
499 |
500 | },
501 |
502 | Out: function ( k ) {
503 |
504 | var s = 1.70158;
505 | return --k * k * ( ( s + 1 ) * k + s ) + 1;
506 |
507 | },
508 |
509 | InOut: function ( k ) {
510 |
511 | var s = 1.70158 * 1.525;
512 | if ( ( k *= 2 ) < 1 ) return 0.5 * ( k * k * ( ( s + 1 ) * k - s ) );
513 | return 0.5 * ( ( k -= 2 ) * k * ( ( s + 1 ) * k + s ) + 2 );
514 |
515 | }
516 |
517 | },
518 |
519 | Bounce: {
520 |
521 | In: function ( k ) {
522 |
523 | return 1 - TWEEN.Easing.Bounce.Out( 1 - k );
524 |
525 | },
526 |
527 | Out: function ( k ) {
528 |
529 | if ( k < ( 1 / 2.75 ) ) {
530 |
531 | return 7.5625 * k * k;
532 |
533 | } else if ( k < ( 2 / 2.75 ) ) {
534 |
535 | return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
536 |
537 | } else if ( k < ( 2.5 / 2.75 ) ) {
538 |
539 | return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
540 |
541 | } else {
542 |
543 | return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
544 |
545 | }
546 |
547 | },
548 |
549 | InOut: function ( k ) {
550 |
551 | if ( k < 0.5 ) return TWEEN.Easing.Bounce.In( k * 2 ) * 0.5;
552 | return TWEEN.Easing.Bounce.Out( k * 2 - 1 ) * 0.5 + 0.5;
553 |
554 | }
555 |
556 | }
557 |
558 | };
559 |
560 | TWEEN.Interpolation = {
561 |
562 | Linear: function ( v, k ) {
563 |
564 | var m = v.length - 1, f = m * k, i = Math.floor( f ), fn = TWEEN.Interpolation.Utils.Linear;
565 |
566 | if ( k < 0 ) return fn( v[ 0 ], v[ 1 ], f );
567 | if ( k > 1 ) return fn( v[ m ], v[ m - 1 ], m - f );
568 |
569 | return fn( v[ i ], v[ i + 1 > m ? m : i + 1 ], f - i );
570 |
571 | },
572 |
573 | Bezier: function ( v, k ) {
574 |
575 | var b = 0, n = v.length - 1, pw = Math.pow, bn = TWEEN.Interpolation.Utils.Bernstein, i;
576 |
577 | for ( i = 0; i <= n; i++ ) {
578 | b += pw( 1 - k, n - i ) * pw( k, i ) * v[ i ] * bn( n, i );
579 | }
580 |
581 | return b;
582 |
583 | },
584 |
585 | CatmullRom: function ( v, k ) {
586 |
587 | var m = v.length - 1, f = m * k, i = Math.floor( f ), fn = TWEEN.Interpolation.Utils.CatmullRom;
588 |
589 | if ( v[ 0 ] === v[ m ] ) {
590 |
591 | if ( k < 0 ) i = Math.floor( f = m * ( 1 + k ) );
592 |
593 | return fn( v[ ( i - 1 + m ) % m ], v[ i ], v[ ( i + 1 ) % m ], v[ ( i + 2 ) % m ], f - i );
594 |
595 | } else {
596 |
597 | if ( k < 0 ) return v[ 0 ] - ( fn( v[ 0 ], v[ 0 ], v[ 1 ], v[ 1 ], -f ) - v[ 0 ] );
598 | if ( k > 1 ) return v[ m ] - ( fn( v[ m ], v[ m ], v[ m - 1 ], v[ m - 1 ], f - m ) - v[ m ] );
599 |
600 | return fn( v[ i ? i - 1 : 0 ], v[ i ], v[ m < i + 1 ? m : i + 1 ], v[ m < i + 2 ? m : i + 2 ], f - i );
601 |
602 | }
603 |
604 | },
605 |
606 | Utils: {
607 |
608 | Linear: function ( p0, p1, t ) {
609 |
610 | return ( p1 - p0 ) * t + p0;
611 |
612 | },
613 |
614 | Bernstein: function ( n , i ) {
615 |
616 | var fc = TWEEN.Interpolation.Utils.Factorial;
617 | return fc( n ) / fc( i ) / fc( n - i );
618 |
619 | },
620 |
621 | Factorial: ( function () {
622 |
623 | var a = [ 1 ];
624 |
625 | return function ( n ) {
626 |
627 | var s = 1, i;
628 | if ( a[ n ] ) return a[ n ];
629 | for ( i = n; i > 1; i-- ) s *= i;
630 | return a[ n ] = s;
631 |
632 | };
633 |
634 | } )(),
635 |
636 | CatmullRom: function ( p0, p1, p2, p3, t ) {
637 |
638 | var v0 = ( p2 - p0 ) * 0.5, v1 = ( p3 - p1 ) * 0.5, t2 = t * t, t3 = t * t2;
639 | return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
640 |
641 | }
642 |
643 | }
644 |
645 | };
--------------------------------------------------------------------------------
/app/client/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Box Shadow
2 | @mixin box-shadow($value) {
3 | -webkit-box-shadow: #{$value};
4 | -moz-box-shadow: #{$value};
5 | -ms-box-shadow: #{$value};
6 | -o-box-shadow: #{$value};
7 | box-shadow: #{$value};
8 | }
9 |
10 |
11 | // Linear Gradient
12 | @mixin background-linear-gradient($collection) {
13 |
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/app/client/scss/project.scss:
--------------------------------------------------------------------------------
1 | @import "_mixins";
2 | @import "compass";
3 |
4 | a {
5 | @include link-colors(#000011, #c0c0c0, #000011, #000011, #c0c0c0);
6 | font-weight: bold;
7 | text-decoration: none;
8 | }
9 |
10 | * {
11 | font-family: 'Gudea', sans-serif;
12 | text-transform: lowercase;
13 | }
14 |
15 | h3 {
16 | margin: 0px;
17 | }
18 |
19 | ul, li {
20 | list-style-type: none;
21 | margin: 0px;
22 | padding: 0px;
23 | }
24 |
25 | body {
26 | background-color: #222222;
27 | background: url("/img/bg.png");
28 | overflow: hidden;
29 |
30 | }
31 |
32 | button, .topper-info {
33 | position: relative;
34 | overflow: visible;
35 | display: inline-block;
36 | padding: 0.5em 1em;
37 |
38 | margin: 0;
39 | text-decoration: none;
40 | text-align: center;
41 | text-shadow: 1px 1px 0 #fff;
42 | font-size: 20px;
43 | color: #333;
44 |
45 |
46 | &.new-game, &.continue {
47 | font-weight: bold;
48 | margin: 30px 0px 30px 275px;
49 | width: 350px;
50 | padding: 10px 20px;
51 | }
52 | }
53 |
54 |
55 | button, .topper-info, .ossprojects li, .view-gamepad {
56 | border: 1px solid #d4d4d4;
57 | white-space: nowrap;
58 | cursor: pointer;
59 | outline: none;
60 | background-color: #ececec;
61 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f4f4f4), to(#ececec));
62 | background-image: -moz-linear-gradient(#f4f4f4, #ececec);
63 | background-image: -ms-linear-gradient(#f4f4f4, #ececec);
64 | background-image: -o-linear-gradient(#f4f4f4, #ececec);
65 | background-image: linear-gradient(#f4f4f4, #ececec);
66 | -moz-background-clip: padding; /* for Firefox 3.6 */
67 | background-clip: padding-box;
68 | border-radius: 0.2em;
69 | }
70 |
71 |
72 | .view-gamepad {
73 | display: block;
74 | text-align: center;
75 | padding: 2px;
76 | margin-top: 5px;
77 | font-weight: normal;
78 | }
79 |
80 | button:hover, .ossprojects li:hover {
81 | background-color: #ffffff;
82 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f4f4f4), to(#ffffff));
83 | background-image: -moz-linear-gradient(#f4f4f4, #ffffff);
84 | background-image: -ms-linear-gradient(#f4f4f4, #ffffff);
85 | background-image: -o-linear-gradient(#f4f4f4, #ffffff);
86 | background-image: linear-gradient(#f4f4f4, #ffffff);
87 | }
88 |
89 | .topper-info {
90 | color: #FFF;
91 | text-transform: lowercase;
92 | border-radius: 0;
93 | cursor: none;
94 | width: 100%;
95 | font-size: 10px;
96 | color: #000011;
97 | }
98 |
99 | .control-help {
100 | font-size: 10px;
101 | color: #FFF;
102 | width: 100px;
103 | position: absolute;
104 | bottom: 0px;
105 | right: 0px;
106 | width: 100px;
107 | }
108 |
109 | .gamepad-status {
110 | position: absolute;
111 | bottom: 100px;
112 | right: 0px;
113 | font-size: 12px;
114 | width: 100px;
115 | color: #FFF;
116 | .connected {
117 | background: #baff72;
118 | }
119 | }
120 |
121 | .req-webgl .continue {
122 | margin: 85px 0px 30px 170px;
123 | width: 600px;
124 | font-size: 23px;
125 | }
126 |
127 | .player-list li {
128 | display: inline;
129 | }
130 |
131 | .req-welcome {
132 | h3 {
133 | color: #333333;
134 | margin-left: 6px;
135 | }
136 | }
137 |
138 | .req-gameover {
139 | h1 {
140 | margin-lefT: 75px;
141 | }
142 | .window p {
143 | margin-left: 35px;
144 | }
145 | }
146 |
147 | .req-project {
148 | aside {
149 | font-size: 20px;
150 | margin: 20px 0px 20px 35px;
151 | }
152 | }
153 |
154 | .frames {
155 | width: 990px;
156 | margin: 0 auto;
157 | position: relative;
158 | }
159 |
160 | .life {
161 | height: 20px;
162 | width: 100%;
163 | // TODO: fix this later
164 | // needs latest Compass, add '@import "compass"' to your scss
165 | background-color: #cdeb8e;
166 | // Old browsers
167 | @include background-image(linear-gradient(top, #cdeb8e 0%, #a5c956 100%));
168 | text-transform: lowercase;
169 |
170 | }
171 |
172 | .frame {
173 | position: absolute;
174 | width: 990px;
175 | top: -1000px;
176 | margin: 0 auto;
177 | h1 {
178 | font-weight: normal;
179 | font-size: 60px;
180 | text-shadow: 2px 1px 4px rgb(39, 38, 38);
181 | height: 90px;
182 | color: #F3F5F7;
183 | margin: 0px 0px 0px 45px;
184 | padding: 0px;
185 | text-transform: lowercase;
186 | }
187 | .window {
188 | @include box-shadow("inset 0px 1px 0px rgba(255,255,255, 0.25), 0px 10px 20px rgba(0,0,0, 0.7)");
189 | width: 900px;
190 | overflow: hidden;
191 | background: #FFF;
192 | position: relative;
193 | min-height: 250px;
194 | max-height: 460px;
195 | margin: 0 auto;
196 | .part {
197 | width: 25%;
198 | float: left;
199 | h3 {
200 | margin: 20px 0px 0px 0px;
201 | }
202 | }
203 | .part-large {
204 | float: left;
205 | width: 70%;
206 | padding-right: 4%;
207 | ul {
208 | margin-left: 5%;
209 | }
210 | li {
211 | font-size: 18px;
212 | margin: 10px 0px 10px 0px;
213 | list-style-type: square;
214 | }
215 | }
216 | h1 {
217 | margin: 0px;
218 | text-align: center;
219 | font-weight: bold;
220 | text-transform: uppercase;
221 | color: #c0c0c0;
222 | &.logo span {
223 | color: #000011;
224 | }
225 | }
226 | .under-logo {
227 | position: absolute;
228 | top: 47px;
229 | left: 350px;
230 | }
231 | }
232 | }
233 |
234 | .plays {
235 | clear: both;
236 | .play {
237 | overflow: hidden;
238 | float: left;
239 | width: 9%;
240 | font-size: 10px;
241 | border-left: 1px solid grey;
242 | padding: 0.7%;
243 | margin: 0.7%;
244 | white-space: nowrap;
245 | }
246 | }
247 |
248 | .progress {
249 | display: none;
250 | }
251 |
252 | .ossprojects {
253 | li {
254 | cursor: pointer;
255 | float: left;
256 | width: 20%;
257 | margin: 1%;
258 | padding: 1%;
259 | height: 100px;
260 | overflow: hidden;
261 | span {
262 | display: block;
263 | }
264 |
265 | .name {
266 | font-weight: bold;
267 | text-align: center;
268 | font-size: 24px;
269 | margin-bottom: 30px;
270 | }
271 | .data {
272 |
273 | }
274 | }
275 | overflow: hidden;
276 | margin: 0px 0px 20px 25px;
277 | }
278 |
279 | .about {
280 | position: absolute;
281 | color: #FFF;
282 | left: 0px;
283 | bottom: 0px;
284 | font-size: 10px;
285 | a {
286 | color: #FFF;
287 | }
288 | }
289 |
290 | .again {
291 | position: absolute;
292 | top: 40px;
293 | right: 36px;
294 | width: 200px;
295 | }
296 |
297 | .g-on {
298 | color: green;
299 | }
300 |
301 | .level {
302 | @include opacity(0.7);
303 | display: none;
304 | background-color: #fc4e1e;
305 | border-radius: 10px;
306 | height: 100px;
307 | width: 10%;
308 | top:80px;
309 | margin-left: -10%;
310 | left: 50%;
311 | text-align: center;
312 | padding: 20px;
313 | position: absolute;
314 | div {
315 | margin-top: 10px;
316 | font-size: 24px;
317 | span {
318 | font-size: 45px;
319 | display: block;
320 | font-weight: bold;
321 | margin: 0auto;
322 | }
323 | }
324 | }
325 |
326 | .window button.music {
327 | padding: 2px;
328 | font-size: 15px;
329 | margin-top: 5px;
330 | }
331 | body > .control-help .music {
332 | font-size: 12px;
333 | padding: 0px 5px;
334 | margin: 0px;
335 | border: 0px;
336 | text-align: left;
337 | text-shadow: none;
338 | }
--------------------------------------------------------------------------------
/app/client/templates/choose.html:
--------------------------------------------------------------------------------
1 |
2 | 2. choose your project
3 |
4 |
5 | {{> projects }}
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/client/templates/game/dashboard.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | [Ø] | You're helping {{project}}
4 | | Commits: {{commits}}
5 | | Stars: {{stars}}
6 | | Level: {{level}}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/client/templates/game/level.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/client/templates/game/life.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/client/templates/gamover.html:
--------------------------------------------------------------------------------
1 |
2 | {{#if stats}}
3 | Code Freeze!
4 |
5 |
You've reached Level {{stats.LEVEL}}.
6 | with {{stats.COMMITS}} more commit(s).
7 | {{stats.STARS}} more star(s).
8 |
9 | {{# if stats.EPIC_FAIL }}
10 |
Get off the fail train and try again!
11 | {{else}}
12 |
Your contribution to this project will be recorded!
13 | {{/if}}
14 |
15 |
{{#if user}} Contributions saved to your account {{else}} Login to save your name to the scoreboard: {{/if}} {{loginButtons}}
16 | {{> projects }}
17 |
18 |
19 | {{/if}}
20 |
21 |
--------------------------------------------------------------------------------
/app/client/templates/partial/about.html:
--------------------------------------------------------------------------------
1 |
2 | built with meteor and three.js | open source
3 |
4 |
--------------------------------------------------------------------------------
/app/client/templates/partial/help.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | - arrow keys - move
4 | - q / w - < , > teleport
5 | - TAB - clockwise tele
6 | - SPACE - attack
7 | - e - enter or exit 3D
8 |
9 | - gamepad: {{status}}
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/client/templates/partial/projects.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{#each list}}
5 | -
6 | {{name}}
7 | {{commits}} commits
8 | {{stars}} stars
9 |
10 | {{/each}}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/client/templates/partial/recentScores.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Recent Games
4 |
5 | {{#each list}}
6 | -
7 |
8 | {{#if user}}
9 | - {{user.services.github.username}}
10 | {{/if}}
11 | - {{project_name}}
12 | - Level: {{session.LEVEL}}
13 | - Commits: {{session.COMMITS}}
14 | - Stars: {{session.STARS}}
15 | - {{session.SECONDS_PLAYED_STRING}}
16 |
17 |
18 | {{/each}}
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/client/templates/partial/topScores.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Top Scores
4 |
5 | {{#each list}}
6 | -
7 |
8 | {{#if user}}
9 | - {{user.services.github.username}}
10 | {{/if}}
11 | - {{project_name}}
12 | - Level: {{session.LEVEL}}
13 | - Commits: {{session.COMMITS}}
14 | - Stars: {{session.STARS}}
15 | - {{session.SECONDS_PLAYED_STRING}}
16 |
17 |
18 | {{/each}}
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/client/templates/tutorial.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2. Instructions
4 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/client/templates/webgl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0. Sorry, Need WebGl!
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/client/templates/welcome.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
cØre committer
6 |
GitHub Game Off 2012 game
7 |
8 |
9 | {{> recentScores}}
10 | {{> topScores}}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/public/img/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/bg.png
--------------------------------------------------------------------------------
/app/public/img/crOrangeMCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/crOrangeMCode.png
--------------------------------------------------------------------------------
/app/public/img/crOrangePCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/crOrangePCode.png
--------------------------------------------------------------------------------
/app/public/img/crPR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/crPR.png
--------------------------------------------------------------------------------
/app/public/img/crPurpleMCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/crPurpleMCode.png
--------------------------------------------------------------------------------
/app/public/img/crPurplePCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/crPurplePCode.png
--------------------------------------------------------------------------------
/app/public/img/crStar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/crStar.png
--------------------------------------------------------------------------------
/app/public/img/crTealMCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/crTealMCode.png
--------------------------------------------------------------------------------
/app/public/img/crTealPCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/crTealPCode.png
--------------------------------------------------------------------------------
/app/public/img/gamepad-map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/gamepad-map.png
--------------------------------------------------------------------------------
/app/public/img/player0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/player0.png
--------------------------------------------------------------------------------
/app/public/img/player1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/player1.png
--------------------------------------------------------------------------------
/app/public/img/player2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/player2.png
--------------------------------------------------------------------------------
/app/public/img/poster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/poster.png
--------------------------------------------------------------------------------
/app/public/img/tutorial-bad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/tutorial-bad.png
--------------------------------------------------------------------------------
/app/public/img/tutorial-good.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/img/tutorial-good.png
--------------------------------------------------------------------------------
/app/public/music/0.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/music/0.ogg
--------------------------------------------------------------------------------
/app/public/music/1.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/music/1.ogg
--------------------------------------------------------------------------------
/app/public/music/2.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/app/public/music/2.ogg
--------------------------------------------------------------------------------
/app/server/server.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Meteor startup
3 | */
4 | Meteor.startup(function () {
5 | // On server startup, create some players if the database is empty.
6 | if (Projects.find().count() === 0) {
7 | populateProjects();
8 | }
9 | });
10 |
11 |
12 | /**
13 | * Publish a list of projects
14 | */
15 | Meteor.publish("projects", function () {
16 | return Projects.find({}, { sort:{ commits: -1, stars: -1 }, fields:{} });
17 | });
18 |
19 |
20 | /**
21 | * Publish Recent Scores
22 | */
23 | Meteor.publish("recent_scores", function () {
24 | var self = this;
25 |
26 | var handle = Plays.find({}, { sort:{ start_time:-1 }, limit:8, fields:{}}).observe({
27 | added:function (item) {
28 | self.set("recent_scores", item._id, item);
29 | self.flush();
30 | },
31 | changed:function (item) {
32 | self.set("recent_scores", item._id, item);
33 | self.flush();
34 | }
35 | });
36 |
37 | this.onStop(function () {
38 | handle.stop();
39 | });
40 | });
41 |
42 |
43 | /**
44 | * Publish top scores
45 | */
46 | Meteor.publish("top_scores", function () {
47 | var self = this;
48 |
49 | var handle = Plays.find({}, { sort:{ commits:-1 }, limit:8, fields:{}}).observe({
50 | added:function (item) {
51 | self.set("top_scores", item._id, item);
52 | self.flush();
53 | },
54 | changed:function (item) {
55 | self.set("top_scores", item._id, item);
56 | self.flush();
57 | }
58 | });
59 |
60 | this.onStop(function () {
61 | handle.stop();
62 | });
63 | });
64 |
65 |
66 | /**
67 | * Populate the projects
68 | * runs on app 'install'
69 | */
70 | function populateProjects() {
71 |
72 | var projects = [
73 | {
74 | code:'jquery',
75 | name:'jQuery',
76 | commits:0,
77 | stars:0,
78 | color:'#3584ad'
79 | },
80 | {
81 | code:'grunt',
82 | name:'Grunt',
83 | commits:0,
84 | stars:0,
85 | color:'#5a360f'
86 | },
87 | {
88 | code:'lodash',
89 | name:'Lo-dash',
90 | commits:0,
91 | stars:0,
92 | color:'#0a1629'
93 | },
94 | {
95 | code:'android',
96 | name:'Android',
97 | commits:0,
98 | stars:0,
99 | color:'#99c726'
100 | },
101 | {
102 | code:'node',
103 | name:'Node',
104 | commits:0,
105 | stars:0,
106 | color:'#8bc451'
107 | },
108 | {
109 | code:'three',
110 | name:'Three.js',
111 | commits:0,
112 | stars:0,
113 | color:'#444449'
114 | },
115 | {
116 | code:'firefox',
117 | name:'Firefox',
118 | commits:0,
119 | stars:0,
120 | color:'#d74618'
121 | },
122 | {
123 | code:'modernizr',
124 | name:'Modernizr',
125 | commits:0,
126 | stars:0,
127 | color:'#de2d75'
128 | }
129 | ].forEach(function (project) {
130 | Projects.insert(project);
131 | });
132 | }
133 |
134 |
135 | /**
136 | * Server methods
137 | * Used with .call by the client
138 | */
139 | Meteor.methods({
140 | // options should include: title, description, x, y, public
141 | sessionUpdate:function (e) {
142 | if (e.data) {
143 | var p = Projects.findOne({_id:e.data.PROJECT});
144 |
145 | if (p) {
146 | var u = Meteor.user();
147 |
148 |
149 | if (e.data.GAMEOVER && Plays.find({user:u, start_time:e.data.START_TIME }).count() == 0) {
150 | // TODO: fix this later, no time right now.
151 | e.data.SECONDS_PLAYED = (e.data.END_TIME - e.data.START_TIME) / 1000;
152 | e.data.SECONDS_PLAYED_STRING = secondsToString(e.data.SECONDS_PLAYED);
153 | Plays.insert({
154 | user:u,
155 | start_time:e.data.START_TIME,
156 | commits:e.data.COMMITS,
157 | session:e.data,
158 | project_name:p.name
159 | });
160 | Projects.update({_id:e.data.PROJECT}, { $inc:{ stars:e.data.STARS, commits:e.data.COMMITS } });
161 | }
162 | }
163 | }
164 | },
165 | userUpdate:function (e) {
166 | Plays.update({start_time:e.data},{$set: {user: Meteor.user()}});
167 | }
168 | });
169 |
170 |
171 | /**
172 | * Create User event
173 | */
174 | Accounts.onCreateUser(function (options, user) {
175 | if (options.profile)
176 | user.profile = options.profile;
177 | return user;
178 | });
179 |
180 |
181 | /**
182 | * Temporary quick util
183 | * Quick seconds util
184 | * TODO: Remove.
185 | * @param seconds
186 | * @return {String}
187 | */
188 | function secondsToString(seconds) {
189 | var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
190 | var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
191 | return numminutes + "min " + parseInt(numseconds, 10) + "sec";
192 |
193 | }
194 |
--------------------------------------------------------------------------------
/app/shared.js:
--------------------------------------------------------------------------------
1 | Projects = new Meteor.Collection("projects");
2 | Plays = new Meteor.Collection("plays");
3 |
4 |
5 |
6 | SessionUpdates = new Meteor.Collection("sessions");
7 | /**
8 | Projects.allow({
9 | update: function (userId, parties, fields, modifier) {
10 | return true;
11 | }
12 | });
13 |
14 | */
15 |
--------------------------------------------------------------------------------
/config.rb:
--------------------------------------------------------------------------------
1 | # Require any additional compass plugins here.
2 |
3 | # Set this to the root of your project when deployed:
4 | http_path = "/"
5 | css_dir = "app/client/css"
6 | sass_dir = "app/client/scss"
7 | images_dir = "app/public/img"
8 | images_path = "static/img"
9 | sprite_load_path = "static/img/sprites"
10 | # You can select your preferred output style here (can be overridden via the command line):
11 | # output_style = :expanded or :nested or :compact or :compressed
12 |
13 | # To enable relative paths to assets via compass helper functions. Uncomment:
14 | # relative_assets = true
15 |
16 | # To disable debugging comments that display the original location of your selectors. Uncomment:
17 | # line_comments = false
18 |
19 |
20 | # If you prefer the indented syntax, you might want to regenerate this
21 | # project again passing --syntax sass, or you can uncomment this:
22 | # preferred_syntax = :sass
23 | # and then run:
24 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
25 |
--------------------------------------------------------------------------------
/misc/assets.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/misc/assets.psd
--------------------------------------------------------------------------------
/misc/bg.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vladikoff/game-off-2012/f1d0ceefcb0a88e7d3d9687f953d33695c4f328e/misc/bg.psd
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "game-off-2012",
3 | "version": "0.0.1",
4 | "private": true,
5 | "description": "",
6 | "engines": {
7 | "node": "0.8.x"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------