Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

adding game files

  • Loading branch information...
commit e88b3b30f8820bbc17610d2cc6036e33bab71697 1 parent f5b5764
@vladikoff authored
Showing with 5,617 additions and 48 deletions.
  1. +21 −0 .gitignore
  2. +13 −0 INSTALL.md
  3. +31 −48 README.md
  4. +2 −0  app/.meteor/.gitignore
  5. +10 −0 app/.meteor/packages
  6. +375 −0 app/client/css/libs/normalize.css
  7. +389 −0 app/client/css/project.css
  8. +33 −0 app/client/index.html
  9. +137 −0 app/client/js/game/App.js
  10. +915 −0 app/client/js/game/Game.js
  11. +65 −0 app/client/js/game/Menu.js
  12. +46 −0 app/client/js/game/MenuDashboard.js
  13. +32 −0 app/client/js/game/MenuGameover.js
  14. +14 −0 app/client/js/game/MenuProjects.js
  15. +11 −0 app/client/js/game/MenuWebgl.js
  16. +23 −0 app/client/js/game/SoundTrack.js
  17. +15 −0 app/client/js/game/Stats.js
  18. +100 −0 app/client/js/game/resources/Branch.js
  19. +62 −0 app/client/js/game/resources/GamepadSupport.js
  20. +81 −0 app/client/js/game/resources/Player.js
  21. +2 −0  app/client/lib/jquery.js
  22. +39 −0 app/client/lib/lodash.js
  23. +827 −0 app/client/lib/modernizr.js
  24. +7 −0 app/client/lib/webgl/Stats.js
  25. +122 −0 app/client/lib/webgl/THREEx.KeyboardState.js
  26. +45 −0 app/client/lib/webgl/THREEx.WindowResize.js
  27. +59 −0 app/client/lib/webgl/core/three/Detector.js
  28. +742 −0 app/client/lib/webgl/core/three/three.js
  29. +645 −0 app/client/lib/webgl/tween/tween.js
  30. +15 −0 app/client/scss/_mixins.scss
  31. +338 −0 app/client/scss/project.scss
  32. +7 −0 app/client/templates/choose.html
  33. +8 −0 app/client/templates/game/dashboard.html
  34. +3 −0  app/client/templates/game/level.html
  35. +3 −0  app/client/templates/game/life.html
  36. +20 −0 app/client/templates/gamover.html
  37. +3 −0  app/client/templates/partial/about.html
  38. +12 −0 app/client/templates/partial/help.html
  39. +13 −0 app/client/templates/partial/projects.html
  40. +21 −0 app/client/templates/partial/recentScores.html
  41. +21 −0 app/client/templates/partial/topScores.html
  42. +29 −0 app/client/templates/tutorial.html
  43. +8 −0 app/client/templates/webgl.html
  44. +13 −0 app/client/templates/welcome.html
  45. BIN  app/public/img/bg.png
  46. BIN  app/public/img/crOrangeMCode.png
  47. BIN  app/public/img/crOrangePCode.png
  48. BIN  app/public/img/crPR.png
  49. BIN  app/public/img/crPurpleMCode.png
  50. BIN  app/public/img/crPurplePCode.png
  51. BIN  app/public/img/crStar.png
  52. BIN  app/public/img/crTealMCode.png
  53. BIN  app/public/img/crTealPCode.png
  54. BIN  app/public/img/gamepad-map.png
  55. BIN  app/public/img/player0.png
  56. BIN  app/public/img/player1.png
  57. BIN  app/public/img/player2.png
  58. BIN  app/public/img/tutorial-bad.png
  59. BIN  app/public/img/tutorial-good.png
  60. BIN  app/public/music/0.ogg
  61. BIN  app/public/music/1.ogg
  62. BIN  app/public/music/2.ogg
  63. +193 −0 app/server/server.js
  64. +14 −0 app/shared.js
  65. +24 −0 config.rb
  66. BIN  misc/assets.psd
  67. BIN  misc/bg.psd
  68. +9 −0 package.json
View
21 .gitignore
@@ -0,0 +1,21 @@
+lib-cov
+*.seed
+*.log
+*.csv
+*.dat
+*.out
+*.pid
+*.gz
+
+pids
+logs
+results
+
+.sass_cache
+.sass-cache
+.idea
+node_modules
+npm-debug.log
+
+
+
View
13 INSTALL.md
@@ -0,0 +1,13 @@
+# The Core Committer Installation Guide
+
+## Dependencies
+* Meteor (http://meteor.com)
+
+## Running the source of the game
+* clone the source, make sure you have Meteor 0.5.2
+* ```cd app``` and ```meteor run```
+
+## Installation Notes
+* This game can save player's name to show off in the leader board, you need to configure GitHub OAuth. To do this,
+play a single game and in the Gameover screen, click on 'configure GitHub', follow the steps in the pop-up.
+
View
79 README.md
@@ -1,64 +1,47 @@
-Here at GitHub, we're no strangers to hosting or sponsoring hackathons. With the growing number of games and game development resources on GitHub, we thought it was about time to throw our very own game jam!
+# The Core Committer
-## The Challenge
+![alt text](public/misc/poster.png "The Core Committer")
-You have the entire month of November to create a **web-based** game *loosely* built around one or more of the following themes:
-* forking (or forks)
-* branching (or branches)
-* cloning (or clones)
-* pushing
-* pulling
+## Story
-What do we mean by **loosely** based on these concepts? We literally mean, *loosely* based. Some examples might be a FPS where you throw forks at water balloons, an educational game about DNA cloning, or perhaps a platformer where you push and pull objects.
-
-Your game. Your rules. You can participate as an individual or as a team. You're encouraged to use open source libraries, frameworks, graphics, and sounds.
-
-## Prizes
-
-We have 5 shiny new iPads with Retina displays (64GB wifi models) to give to our winners (or Apple Store Credit equivalent). Runners up will receive GitHub swag of their choice ($100 credit for the [GitHub Shop](http://shop.github.com/)). If you have a team submission, we'll give you Apple Store credit equal to the value of the iPad. You can split it with your teammates as appropriate.
-
-All of the winners and runners up will be showcased on our blog.
-
-<img src="http://i.imgur.com/lxZrD.png" style="border:0;">
-
-### Everyone's a winner!
+## Instructions
+* allow the code blocks to hit the related branch color
+* i.e. good: ![alt text](public/img/tutorial-good.png ""), bad: ![alt text](public/img/tutorial-bad.png "")
+* destroy the blocks that do not match the branch color
+* branches change if you destroy matching blocks or a block
+* the game gets harder over time, be prepared!
+* you lose health if you mismatch the colors or destroy good code
+* when stars get to the branch, collect then with your committer
+* use branch teleporting (tab) and 3D view to your advantage
-All participants will receive a limited edition [Coderwall](http://www.coderwall.com) badge as shown above. Winners and runners up will also get their own special version of it.
-## Judging
+## Controls
-We have a number of awesome judges who graciously volunteered to take a look at all the entries!
+### Keyboard Controls
-* [David Czarnecki](http://twitter.com/CzarneckiD), Lead Engineer at Agora Games
-* [Eric Preisz](https://twitter.com/epreisz), CEO of GarageGames
-* [Matt Hackett](https://twitter.com/#!/richtaur), Co-founder of Lost Decade Games
-* [Lee Reilly](http://twitter.com/leereilly), Gamer Dad and Software Developer at GitHub
-* [Romana Ramzan](https://twitter.com/Manak/), Denki's Player Champion. PhD Researcher. Organiser of Scottish Game Jam.
+* __arrow keys__ - move
+* __q / w__ - < , > teleport
+* __TAB__ - clockwise tele
+* __SPACE__ - attack
+* __e__ - enter or exit 3D
-## Rules
-* To qualify for entry as an **individual** you must fork the [github/game-off-2012](https://github.com/github/game-off-2012) repository to your individual account
-* To qualify for entry as a **team** you must fork the [github/game-off-2012](https://github.com/github/game-off-2012) to a [free organization account](https://github.com/settings/organizations)
-* All entries must be web-based i.e. playable in a browser. HTML5, WebGL, Unity, Torque 3D, Node JS, Flash is all possible - just be sure the source is made available on your fork.
-* You must be over the age of 13
+### GamePad Controls
+![alt text](public/img/gamepad-map.png "GamePad Controls")
-## Instructions
-* If you don't already have a GitHub account, [sign up now](https://github.com/signup/free) - it's free!
-* Fork the [github/game-off-2012](https://github.com/github/game-off-2012) repository to your individual account (or to a free organization account)
-* Be sure to follow @github on Twitter for updates
-* Make sure your code is pushed to the master branch of before Dec 1st!
-* Make sure you have a README file with a brief description, what open source projects (if any) you used, and a screenshot.
-* Your repo should have a brief description and a URL where the game is playable entered into the fields shown below (this will make our judging process easier):
+## Features
-![](https://img.skitch.com/20121010-x2ecpu95fi91us6hbfehg2dgit.png)
+*
+* HTML5 GamePad support in Chrome
+* GitHub Auth to save your game score
+* 3 Music Tracks
-Winners will be announced before Christmas :santa:
+## Notes
-# Comments / Questions / Help
+* All project names & trademarks are the property of their respective owners
+* Game music used under Creative Commons License.
+Thanks to [Flembaz (Written, produced, mixed, mastered by João Bandarra & Pedro R. Artur)] (http://soundcloud.com/flembaz/sets/indigo/)
+* Source Installation instructions are in [INSTALL.md] (INSTALL.MD)
-* New to Git, GitHub, and/or version control? Check out our [help documentation](https://help.github.com/) to get started!
-* Questions about Git/GitHub? Please email support@github.com and be sure to include 'GitHub Game Off' in the subject.
-* Questions specific to the GitHub Game Off? Please [create an issue](https://github.com/github/game-off-2012/issues/new). That will be the offical FAQ.
-* The official Twitter hashtag is [#ggo12](https://twitter.com/search/realtime?q=%23ggo12).
View
2  app/.meteor/.gitignore
@@ -0,0 +1,2 @@
+local
+meteorite
View
10 app/.meteor/packages
@@ -0,0 +1,10 @@
+# Meteor packages used by this project, one per line.
+#
+# 'meteor add' and 'meteor remove' will edit this file for you,
+# but you can also edit it by hand.
+
+#autopublish
+accounts-base
+accounts-oauth2-helper
+accounts-ui
+accounts-github
View
375 app/client/css/libs/normalize.css
@@ -0,0 +1,375 @@
+/*! normalize.css v2.0.1 | MIT License | git.io/normalize */
+
+/* ==========================================================================
+ HTML5 display definitions
+ ========================================================================== */
+
+/*
+ * Corrects `block` display not defined in IE 8/9.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/*
+ * Corrects `inline-block` display not defined in IE 8/9.
+ */
+
+audio,
+canvas,
+video {
+ display: inline-block;
+}
+
+/*
+ * Prevents modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/*
+ * Addresses styling for `hidden` attribute not present in IE 8/9.
+ */
+
+[hidden] {
+ display: none;
+}
+
+/* ==========================================================================
+ Base
+ ========================================================================== */
+
+/*
+ * 1. Sets default font family to sans-serif.
+ * 2. Prevents iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+ -ms-text-size-adjust: 100%; /* 2 */
+}
+
+/*
+ * Removes default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Links
+ ========================================================================== */
+
+/*
+ * Addresses `outline` inconsistency between Chrome and other browsers.
+ */
+
+a:focus {
+ outline: thin dotted;
+}
+
+/*
+ * Improves readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* ==========================================================================
+ Typography
+ ========================================================================== */
+
+/*
+ * Addresses `h1` font sizes within `section` and `article` in Firefox 4+,
+ * Safari 5, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+}
+
+/*
+ * Addresses styling not present in IE 8/9, Safari 5, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/*
+ * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/*
+ * Addresses styling not present in Safari 5 and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/*
+ * Addresses styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+
+/*
+ * Corrects font family set oddly in Safari 5 and Chrome.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ font-size: 1em;
+}
+
+/*
+ * Improves readability of pre-formatted text in all browsers.
+ */
+
+pre {
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+/*
+ * Sets consistent quote types.
+ */
+
+q {
+ quotes: "\201C" "\201D" "\2018" "\2019";
+}
+
+/*
+ * Addresses inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/*
+ * Prevents `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* ==========================================================================
+ Embedded content
+ ========================================================================== */
+
+/*
+ * Removes border when inside `a` element in IE 8/9.
+ */
+
+img {
+ border: 0;
+}
+
+/*
+ * Corrects overflow displayed oddly in IE 9.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* ==========================================================================
+ Figures
+ ========================================================================== */
+
+/*
+ * Addresses margin not present in IE 8/9 and Safari 5.
+ */
+
+figure {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Forms
+ ========================================================================== */
+
+/*
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/*
+ * 1. Corrects color not being inherited in IE 8/9.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/*
+ * 1. Corrects font family not being inherited in all browsers.
+ * 2. Corrects font size not being inherited in all browsers.
+ * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome
+ */
+
+button,
+input,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/*
+ * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+button,
+input {
+ line-height: normal;
+}
+
+/*
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Corrects inability to style clickable `input` types in iOS.
+ * 3. Improves usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+}
+
+/*
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+input[disabled] {
+ cursor: default;
+}
+
+/*
+ * 1. Addresses box sizing set to `content-box` in IE 8/9.
+ * 2. Removes excess padding in IE 8/9.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/*
+ * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome.
+ * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* 2 */
+ box-sizing: content-box;
+}
+
+/*
+ * Removes inner padding and search cancel button in Safari 5 and Chrome
+ * on OS X.
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/*
+ * Removes inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/*
+ * 1. Removes default vertical scrollbar in IE 8/9.
+ * 2. Improves readability and alignment in all browsers.
+ */
+
+textarea {
+ overflow: auto; /* 1 */
+ vertical-align: top; /* 2 */
+}
+
+/* ==========================================================================
+ Tables
+ ========================================================================== */
+
+/*
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
View
389 app/client/css/project.css
@@ -0,0 +1,389 @@
+/* line 4, ../scss/project.scss */
+a {
+ color: #000011;
+ font-weight: bold;
+ text-decoration: none;
+}
+/* line 18, ../../../../../.rvm/gems/ruby-1.9.3-p194/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/typography/links/_link-colors.scss */
+a:visited {
+ color: #000011;
+}
+/* line 21, ../../../../../.rvm/gems/ruby-1.9.3-p194/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/typography/links/_link-colors.scss */
+a:focus {
+ color: silver;
+}
+/* line 24, ../../../../../.rvm/gems/ruby-1.9.3-p194/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/typography/links/_link-colors.scss */
+a:hover {
+ color: silver;
+}
+/* line 27, ../../../../../.rvm/gems/ruby-1.9.3-p194/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/typography/links/_link-colors.scss */
+a:active {
+ color: #000011;
+}
+
+/* line 10, ../scss/project.scss */
+* {
+ font-family: 'Gudea', sans-serif;
+ text-transform: lowercase;
+}
+
+/* line 15, ../scss/project.scss */
+h3 {
+ margin: 0px;
+}
+
+/* line 19, ../scss/project.scss */
+ul, li {
+ list-style-type: none;
+ margin: 0px;
+ padding: 0px;
+}
+
+/* line 25, ../scss/project.scss */
+body {
+ background-color: #222222;
+ background: url("/img/bg.png");
+ overflow: hidden;
+}
+
+/* line 32, ../scss/project.scss */
+button, .topper-info {
+ position: relative;
+ overflow: visible;
+ display: inline-block;
+ padding: 0.5em 1em;
+ margin: 0;
+ text-decoration: none;
+ text-align: center;
+ text-shadow: 1px 1px 0 #fff;
+ font-size: 20px;
+ color: #333;
+}
+/* line 46, ../scss/project.scss */
+button.new-game, button.continue, .topper-info.new-game, .topper-info.continue {
+ font-weight: bold;
+ margin: 30px 0px 30px 275px;
+ width: 350px;
+ padding: 10px 20px;
+}
+
+/* line 55, ../scss/project.scss */
+button, .topper-info, .ossprojects li, .view-gamepad {
+ border: 1px solid #d4d4d4;
+ white-space: nowrap;
+ cursor: pointer;
+ outline: none;
+ background-color: #ececec;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f4f4f4), to(#ececec));
+ background-image: -moz-linear-gradient(#f4f4f4, #ececec);
+ background-image: -ms-linear-gradient(#f4f4f4, #ececec);
+ background-image: -o-linear-gradient(#f4f4f4, #ececec);
+ background-image: linear-gradient(#f4f4f4, #ececec);
+ -moz-background-clip: padding;
+ /* for Firefox 3.6 */
+ background-clip: padding-box;
+ border-radius: 0.2em;
+}
+
+/* line 72, ../scss/project.scss */
+.view-gamepad {
+ display: block;
+ text-align: center;
+ padding: 2px;
+ margin-top: 5px;
+ font-weight: normal;
+}
+
+/* line 80, ../scss/project.scss */
+button:hover, .ossprojects li:hover {
+ background-color: #ffffff;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f4f4f4), to(white));
+ background-image: -moz-linear-gradient(#f4f4f4, white);
+ background-image: -ms-linear-gradient(#f4f4f4, white);
+ background-image: -o-linear-gradient(#f4f4f4, white);
+ background-image: linear-gradient(#f4f4f4, #ffffff);
+}
+
+/* line 89, ../scss/project.scss */
+.topper-info {
+ color: #FFF;
+ text-transform: lowercase;
+ border-radius: 0;
+ cursor: none;
+ width: 100%;
+ font-size: 10px;
+ color: #000011;
+}
+
+/* line 99, ../scss/project.scss */
+.control-help {
+ font-size: 10px;
+ color: #FFF;
+ width: 100px;
+ position: absolute;
+ bottom: 0px;
+ right: 0px;
+ width: 100px;
+}
+
+/* line 109, ../scss/project.scss */
+.gamepad-status {
+ position: absolute;
+ bottom: 100px;
+ right: 0px;
+ font-size: 12px;
+ width: 100px;
+ color: #FFF;
+}
+/* line 116, ../scss/project.scss */
+.gamepad-status .connected {
+ background: #baff72;
+}
+
+/* line 121, ../scss/project.scss */
+.req-webgl .continue {
+ margin: 85px 0px 30px 170px;
+ width: 600px;
+ font-size: 23px;
+}
+
+/* line 127, ../scss/project.scss */
+.player-list li {
+ display: inline;
+}
+
+/* line 132, ../scss/project.scss */
+.req-welcome h3 {
+ color: #333333;
+ margin-left: 6px;
+}
+
+/* line 139, ../scss/project.scss */
+.req-gameover h1 {
+ margin-lefT: 75px;
+}
+/* line 142, ../scss/project.scss */
+.req-gameover .window p {
+ margin-left: 35px;
+}
+
+/* line 148, ../scss/project.scss */
+.req-project aside {
+ font-size: 20px;
+ margin: 20px 0px 20px 35px;
+}
+
+/* line 154, ../scss/project.scss */
+.frames {
+ width: 990px;
+ margin: 0 auto;
+ position: relative;
+}
+
+/* line 160, ../scss/project.scss */
+.life {
+ height: 20px;
+ width: 100%;
+ background-color: #cdeb8e;
+ background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #cdeb8e), color-stop(100%, #a5c956));
+ background-image: -webkit-linear-gradient(top, #cdeb8e 0%, #a5c956 100%);
+ background-image: -moz-linear-gradient(top, #cdeb8e 0%, #a5c956 100%);
+ background-image: -o-linear-gradient(top, #cdeb8e 0%, #a5c956 100%);
+ background-image: linear-gradient(top, #cdeb8e 0%, #a5c956 100%);
+ text-transform: lowercase;
+}
+
+/* line 172, ../scss/project.scss */
+.frame {
+ position: absolute;
+ width: 990px;
+ top: -1000px;
+ margin: 0 auto;
+}
+/* line 177, ../scss/project.scss */
+.frame h1 {
+ font-weight: normal;
+ font-size: 60px;
+ text-shadow: 2px 1px 4px #272626;
+ height: 90px;
+ color: #F3F5F7;
+ margin: 0px 0px 0px 45px;
+ padding: 0px;
+ text-transform: lowercase;
+}
+/* line 187, ../scss/project.scss */
+.frame .window {
+ -webkit-box-shadow: "inset 0px 1px 0px rgba(255,255,255, 0.25), 0px 10px 20px rgba(0,0,0, 0.7)";
+ -moz-box-shadow: "inset 0px 1px 0px rgba(255,255,255, 0.25), 0px 10px 20px rgba(0,0,0, 0.7)";
+ box-shadow: "inset 0px 1px 0px rgba(255,255,255, 0.25), 0px 10px 20px rgba(0,0,0, 0.7)";
+ width: 900px;
+ overflow: hidden;
+ background: #FFF;
+ position: relative;
+ min-height: 250px;
+ max-height: 460px;
+ margin: 0 auto;
+}
+/* line 196, ../scss/project.scss */
+.frame .window .part {
+ width: 25%;
+ float: left;
+}
+/* line 199, ../scss/project.scss */
+.frame .window .part h3 {
+ margin: 20px 0px 0px 0px;
+}
+/* line 203, ../scss/project.scss */
+.frame .window .part-large {
+ float: left;
+ width: 70%;
+ padding-right: 4%;
+}
+/* line 207, ../scss/project.scss */
+.frame .window .part-large ul {
+ margin-left: 5%;
+}
+/* line 210, ../scss/project.scss */
+.frame .window .part-large li {
+ font-size: 18px;
+ margin: 10px 0px 10px 0px;
+ list-style-type: square;
+}
+/* line 216, ../scss/project.scss */
+.frame .window h1 {
+ margin: 0px;
+ text-align: center;
+ font-weight: bold;
+ text-transform: uppercase;
+ color: #c0c0c0;
+}
+/* line 222, ../scss/project.scss */
+.frame .window h1.logo span {
+ color: #000011;
+}
+/* line 226, ../scss/project.scss */
+.frame .window .under-logo {
+ position: absolute;
+ top: 47px;
+ left: 350px;
+}
+
+/* line 234, ../scss/project.scss */
+.plays {
+ clear: both;
+}
+/* line 236, ../scss/project.scss */
+.plays .play {
+ overflow: hidden;
+ float: left;
+ width: 9%;
+ font-size: 10px;
+ border-left: 1px solid grey;
+ padding: 0.7%;
+ margin: 0.7%;
+ white-space: nowrap;
+}
+
+/* line 248, ../scss/project.scss */
+.progress {
+ display: none;
+}
+
+/* line 252, ../scss/project.scss */
+.ossprojects {
+ overflow: hidden;
+ margin: 0px 0px 20px 25px;
+}
+/* line 253, ../scss/project.scss */
+.ossprojects li {
+ cursor: pointer;
+ float: left;
+ width: 20%;
+ margin: 1%;
+ padding: 1%;
+ height: 100px;
+ overflow: hidden;
+}
+/* line 261, ../scss/project.scss */
+.ossprojects li span {
+ display: block;
+}
+/* line 265, ../scss/project.scss */
+.ossprojects li .name {
+ font-weight: bold;
+ text-align: center;
+ font-size: 24px;
+ margin-bottom: 30px;
+}
+
+/* line 279, ../scss/project.scss */
+.about {
+ position: absolute;
+ color: #FFF;
+ left: 0px;
+ bottom: 0px;
+ font-size: 10px;
+}
+/* line 285, ../scss/project.scss */
+.about a {
+ color: #FFF;
+}
+
+/* line 290, ../scss/project.scss */
+.again {
+ position: absolute;
+ top: 40px;
+ right: 36px;
+ width: 200px;
+}
+
+/* line 297, ../scss/project.scss */
+.g-on {
+ color: green;
+}
+
+/* line 301, ../scss/project.scss */
+.level {
+ filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70);
+ opacity: 0.7;
+ display: none;
+ background-color: #fc4e1e;
+ border-radius: 10px;
+ height: 100px;
+ width: 10%;
+ top: 80px;
+ margin-left: -10%;
+ left: 50%;
+ text-align: center;
+ padding: 20px;
+ position: absolute;
+}
+/* line 314, ../scss/project.scss */
+.level div {
+ margin-top: 10px;
+ font-size: 24px;
+}
+/* line 317, ../scss/project.scss */
+.level div span {
+ font-size: 45px;
+ display: block;
+ font-weight: bold;
+ margin: 0auto;
+}
+
+/* line 326, ../scss/project.scss */
+.window button.music {
+ padding: 2px;
+ font-size: 15px;
+ margin-top: 5px;
+}
+
+/* line 331, ../scss/project.scss */
+body > .control-help .music {
+ font-size: 12px;
+ padding: 0px 5px;
+ margin: 0px;
+ border: 0px;
+ text-align: left;
+ text-shadow: none;
+}
View
33 app/client/index.html
@@ -0,0 +1,33 @@
+<head>
+ <title>Core Committer - The Game</title>
+ <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+ <link href='http://fonts.googleapis.com/css?family=Gudea:400,700' rel='stylesheet' type='text/css'>
+</head>
+<body>
+
+<section class=frames>
+ <section class='frame req-gameover'>
+ {{> gameover }}
+ </section>
+
+ <section class='frame req-project'>
+ {{> choose }}
+ </section>
+
+ {{> tutorial }}
+ {{> welcome }}
+ {{> webgl }}
+</section>
+
+<section class=progress>
+ {{> dashboard}}
+ {{> life}}
+ {{> level}}
+</section>
+
+<section class='control-help'>
+ {{> help}}
+</section>
+
+{{> about}}
+</body>
View
137 app/client/js/game/App.js
@@ -0,0 +1,137 @@
+var PX_HIDE = -1500,
+ PX_SHOW = 0,
+ PX_SPEED = 300,
+ MUSIC;
+
+var RecentScores = new Meteor.Collection("recent_scores"),
+ TopScores = new Meteor.Collection("top_scores");
+
+
+// shim layer with setTimeout fallback
+window.requestAnimFrame = (function(){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function( callback ){
+ window.setTimeout(callback, 1000 / 60);
+ };
+})();
+
+Meteor.subscribe('projects');
+Meteor.subscribe("recent_scores");
+Meteor.subscribe("top_scores");
+
+
+/**
+ * Meteor startup!
+ */
+Meteor.startup(function () {
+ Session.set('gameOn', false);
+ Session.set('sessionLevel', 0);
+ Session.set('sessionStars', 0);
+ Session.set('sessionCommits', 0);
+ Session.set('pid', null);
+ Session.set('stats', null);
+ Session.set('gamepadStatus', 'off');
+
+ if (! Session.get('musicStatus')) Session.set('musicStatus', 'on');
+
+ if (Modernizr.audio) {
+ MUSIC = new SoundTrack();
+ }
+ //if (Modernizr.webgl){
+ if ( Detector.webgl ) {
+ //$('.req-webgl').animate({ top: PX_SHOW });
+ $('.req-welcome').animate({ top: PX_SHOW });
+ //startGame(); // sup debug
+
+ } else {
+ $('.req-webgl').animate({ top: PX_SHOW });
+ }
+});
+
+
+/**
+ * Meteor autorun
+ */
+Meteor.autorun(function() {
+ if (Meteor.user() && Session.equals("gameOver", true)) {
+ Meteor.call('userUpdate', { data: Session.get('st') });
+ Session.set('gameOver', false);
+ }
+});
+
+/**
+ * GitHub Login setup
+ */
+Meteor.loginWithGithub({
+ requestPermissions: ['user', 'public_repo']
+}, function (err) {
+ if (err) {
+ Session.set('errorMessage', err.reason || 'Unknown error');
+ }
+});
+
+
+/**
+ * Let the games begin
+ */
+function startGame() {
+
+ var cc;
+ var $lifeBar = $('.life'),
+ $progress = $('.progress');
+
+
+ cc = new CoreCommit(Session.get("pid"));
+ cc.addEventListener('decreaseLife', function (e) {
+ $lifeBar.css('width', e.data + '%');
+ });
+
+ cc.addEventListener('decreaseLife', function (e) {
+ $lifeBar.css('width', e.data + '%');
+ });
+
+ cc.addEventListener('start', function (e) {
+ $progress.fadeIn();
+ });
+
+ cc.addEventListener('session', function (e) {
+ Session.set('sessionCommits', e.detail.COMMITS);
+ Session.set('sessionStars', e.detail.STARS);
+ Meteor.call('sessionUpdate', { data: e.detail });
+ });
+
+ cc.addEventListener('gamepadConnected', function (e) {
+ Session.set('gamepadStatus', 'on');
+ });
+
+ cc.addEventListener('gamepadDisconnected', function (e) {
+ Session.set('gamepadStatus', 'off');
+ });
+
+ cc.addEventListener('levelUpdate', function (e) {
+ Session.set("sessionLevel", e.detail);
+ });
+
+ cc.addEventListener('gameOver', function (e) {
+ $('.req-gameover').animate({ top: PX_SHOW });
+ Session.set("gameOver", true);
+ if (e.detail.LEVEL == 0 && e.detail.COMMITS == 0 && e.detail.STARS == 0) {
+ e.detail.EPIC_FAIL = true;
+ }
+ Session.set('stats', e.detail);
+ Session.set('st', e.detail.START_TIME);
+ $progress.slideUp();
+ Session.set('gameOn', false);
+ });
+
+ cc.start();
+ Session.set('gameOn', true);
+ if (Session.get('musicStatus') == 'on') {
+ MUSIC.play();
+ }
+
+}
View
915 app/client/js/game/Game.js
@@ -0,0 +1,915 @@
+(function (exports) {
+
+ var CoreCommit = function (project) {
+ // standard global variables
+ var container, scene, camera, stats, self = this;
+
+ this.setGameVariables(project);
+ // enable events for this object
+ this.extendAsEventDispatcher();
+ // add custom events
+ this.addCustomEvents();
+
+ // CAMERA
+ var VIEW_ANGLE = 45, ASPECT = this.SCREEN_WIDTH / this.SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
+ camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
+ camera.position.set(1200, 0, 4000);
+
+ this.camera = camera;
+ this.camera.up.set(0,0,0);
+
+ // SCENE
+ scene = new THREE.Scene();
+ scene.position.set(0, 0, 0);
+ this.scene = scene;
+ scene.add(camera);
+
+ // ROTATOR
+ var crateMaterial = new THREE.MeshBasicMaterial({ color:0xff4747, transparent:true, opacity:0 });
+ this.__rotator = new THREE.Mesh(THREE.GeometryUtils.clone(new THREE.CubeGeometry(60, 25, 25)), crateMaterial);
+ this.__rotator.position.set(0,0,0);
+ this.scene.add(this.__rotator);
+
+ // RENDERER
+ this.renderer = new THREE.WebGLRenderer({antialias:false});
+ this.renderer.setSize(this.SCREEN_WIDTH, this.SCREEN_HEIGHT);
+
+ container = document.createElement('div');
+ document.body.appendChild(container);
+ container.appendChild(this.renderer.domElement);
+
+ // EVENTS
+ THREEx.WindowResize(this.renderer, this.camera);
+ //THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
+ // CONTROLS
+ //controls = new THREE.TrackballControls( camera );
+
+ // STATS
+ stats = new Stats();
+ stats.domElement.style.position = 'absolute';
+ stats.domElement.style.bottom = '0px';
+ stats.domElement.style.zIndex = 100;
+ this.stats = stats;
+ //container.appendChild(stats.domElement);
+
+ // Create git branches
+ this.generateBranches();
+ // Load Textures
+ this.loadTextures();
+
+ // GAMEPAD SUPPORT
+ // Add gamepad support
+ this.prevRawGamepadTypes = [];
+ this.gamepad = new GamepadSupport();
+
+ // Add a new player
+ this.player = new Player();
+ // set the current view
+ this.player.view = 4;
+ scene.add(this.player.mesh);
+ };
+
+
+ /**
+ * Animate the game
+ */
+ CoreCommit.prototype.start = function () {
+ var self = this;
+ this.dispatchEvent({type:'start'});
+ var endAnim = new TWEEN.Tween(this.camera.position)
+ .onUpdate(function(){
+ self.camera.lookAt(self.scene.position);
+ })
+ .to({ x:0, z:2200 }, 1500)
+ .easing(TWEEN.Easing.Sinusoidal.In).start();
+
+
+
+ this.animate(); // keep last
+
+ this.addEventListener('handleCollision', function (e) {
+ self.handleCollision(e.data);
+ });
+ };
+
+
+ /**
+ * Animate the game
+ */
+ CoreCommit.prototype.animate = function () {
+ // support gamepads
+ this.gamepad.checkGamepadSupport();
+
+ // game frame update
+ this.update();
+
+ // animates tweens
+ TWEEN.update();
+
+ // increase frames
+ this.FRAME++;
+
+ // game over
+ if (!this.PAUSED) window.requestAnimFrame(this.animate.bind(this));
+ };
+
+
+ CoreCommit.prototype.sendSession = function (s) {
+ this.dispatchEvent(this.sendSessionEvent);
+ };
+
+
+ /**
+ * increase game level, change difficulty and speeds
+ */
+ CoreCommit.prototype.trackGameLevel = function () {
+ var level,
+ maxSpeed = 3000;
+
+ if (this.FRAME > 1000) {
+ level = parseInt(this.FRAME / 1000, 10);
+ if (level > this.SESSION.LEVEL) {
+ // up level!
+ this.SESSION.LEVEL = level;
+ this.dispatchEvent(new CustomEvent('levelUpdate', { 'detail':this.SESSION.LEVEL }));
+ this.__CRATE_RATE -= 8;
+ // Increase speed here too.
+ if (this.SPEED > maxSpeed) this.SPEED -= 700;
+ }
+ }
+ };
+
+
+ /**
+ * update frame
+ */
+ CoreCommit.prototype.update = function () {
+
+ this.renderer.render(this.scene, this.camera);
+
+ var self = this,
+ kb = this.keyboard; // keyboard
+
+
+ if (this.LIFE <= 0) {
+ this.endGame();
+ }
+
+ // up the speeds, show notifications
+ this.trackGameLevel();
+
+ if (this.gamepad.GAMEPADS && this.gamepad.GAMEPADS.length > 0) {
+ if (! this.gamepadConnected) {
+ this.gamepadConnected = true;
+ this.dispatchEvent(new CustomEvent('gamepadConnected'));
+ }
+ for (var i in this.gamepad.GAMEPADS) {
+ var gamepad = this.gamepad.GAMEPADS[i];
+ if (gamepad.buttons[0] && this.AMMO) { // A - attack
+ this.AMMO = false;
+ this.NEW_BULLET = this.FRAME + 20;
+ self.playerShoot();
+ }
+
+ if (gamepad.buttons[8] || gamepad.buttons[9] || gamepad.buttons[4] || gamepad.buttons[5]) {
+ if (!this.SWITCHING) {
+ if (this.player.view == this.VIEW.TOP) {
+ self.switchMode('3d');
+ } else {
+ self.switchMode('top');
+ }
+ }
+ }
+
+ if (gamepad.buttons[2]) {
+ if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
+ self.rotateMode('left', true);
+ } else if (!this._teleporting) {
+ self.teleportPlayer(null, 'left');
+ }
+ }
+
+ if (gamepad.buttons[3]) {
+ if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
+ self.rotateMode('right', true);
+ } else if (!this._teleporting) {
+ self.teleportPlayer();
+ }
+ }
+
+ // feature disabled, always true
+ if (gamepad.buttons[6]) {
+ if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
+ self.rotateMode('left', true);
+ } else if (!this._teleporting) {
+ self.teleportPlayer(null, 'left');
+ }
+ }
+
+ if (gamepad.buttons[7] || gamepad.buttons[3]) {
+ if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
+ self.rotateMode('right', true);
+ } else if (!this._teleporting) {
+ self.teleportPlayer();
+ }
+ }
+
+ if (gamepad.buttons[1]) {
+ if (!this._teleporting) {
+ self.teleportPlayer();
+ }
+ }
+
+ if (gamepad.buttons[12] || gamepad.axes[1] < -0.25 || gamepad.axes[3] < -0.25) { // up
+ this.player.moveUpLeft(this.player.branch, this.VIEW);
+ }
+ if (gamepad.buttons[13] || gamepad.axes[1] > 0.25 || gamepad.axes[3] > 0.25) { // down
+ this.player.moveDownRight(this.player.branch, this.VIEW);
+ }
+ if (gamepad.buttons[14] || gamepad.axes[0] < -0.25 || gamepad.axes[2] < -0.25) { // left
+ this.player.moveUpLeft(this.player.branch, this.VIEW);
+ }
+ if (gamepad.buttons[15] || gamepad.axes[0] > 0.25 || gamepad.axes[2] > 0.25) { // right
+ this.player.moveDownRight(this.player.branch, this.VIEW);
+ }
+ }
+ } else {
+ if (this.gamepadConnected) {
+ this.gamepadConnected = false;
+ this.dispatchEvent('gamepadDisconnected');
+ }
+ }
+
+ // teleport between branches
+ if (kb.pressed('tab')) {
+ if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
+ self.rotateMode('right', true);
+ } else if (!this._teleporting) {
+ self.teleportPlayer();
+ }
+ }
+
+ if (( kb.pressed('up') || kb.pressed('left') )) {
+ this.player.moveUpLeft(this.player.branch, this.VIEW);
+ }
+
+ if (kb.pressed('down') || kb.pressed('right')) {
+ this.player.moveDownRight(this.player.branch, this.VIEW);
+ }
+
+
+ if (kb.pressed('space') && (this.AMMO)) {
+ this.AMMO = false;
+ this.NEW_BULLET = this.FRAME + 20;
+ self.playerShoot();
+ }
+
+ if ((this.NEW_BULLET == this.FRAME)) {
+ this.AMMO = true;
+ }
+
+ if (kb.pressed('e')) {
+ if (!this.SWITCHING) {
+ if (this.player.view == this.VIEW.TOP) {
+ self.switchMode('3d');
+ } else {
+ self.switchMode('top');
+ }
+ }
+ }
+
+
+ if (kb.pressed('q')) {
+ if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
+ self.rotateMode('left', true);
+ } else if (!this._teleporting) {
+ self.teleportPlayer(null, 'left');
+ }
+ }
+
+ if (kb.pressed('w')) {
+ if (!this.SWITCHING && this.player.view != this.VIEW.TOP) {
+ self.rotateMode('right', true);
+ } else if (!this._teleporting) {
+ self.teleportPlayer();
+ }
+ }
+
+ // generate game grates
+ if (this.NEW_CRATE_TIMER == this.FRAME) {
+ this.NEW_CRATE_TIMER = this.FRAME + this.__CRATE_RATE;
+ self.generateCrates();
+ }
+
+ _.each(self.BULLETS, function (bullet) {
+ // detect bullet collisions
+ self.detectCollision(bullet);
+
+ });
+
+ var timer = ( Date.now() * 0.04 );
+ if (self.CRATES_GENERATING) {
+ _.each(self.CRATES, function (crate) {
+
+ crate.rotation.y = 0.01 * timer;
+ crate.rotation.x = 0.01 * timer;
+ });
+ }
+
+ // STATS
+ //this.stats.update();
+ };
+
+
+ /**
+ * detect collision
+ * @param bullet
+ */
+ CoreCommit.prototype.detectCollision = function (bullet) {
+ var self = this,
+ cObj,
+ originPoint = bullet.position.clone();
+
+ // strange issue here, .intersectObjects(objects) used to report a lot of false collisions.
+ _.each(self.CRATES, function (crate) {
+ for (var vertexIndex = 0; vertexIndex < bullet.geometry.vertices.length; vertexIndex++) {
+ var localVertex = bullet.geometry.vertices[vertexIndex].clone();
+ //var globalVertex = bullet.matrix.multiplyVector3(localVertex);
+ //var directionVector = globalVertex.subSelf(bullet.position);
+
+ var ray = new THREE.Ray(originPoint, localVertex.clone().normalize());
+ var collisionResults = ray.intersectObject(crate);
+ if (collisionResults.length > 0 ) {
+ cObj = collisionResults[0].object;
+ break;
+ }
+ }
+ });
+
+ if (cObj) {
+ self.scene.remove(cObj);
+ self.scene.remove(bullet);
+ cObj.dead = true;
+ bullet.tween.stop();
+ self.BULLETS = _.without(self.BULLETS, bullet);
+ self.CRATES = _.without(self.CRATES, cObj);
+
+ // TODO: this works, but wrong. fix later
+ var e = {type:'handleCollision', data:cObj };
+ self.dispatchEvent(e);
+ }
+ };
+
+
+ /**
+ * switch to a different branch
+ */
+ CoreCommit.prototype.gameSwitchBranch = function () {
+ var newBranch = this.GAME_BRANCH;
+ while (newBranch == this.GAME_BRANCH) {
+ newBranch = parseInt(Math.random() * 3, 10); // choose a branch from 0 to 2
+ }
+ this.GAME_BRANCH = newBranch;
+ _.each(this.branches, function (branch) {
+ branch.unsetCurrent();
+ });
+ this.branches[this.GAME_BRANCH].setCurrent();
+ };
+
+
+ /**
+ * handleCollision for the crates
+ * @param crate
+ */
+ CoreCommit.prototype.handleCollision = function (crate) {
+ var crateType = crate.type;
+ if (crate.regularCrate) {
+ // switch branch if you killed a good code crate :(
+ if (crate.goodCrate) {
+ this.decreaseLife();
+ if (this.GAME_BRANCH == crate.targetBranch) {
+ this.gameSwitchBranch();
+ }
+ }
+ } else {
+ switch (crateType) {
+ case 0: // changeBranch
+ this.gameSwitchBranch();
+ break;
+ case 1: // star
+ this.SESSION.STARS++;
+ this.sendSession(this.SESSION);
+ break;
+ default:
+ this.SESSION.STARS++;
+ this.sendSession(this.SESSION);
+ break
+ }
+ }
+ };
+
+
+ /**
+ * endGame
+ */
+ CoreCommit.prototype.endGame = function () {
+ var self = this;
+
+ if (! self._gameover_anim) {
+ self._gameover_anim = true;
+ this.SESSION.END_TIME = Date.now();
+ this.SESSION.GAMEOVER = true;
+ var endAnim = new TWEEN.Tween(self.camera.position)
+ .to({ z:25000 }, 4000)
+ .easing(TWEEN.Easing.Sinusoidal.In).start();
+
+ endAnim.onComplete(function () {
+ self.PAUSED = true;
+ });
+
+ this.dispatchEvent(this.gameOverEvent);
+ this.dispatchEvent(this.sendSessionEvent);
+ }
+ };
+
+
+ /**
+ * rotate 3d view;
+ * @param type , type of rotation
+ */
+ CoreCommit.prototype.rotateMode = function (type, teleport) {
+ this.SWITCHING = true;
+ var self = this;
+ // TODO: this can be optimized.
+ var poses = [
+ new THREE.Vector3(0, -1600, 900),
+ new THREE.Vector3(-1600, 0, 900),
+ new THREE.Vector3(0, 1600, 900)
+ ];
+
+ if (type == 'left') {
+ this.player.view = (this.player.view < 2) ? ++this.player.view : 0;
+ } else {
+ this.player.view = (this.player.view > 0) ? --this.player.view : 2;
+ }
+
+ var anim2 = new TWEEN.Tween(this.camera.position).to(poses[this.player.view], 500)
+ .easing(TWEEN.Easing.Back.Out)
+ .onUpdate(function () {
+ self.camera.lookAt(self.__rotator.position);
+ })
+ .onComplete(function(){
+ self.SWITCHING = false;
+ })
+ .start();
+
+ if (teleport) {
+ this.teleportPlayer(this.player.view);
+ }
+ };
+
+
+ /**
+ * switch view mode
+ * @param direction
+ */
+ CoreCommit.prototype.switchMode = function (direction) {
+ var self = this,
+ animPos,
+ cameraLookAt;
+
+ this.SWITCHING = true;
+
+ // switch mode between top and 3d
+ if(direction == 'top') {
+ this.camera.up.set(0,0,0);
+ this.player.view = this.VIEW.TOP;
+ animPos = new THREE.Vector3(0, 0 , 2200);
+ } else {
+ animPos = this.branches[this.player.branch]._cameraPos;
+ }
+
+ if(direction == '3d') {
+ this.camera.up.set(0,0,1);
+ // if we are entering 3D, go to the player branch
+ animPos = this.branches[this.player.branch]._cameraPos;
+ this.player.view = this.player.branch;
+
+ }
+
+ var anim2 = new TWEEN.Tween(this.camera.position).to(animPos, 250)
+ .easing(TWEEN.Easing.Linear.None)
+ .onUpdate(function () {
+ self.camera.lookAt(self.__rotator.position);
+ })
+ .start();
+
+ anim2.onComplete(function () {
+ self.SWITCHING = false;
+ });
+ };
+
+
+ /**
+ * handle shooting
+ */
+ CoreCommit.prototype.playerShoot = function () {
+ var self = this,
+ shootRate = 1200,
+ shootAt,
+ geom;
+
+ // TODO: fix this
+ var crateMaterial = new THREE.MeshBasicMaterial({ color:0xff4747, transparent:true, opacity:1 });
+
+ if (this.player.branch == 0 || this.player.branch == 2) {
+ geom = new THREE.CubeGeometry(25, 60, 25)
+ } else {
+ geom = new THREE.CubeGeometry(60, 25, 25)
+ }
+
+ var bullet = new THREE.Mesh(THREE.GeometryUtils.clone(geom), crateMaterial);
+
+ bullet.position.set(this.player.mesh.position.x, this.player.mesh.position.y, 0);
+ bullet.bulletId = self.BULLETS.length;
+ this.scene.add(bullet);
+
+
+ switch (this.player.branch) {
+ case 0:
+ shootAt = { y:950 };
+ break;
+ case 1:
+ shootAt = { x:950 };
+ break;
+ case 2:
+ shootAt = { y:-950 };
+ break;
+ }
+
+ bullet.tween = new TWEEN.Tween(bullet.position).to(shootAt, shootRate)
+ .easing(TWEEN.Easing.Linear.None).start();
+
+ bullet.tween.onComplete(function () {
+ if (bullet) {
+ self.BULLETS = _.without(self.BULLETS, bullet);
+ self.scene.remove(bullet);
+ }
+ });
+
+ self.BULLETS.push(bullet);
+ };
+
+
+ /**
+ * Generate game crates
+ */
+ CoreCommit.prototype.generateCrates = function () {
+ var self = this,
+ textureFile,
+ regularCrate = false,
+ crateType,
+ cStartDistance = 3100,
+ extraDistance = 0;
+
+ this.CRATES_GENERATING = true;
+
+ // decide if we want to create a special crate
+ var lucky = parseInt(Math.random() * 50, 10); // random between 0 - 5
+ if (lucky < 10) {
+ // set the lucky crate type
+ crateType = parseInt(Math.random() * 2, 10); // random between 0 =>< 3
+ textureFile = self.otherCrateList[crateType];
+ regularCrate = false;
+ if (crateType == 1) { // if it is a star
+ extraDistance = 95;
+ }
+ } else {
+ // create a branch create
+ regularCrate = true;
+ crateType = parseInt(Math.random() * 5, 10); // random between 0 - 5
+ textureFile = self.branchCrateList[crateType];
+ }
+
+ this.__CRATE_SIZE = (this.__CRATE_SIZE >= 50) ? --this.__CRATE_SIZE : 50;
+ var size = this.__CRATE_SIZE;
+ // crate mesh
+ var crateMaterial = new THREE.MeshBasicMaterial({ map:textureFile }),
+ crate = new THREE.Mesh(THREE.GeometryUtils.clone(new THREE.CubeGeometry(size, size, size)), crateMaterial);
+
+ // crate points
+ var landingPointTween,
+ startingP = Math.floor(Math.random() * 931) - 465, // random starting point
+ landingRandomPoint = Math.floor(Math.random() * 931) - 465; // random landing point
+
+ // depending on the branch, the starting point should be different
+ // also define the tween to fly properly
+ if (this.GAME_BRANCH == 0) { // from the right
+ crate.position.set(startingP, cStartDistance, 0);
+ landingPointTween = { x:landingRandomPoint, y:-485 - extraDistance };
+ }
+ else if (this.GAME_BRANCH == 1) { // from the top
+ crate.position.set(cStartDistance, startingP, 0);
+ landingPointTween = { x:-485 - extraDistance, y:landingRandomPoint };
+ }
+ else if (this.GAME_BRANCH == 2) { // from the bottom
+ crate.position.set(startingP, -cStartDistance, 0);
+ landingPointTween = { x:landingRandomPoint, y:485 + extraDistance };
+ }
+
+ crate.regularCrate = regularCrate;
+ crate.type = crateType;
+ crate.dead = false;
+ crate.targetPosition = landingPointTween;
+
+ // set the targetBranch
+ var tb;
+ if ((crate.type == 4) || (crate.type == 5)) tb = 0;
+ if ((crate.type == 2) || (crate.type == 3)) tb = 1;
+ if ((crate.type == 0) || (crate.type == 1)) tb = 2;
+
+ crate.branch = tb;
+ crate.targetBranch = this.GAME_BRANCH;
+ crate.goodCrate = !!((this.GAME_BRANCH == tb));
+ this.scene.add(crate);
+
+ crate.animation = new TWEEN.Tween(crate.position)
+ .to(landingPointTween, this.SPEED).start();
+
+ crate.animation.onComplete(function () { // the crate is landing
+ if (crate) {
+ self.scene.remove(crate);
+ self.CRATES = _.without(self.CRATES, crate);
+ self.checkCrateLanding(crate);
+ }
+ });
+
+ this.CRATES.push(crate);
+ };
+
+
+ /**
+ * Checking if the landed crate is in the the right branch
+ * checking if the player captured the crate
+ */
+ CoreCommit.prototype.checkCrateLanding = function (crate) {
+ var pl = this.player.mesh;
+
+ // branch switcher
+ if (!crate.regularCrate && crate.type == 0) {
+ this.gameSwitchBranch();
+ }
+
+ // star
+ if (!crate.regularCrate && crate.type == 1) {
+ if (pl.position.x) {
+ var originPoint = pl.position.clone();
+
+ for (var vertexIndex = 0; vertexIndex < pl.geometry.vertices.length; vertexIndex++) {
+ var localVertex = pl.geometry.vertices[vertexIndex].clone();
+ var globalVertex = pl.matrix.multiplyVector3(localVertex);
+ var directionVector = globalVertex.subSelf(pl.position);
+
+ var ray = new THREE.Ray(originPoint, directionVector.clone().normalize());
+ var collisionResults = ray.intersectObject(crate);
+
+ // if the player position is close to a crate, the player captures it.
+ if (collisionResults.length > 0 &&
+ collisionResults[0].distance < directionVector.length()) {
+ this.SESSION.STARS++;
+ this.dispatchEvent(this.sendSessionEvent);
+ this.branches[crate.targetBranch].commit();
+ this.collectStar(crate);
+ break;
+ }
+ }
+ }
+ }
+
+ // regular crates
+ if ((!crate.dead) && crate.regularCrate) {
+ if ((crate.targetBranch != crate.branch)) {
+ // if the crate is not dead, and if it does not match a proper branch
+ this.decreaseLife();
+ // bad collision, add effects to this branch
+ this.branches[crate.targetBranch].hit();
+ } else {
+ this.SESSION.COMMITS++;
+ this.dispatchEvent(this.sendSessionEvent);
+ this.collectStar(crate);
+ }
+ }
+ };
+
+
+ /**
+ * decreaseLife
+ */
+ CoreCommit.prototype.decreaseLife = function () {
+ this.LIFE -= 10;
+ // TODO: fix this.
+ var e = {type:'decreaseLife', data:this.LIFE };
+ this.dispatchEvent(e);
+ };
+
+
+ /**
+ * collectStar
+ */
+ CoreCommit.prototype.collectStar = function (crate) {
+ var self = this,
+ starMesh = crate.material,
+ starCollect = new THREE.Mesh(THREE.GeometryUtils.clone(new THREE.CubeGeometry(50, 50, 50)), starMesh);
+
+ starCollect.position.set(crate.targetPosition.x, crate.targetPosition.y, 0);
+ this.scene.add(starCollect);
+ var cP = this.camera.position;
+ var cameraPos = new THREE.Vector3(cP.x, cP.y, cP.z);
+ cameraPos.x -= 200;
+ starCollect.animation = new TWEEN.Tween(starCollect.position)
+ .to(cameraPos, 500)
+ .easing(TWEEN.Easing.Quadratic.Out)
+ .start();
+
+ starCollect.animation.onComplete(function () {
+ if (starCollect) {
+ self.scene.remove(starCollect);
+ }
+ });
+ };
+
+
+ /**
+ * teleportPlayer between branch positions
+ */
+ CoreCommit.prototype.teleportPlayer = function (branch, direction) {
+ var self = this;
+
+ this._teleporting = true;
+ // depending on which branch you are on, clockwise teleport between branches
+ if (branch != null) {
+ this.player.branch = branch;
+ } else {
+ if (direction == "left") {
+ this.player.branch = (this.player.branch == 0) ? 2 : this.player.branch - 1;
+ } else {
+ this.player.branch = (this.player.branch == 2) ? 0 : this.player.branch + 1;
+ }
+ }
+ var r = new TWEEN.Tween(this.player.mesh.position)
+ .to(this.branches[this.player.branch].getCenter(), 300)
+ .easing(TWEEN.Easing.Back.InOut).start();
+
+ r.onComplete(function () {
+ self.player.changeTexture(self.player.branch);
+ self._teleporting = false;
+ });
+ };
+
+
+
+ /**
+ * Create Game Branches
+ */
+ CoreCommit.prototype.generateBranches = function () {
+ this.branches = [
+ // posX, posY, posZ, color, cameraPos, cameraLookAtPos, playerShift
+ new Branch(0, -480, 50, 0xd23aa1, new THREE.Vector3(0, -1600, 900), new THREE.Vector3(0, 1000, -100), -75), // purple
+ new Branch(-480, 0, 50, 0xffb139, new THREE.Vector3(-1600, 0, 900), new THREE.Vector3(1000, 0, -100), -75), // orange
+ new Branch(0, 480, 50, 0x2bc3db, new THREE.Vector3(0, 1600, 900), new THREE.Vector3(0, -1000, 220), 75) // teal
+ ];
+
+ this.branches[0].mesh.rotation.z = 90 * Math.PI / 180;
+ this.branches[2].mesh.rotation.z = 90 * Math.PI / 180;
+
+ this.branches[this.GAME_BRANCH].setCurrent();
+
+ this.scene.add(this.branches[0].mesh);
+ this.scene.add(this.branches[1].mesh);
+ this.scene.add(this.branches[2].mesh);
+
+ };
+
+
+ /**
+ * Load crate textures
+ */
+ CoreCommit.prototype.loadTextures = function () {
+
+ // Code crate textures
+ this.branchCrateList = [
+ new THREE.ImageUtils.loadTexture('img/crTealPCode.png'), // 0
+ new THREE.ImageUtils.loadTexture('img/crTealMCode.png'), // 1
+ new THREE.ImageUtils.loadTexture('img/crOrangePCode.png'), // 2
+ new THREE.ImageUtils.loadTexture('img/crOrangeMCode.png'), // 3
+ new THREE.ImageUtils.loadTexture('img/crPurplePCode.png'), // 4
+ new THREE.ImageUtils.loadTexture('img/crPurplePCode.png') // 5
+ ];
+
+ // Other crate textures
+ this.otherCrateList = [
+ new THREE.ImageUtils.loadTexture('img/crPR.png'), // 0
+ new THREE.ImageUtils.loadTexture('img/crStar.png') // 1
+ ];
+ };
+
+
+ /**
+ * Setup custom events
+ */
+ CoreCommit.prototype.addCustomEvents = function () {
+ this.sendSessionEvent = new CustomEvent('session', { 'detail':this.SESSION });
+ this.gameOverEvent = new CustomEvent('gameOver', { 'detail':this.SESSION });
+ };
+
+
+ /**
+ * Setup custom events
+ */
+ CoreCommit.prototype.setGameVariables = function (project) {
+ // game session
+ this.SESSION = {
+ START_TIME:Date.now(), END_TIME:Date.now(), LEVEL:0, STARS:0, COMMITS:0, GAMEOVER:false,
+ SWITCHED_BRANCH:0, PROJECT:project
+ };
+
+ // types of views
+ this.VIEW = {TOP:4, CENTER:1, LEFT:2, RIGHT:0};
+
+ // game branch
+ this.GAME_BRANCH = 1; // current git branch bottom - 0, left - 1, top - 2
+
+ // create a counter for frames
+ this.FRAME = 0;
+ this.SPEED = 25000;
+ this.__CRATE_RATE = 145;
+ this.__CRATE_SIZE = 100;
+
+ // a timer for crates
+ this.NEW_CRATE_TIMER = 0;
+ // a timer for bullets
+ this.NEW_BULLET = 0;
+ this.AMMO = true;
+
+ // paused state
+ this.PAUSED = false;
+
+ // enable keyboard plugin
+ this.keyboard = new THREEx.KeyboardState();
+
+ // setup player life level
+ this.LIFE = 100;
+
+ // CAMERA
+ this.SCREEN_WIDTH = window.innerWidth;
+ this.SCREEN_HEIGHT = window.innerHeight;
+
+
+ this.BULLETS = []; // track bullets
+ this.CRATES = []; // track crates
+ };
+
+
+ /**
+ * Object that during their initialization can call this function
+ * This will extend the calling object with basic
+ * Event Dispatching functionality
+ *
+ */
+ CoreCommit.prototype.extendAsEventDispatcher = function () {
+ if (this._listeners == null) {
+ this._listeners = [];
+ }
+ this.isEventDispatcher = true;
+ if (typeof(this.dispatchEvent) == 'undefined') {
+ this.dispatchEvent = function (eventObject) {
+ for (var i = 0; i < this._listeners.length; i++) {
+ var test = this._listeners[i];
+ if (test.type === eventObject.type) {
+ test.callback(eventObject);
+ break;
+ }
+ }
+ };
+ }
+ if (typeof(this.addEventListener) == 'undefined') {
+ this.addEventListener = function (type, callback, capture) {
+ // no dupes
+ var declared = false;
+ for (var i = 0; i < this._listeners.length; i++) {
+ var test = this._listeners[i];
+ if (test.type === type && test.callback === callback) {
+ declared = true;
+ break;
+ }
+ }
+ if (!declared) {
+ this._listeners.push({'type':type, 'callback':callback, 'capture':capture});
+ }
+ };
+ }
+ };
+
+ exports.CoreCommit = CoreCommit;
+
+})(window);
View
65 app/client/js/game/Menu.js
@@ -0,0 +1,65 @@
+/**
+ * Welcome Notice
+ */
+Template.welcome.events({
+ 'click .continue': function () {
+ $('.req-welcome').animate({ top: PX_HIDE }, PX_SPEED, function() {
+ $('.req-tutorial').animate({ top: PX_SHOW });
+ });
+ }
+});
+
+
+/**
+ * Project Choice
+ */
+Template.choose.events({
+ 'click .project': function (event, template) {
+ Session.set("pid", this._id);
+
+ $('.req-project').animate({ top: PX_HIDE }, PX_SPEED, function() { });
+ startGame();
+
+ return false;
+ }
+});
+
+
+/**
+ * Welcome Notice
+ */
+Template.tutorial.events({
+ 'click .continue': function () {
+ $('.req-tutorial').animate({ top: PX_HIDE }, PX_SPEED, function() {
+ $('.req-project').animate({ top: PX_SHOW });
+ });
+ }
+});
+
+Template.help.status = function () {
+ return Session.get('gamepadStatus');
+};
+
+Template.help.musicStatus = function () {
+ return Session.get('musicStatus');
+};
+
+
+/**
+ * Project Choice
+ */
+Template.help.events({
+ 'click .music': function (event, template) {
+ if (Session.get('musicStatus', 'on')) {
+ Session.set('musicStatus', 'off');
+ MUSIC.pause();
+ } else {
+ Session.set('musicStatus', 'on');
+ if (Session.get('gameOn')) {
+ MUSIC.play();
+ }
+ }
+ }
+});
+
+
View
46 app/client/js/game/MenuDashboard.js
@@ -0,0 +1,46 @@
+Template.dashboard.stars = function () {
+ var stars = Session.get('sessionStars');
+ return (stars) ? stars : 0;
+};
+
+
+Template.dashboard.project = function () {
+ var p = Projects.findOne({_id:Session.get('pid')});
+ if (p && p.name) {
+ return p.name
+ } else {
+ return 'a project'
+ }
+};
+
+
+Template.dashboard.commits = function () {
+ var commits = Session.get('sessionCommits');
+ return (commits) ? commits : 0;
+};
+
+
+Template.dashboard.level = function () {
+ var lvl = Session.get('sessionLevel');
+ return (lvl) ? lvl : 0;
+
+};
+
+Template.dashboard.rendered = function(){
+ // quick hack.
+ var s = Session.get('sessionLevel'),
+ b = Session.get('sessionLevelBackup');
+
+ if (s != b) {
+ Session.set("sessionLevelBackup", s);
+ $('.level').fadeIn(300).delay(500).fadeOut(400);
+ }
+};
+
+
+Template.level.count = function () {
+ var lvl = Session.get('sessionLevel');
+ return (lvl) ? lvl : 0;
+
+};
+
View
32 app/client/js/game/MenuGameover.js
@@ -0,0 +1,32 @@
+/**
+ * Return currently logged in user
+ */
+Template.gameover.user = function() {
+ return Meteor.user();
+};
+
+
+/**
+ * Show game stats
+ */
+Template.gameover.stats = function() {
+ return Session.get('stats');
+};
+
+
+/**
+ * List the projects for the gameover menu
+ */
+Template.gameover.list = function() {
+ return Projects.find();
+};
+
+
+/**
+ * Game Over Notice
+ */
+Template.gameover.events({
+ 'click .again': function () {
+ window.location.reload();
+ }
+});
View
14 app/client/js/game/MenuProjects.js
@@ -0,0 +1,14 @@
+/**
+ * List the project for the choosing menu
+ */
+Template.projects.list = function() {
+ return Projects.find();
+};
+
+/**
+ * Chosen project id
+ */
+Template.projects.selected = function() {
+ return Session.get('pid');
+};
+
View
11 app/client/js/game/MenuWebgl.js
@@ -0,0 +1,11 @@
+
+/**
+ * WebGl Notice
+ */
+Template.webgl.events({
+ 'click .continue': function () {
+ $('.req-webgl').animate({ top: PX_HIDE }, PX_SPEED, function() {
+ $('.req-welcome').animate({ top: PX_SHOW });
+ });
+ }
+});
View
23 app/client/js/game/SoundTrack.js
@@ -0,0 +1,23 @@
+(function (exports) {
+
+ var SoundTrack = function () {
+ this.audio = new Audio();
+ var tracks = [
+ "music/0.ogg",
+ "music/1.ogg",
+ "music/2.ogg"
+ ];
+ this.audio.src = tracks[parseInt(Math.random() * 3, 10)];
+ this.audio.volume = 0.1;
+ };
+
+ SoundTrack.prototype.play = function() {
+ this.audio.play();
+ };
+
+ SoundTrack.prototype.pause = function() {
+ this.audio.pause();
+ };
+
+ exports.SoundTrack = SoundTrack;
+})(window);
View
15 app/client/js/game/Stats.js
@@ -0,0 +1,15 @@
+/**
+ * Show game stats
+ */
+Template.recentScores.list = function() {
+ // the server controls the limit, but we are forcing it here as well.
+ return RecentScores.find().fetch().slice(0,8);
+};
+
+
+/**
+ * Show top scores
+ */
+Template.topScores.list = function() {
+ return TopScores.find().fetch().slice(0,8);
+};
View
100 app/client/js/game/resources/Branch.js
@@ -0,0 +1,100 @@
+(function (exports) {
+
+ /**
+ * Game Branch
+ * @param posX
+ * @param posY
+ * @param posZ
+ * @param color
+ * @param cameraPos
+ * @param cameraLookAtPos
+ * @constructor
+ */
+ var Branch = function (posX, posY, posZ, color, cameraPos, cameraLookAtPos, playerShift) {
+ this._posX = posX;
+ this._posY = posY;
+ this._posZ = posZ;
+ this._cameraPos = cameraPos;
+ this._cameraLookAtPos = cameraLookAtPos;
+ this._orientation = (posY == 0) ? 'x' : 'y';
+ this._playerShift = playerShift;
+
+ // branch 1 - left
+ this.mesh = new THREE.Mesh(
+ THREE.GeometryUtils.clone(new THREE.CubeGeometry(60, 900, 120)),
+ new THREE.MeshBasicMaterial({ color:color, transparent:true, opacity:0.35 }));
+ this.mesh.position.set(posX, posY, posZ);
+ };
+
+
+ /**
+ * Branch hit by an object
+ */
+ Branch.prototype.hit = function () {
+ if (!this._animated) {
+ this._animated = true;
+ this._end = new Date(Date.now() + 500);
+ this._anim();
+ }
+ };
+
+
+ /**
+ * Set this branch as current
+ */
+ Branch.prototype.setCurrent = function () {
+ this.current = true;
+ this.mesh.material.opacity = 1.0;
+ };
+
+
+ /**
+ * Unset this branch as current
+ */
+ Branch.prototype.unsetCurrent = function () {
+ this.current = false;
+ this.mesh.material.opacity = 0.35;
+ };
+
+
+ /**
+ * Animate the branch hit
+ * @private
+ */
+ Branch.prototype._anim = function () {
+ var self = this;
+
+ var timer = Date.now() * 0.01; // SPEED
+ var cos = Math.cos(timer); // Amp
+ //this.mesh.position.x += (cos > 0) ? -0.3 : 0.3;
+ this.mesh.material.opacity = Math.abs(cos);
+ if (this._end < Date.now()) {
+ this._animated = false;
+
+ this.mesh.material.opacity = (this.current) ? 1.0 : 0.35 ;
+ }
+
+ if (this._animated) window.requestAnimFrame(this._anim.bind(this));
+ };
+
+
+ Branch.prototype.commit = function () {
+ // opacity up?
+ };
+
+
+ /**
+ * Get the center position for the player teleport
+ * @return {Object}
+ */
+ Branch.prototype.getCenter = function () {
+ // TODO: patch this.
+ if (this._orientation == 'y') {
+ return {x: this._posX, y: this._posY + this._playerShift, z: this._posZ};
+ } else {
+ return {x: this._posX + this._playerShift, y: this._posY, z: this._posZ};
+ }
+ };
+
+ exports.Branch = Branch;
+})(window);
View
62 app/client/js/game/resources/GamepadSupport.js
@@ -0,0 +1,62 @@
+(function (exports) {
+
+
+ var GamepadSupport = function () {
+
+ window.addEventListener('MozGamepadConnected', this.onGamepadConnect, false);
+ window.addEventListener('MozGamepadDisconnected', this.onGamepadDisconnect, false);
+ this.prevRawGamepadTypes = []
+ };