├── .github
└── FUNDING.yml
├── LICENSE
├── README.md
├── css
├── courtain.css
├── game.css
├── index.css
├── levels.css
├── tooltip.css
└── worlds.css
├── favicon
└── icon.svg
├── images
├── aviator
│ ├── aviator.png
│ └── logo.png
├── blockly
│ └── logo_built_on.svg
├── logo
│ ├── README.md
│ └── icon.svg
├── screens
│ ├── game.gif
│ └── worlds.gif
└── worlds
│ ├── 1.png
│ ├── 2.png
│ ├── 3.png
│ ├── 4.png
│ └── README.md
├── index.html
├── js
├── game
│ └── game.js
├── gui
│ ├── animations.js
│ └── gui.js
├── index
│ └── index.js
├── ui
│ ├── gameBoard.js
│ ├── textures.js
│ └── three.js
└── worlds
│ ├── jollycolor.js
│ ├── parser.js
│ └── worlds.js
├── libs
├── blockly
│ ├── blockly_compressed.js
│ ├── blocks_compressed.js
│ ├── en.js
│ ├── javascript_compressed.js
│ └── theme.js
├── gamepad
│ └── gamepad.js
├── github
│ └── index.js
├── parallax
│ └── parallax.min.js
├── pleaserotate
│ └── pleaserotate.min.js
├── reveal
│ └── reveal.js
├── split
│ └── split.min.js
├── sweetalert2
│ └── sweetalert2.all.min.js
├── three
│ ├── OrbitControls.min.js
│ └── three.min.js
└── tween
│ └── TweenMax.min.js
├── package.json
├── solution
├── README.md
└── index.html
└── tutorial
├── css
├── black.css
└── reveal.css
├── font
├── source-sans-pro-italic.eot
├── source-sans-pro-italic.ttf
├── source-sans-pro-italic.woff
├── source-sans-pro-regular.eot
├── source-sans-pro-regular.ttf
├── source-sans-pro-regular.woff
├── source-sans-pro-semibold.eot
├── source-sans-pro-semibold.ttf
├── source-sans-pro-semibold.woff
├── source-sans-pro-semibolditalic.eot
├── source-sans-pro-semibolditalic.ttf
├── source-sans-pro-semibolditalic.woff
└── source-sans-pro.css
├── images
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
├── 7.png
├── arrow.png
├── code.png
├── debug.png
├── final1.png
├── final2.png
├── gover.png
├── gover2.png
├── gtake.png
├── gtaken2.png
├── iftaken.png
├── load.png
├── menu.gif
├── movebackward.png
├── moveforward.png
├── over.png
├── play.png
├── release.png
├── show.png
├── take.png
├── taken.png
├── turnleft.png
├── turnright.png
├── whileover.png
├── worlds.png
└── wow.gif
└── index.html
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: dopevog
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021-Present Vedant Kothari
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | # The Game 🎮
7 |
8 | **Do you like challenges? Play a `coding Game` that test your `skills` in creating algorithms. The proposed challenges have different difficulty levels, which make the game suitable for both beginner and experienced programmers.**
9 |
10 | **What are you waiting for? Test yourself and challenge friends and colleagues 😎**
11 |
12 | - **[Online Game](https://dopevog.github.io/aviation-with-code/)**
13 | - **[Tutorial](https://dopevog.github.io/aviation-with-code/tutorial/#/)**
14 |
15 |
18 |
19 |
20 |
21 |
22 | **I would recommend tools like this as `educational`👨🎓 support in schools and universities. Thanks to targeted design choices and an advanced code debugging system _(with time travel)_, The Game tries to provide the best developer experience and guide the student's `reasoning` in each challenge.**
23 |
24 |
25 |
26 | # Worlds 🌍
27 | - `BEGINNERS' FOREST` 🌲 - Designed for beginners
28 | -
29 | - `PROGRAMMERS' FARM` 🚜 - Designed for beginners
30 | -
31 | - `RECURSIVE VOLCANO` 🌋 - Designed for advanced students and teachers
32 | -
33 | - `IMPOSSIBLE OCEAN` 🐳 - Not even teachers can solve this 😎
34 | -
35 |
36 |
37 |
38 | # License
39 | This Project Has Been [MIT Licensed](LICENSE)
40 |
--------------------------------------------------------------------------------
/css/courtain.css:
--------------------------------------------------------------------------------
1 | /* --- Courtain --- */
2 | .courtain {
3 | background-color: gray;
4 |
5 | border-left: 2px solid black;
6 | border-right: 2px solid black;
7 | background-image: linear-gradient(rgb(228, 224, 186), rgb(247, 217, 170));
8 | }
9 |
10 | .aviator {
11 | position: absolute;
12 | top: 100%;
13 | left: 40%;
14 | width: 14vw;
15 | cursor: pointer;
16 | }
17 |
18 | .content {
19 | width: 100%;
20 | height: 100%;
21 | }
22 |
23 | .title {
24 | position: relative;
25 | font-family: 'Playfair Display';
26 | font-size: 22vw;
27 | line-height: 1;
28 | margin: 0;
29 | letter-spacing: -0.025em;
30 | color: #d1b790;
31 | top: calc(50vh - 18vw);
32 | margin-left: -70px;
33 | opacity: 0;
34 | text-align: center;
35 | }
36 |
37 | @media only screen and (min-width: 1200px) {
38 | .title {
39 | font-size: calc(1200px / 100 * 22);
40 | top: calc(50vh - 1200px / 100 * 18);
41 | }
42 | }
43 |
44 | .title>span {
45 | font-size: 0.3em;
46 | font-style: italic;
47 | letter-spacing: 0px;
48 | }
--------------------------------------------------------------------------------
/css/game.css:
--------------------------------------------------------------------------------
1 | /* --- Game --- */
2 | #canvas {
3 | height: 100%;
4 | width: 100%;
5 | display: flex;
6 | text-align: center;
7 | align-items: center;
8 | background-color: black;
9 | }
10 |
11 | /* --- Split ---*/
12 | .split {
13 | display: flex;
14 | flex-direction: row;
15 | height: 100%;
16 | width: 100%;
17 | transition: 0.5s height;
18 | }
19 |
20 | .split-container {
21 | height: 100%;
22 | position: relative;
23 | overflow: hidden;
24 | }
25 |
26 | .gutter {
27 | cursor: col-resize;
28 | background-color: #cccccc;
29 | }
30 |
31 | /* --- Blockly --- */
32 | .blockly-editor,
33 | #blockly-div {
34 | width: 100%;
35 | height: 100%;
36 | }
37 |
38 | /* --- Menu ---*/
39 | .game-menu {
40 | width: 680px;
41 | height: 52px;
42 |
43 | position: absolute;
44 | bottom: 50px;
45 | right: -590px;
46 | z-index: 1000;
47 |
48 | display: flex;
49 | flex-direction: row;
50 | align-items: center;
51 | justify-content: space-around;
52 | }
53 |
54 | .game-menu>div {
55 | display: flex;
56 | flex-direction: row;
57 | align-items: center;
58 | justify-content: center;
59 |
60 | }
61 |
62 | .game-menu-world {
63 | width: 130px;
64 | height: 130px;
65 | border: 1px solid black;
66 | border-radius: 120px;
67 | background-color: white;
68 | cursor: pointer;
69 | margin-right: -35px;
70 | }
71 |
72 | .game-menu-world>div {
73 | background-position: center;
74 | background-size: contain;
75 | background-repeat: no-repeat;
76 | width: 90%;
77 | height: 90%;
78 | }
79 |
80 | .game-menu-container {
81 | height: 100%;
82 | border: 1px solid black;
83 | border-radius: 100px;
84 | background-color: #ddd;
85 | padding: 0 12px;
86 | }
87 |
88 | .game-menu-board {
89 | height: 100%;
90 | width: 58px;
91 | display: flex;
92 | flex-direction: column;
93 | align-items: center;
94 | }
95 |
96 | .game-menu-buttons {
97 | width: 100%;
98 | height: 100%;
99 | display: flex;
100 | flex-direction: row;
101 | justify-content: space-around;
102 | align-content: space-around;
103 | align-items: center;
104 | }
105 |
106 | .board-moves {
107 | font-family: 'Times New Roman';
108 | font-size: 34px;
109 | color: #ddd;
110 | line-height: 30px;
111 | stroke: 1px black;
112 | text-shadow: 1.5px 1.5px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
113 | }
114 |
115 | .board-color {
116 | display: inline-block;
117 | width: 28px;
118 | height: 28px;
119 | margin-bottom: 2px;
120 | border-radius: 100%;
121 | border: solid black 1px;
122 | }
123 |
124 | .board-name {
125 | text-align: center;
126 | text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
127 | width: 100%;
128 | font-size: 17px;
129 | }
130 |
131 | .game-menu-level {
132 | font-family: 'Playfair Display';
133 | text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
134 | font-size: 25px;
135 | }
136 |
137 | .game-controller {
138 | width: 100px;
139 | top: 100px;
140 | height: calc(100% - 100px);
141 | position: absolute;
142 | overflow-y: auto;
143 | right: 0;
144 | z-index: 71;
145 | overflow-x: hidden;
146 | }
147 |
148 | .game-controller>div {
149 | padding-top: 50px;
150 | width: 100%;
151 | height: 350px;
152 | margin: auto;
153 | display: flex;
154 | flex-direction: column;
155 | align-items: center;
156 | justify-content: space-around;
157 | }
158 |
159 | /* --- Buttons ---*/
160 | .game-button {
161 | font-size: 35px;
162 | cursor: pointer;
163 | transition: 0.3 transform;
164 | filter: hue-rotate(45deg);
165 | }
166 |
167 | .game-button:hover {
168 | transform: scale(1.03);
169 | }
170 |
171 | /* --- slider --- */
172 | .slidecontainer {
173 | width: 80px;
174 | /* height: 100%; */
175 | display: inline-flex;
176 | /* margin: auto 10px; */
177 | }
178 |
179 | .slider {
180 | width: 100%;
181 | height: 6px;
182 | -webkit-appearance: none;
183 | border-radius: 10px;
184 | background: #d3d3d3;
185 | outline: none;
186 | opacity: 0.7;
187 | -webkit-transition: .2s;
188 | transition: opacity .2s;
189 | border: 1px solid #000;
190 | margin-top: 5px;
191 | }
192 |
193 | .slider:hover {
194 | opacity: 1;
195 | }
196 |
197 | .slider::-webkit-slider-thumb {
198 | -webkit-appearance: none;
199 | appearance: none;
200 | width: 18px;
201 | height: 18px;
202 | border-radius: 50%;
203 | background: #70D467;
204 | border: 1px solid #000;
205 | cursor: pointer;
206 | transition: all 0.3s;
207 | }
208 |
209 | .slider::-webkit-slider-thumb:hover {
210 | transform: scale(1.1);
211 | }
212 |
213 | .slider::-moz-range-thumb {
214 | width: 25px;
215 | height: 25px;
216 | border-radius: 50%;
217 | background: #4CAF50;
218 | cursor: pointer;
219 | }
220 |
221 | #swal2-content{
222 | font-family: monospace;
223 | }
--------------------------------------------------------------------------------
/css/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | user-select: none;
6 | font-family: 'Playfair Display';
7 | }
8 |
9 | .fullscreen {
10 | position: fixed;
11 | width: 100vw;
12 | height: 100vh;
13 | }
14 |
15 | ::-webkit-scrollbar-track {
16 | background: transparent;
17 | }
18 |
19 | ::-webkit-scrollbar {
20 | width: 7px;
21 | background-color: transparent;
22 | }
23 |
24 | ::-webkit-scrollbar-thumb {
25 | border-radius: 10px;
26 | background-color: #aaaaaa;
27 | }
--------------------------------------------------------------------------------
/css/levels.css:
--------------------------------------------------------------------------------
1 | /* --- Levels --- */
2 | .levels{
3 | overflow: hidden;
4 | display: grid;
5 | grid-template-columns: 50vw 50vw;
6 | }
7 |
8 | .worlds-chooser{
9 | background-color: aliceblue;
10 | }
11 |
12 | /* view */
13 | .world-view{
14 | width: 80%;
15 | height: 100%;
16 | margin: 0 10%;
17 | overflow: hidden;
18 | display: flex;
19 | align-items: center;
20 | }
21 |
22 | .world-view > .world {
23 | height: 0;
24 | width: 200%;
25 | padding-top: 100%;
26 | position: relative;
27 | }
28 |
29 | @media only screen and (min-width: 170vh) {
30 | .world-view > .world {
31 | width: 170vh;
32 | }
33 | }
34 |
35 | .level-view{
36 | width: 100%;
37 | height: 100%;
38 | }
39 |
40 | .levels-container{
41 | width: 100%;
42 | height: 100%;
43 |
44 | display: flex;
45 | flex-direction: column;
46 | justify-content: center;
47 | align-items: center;
48 | align-content: space-around;
49 | }
50 |
51 | .level{
52 | opacity: 0;
53 | margin-left: 120px;
54 | margin-top: 10px;
55 | }
56 |
57 | .name {
58 | position: relative;
59 | top: 60px;
60 | width: 50vw;
61 | height: 20px;
62 | font-size: 7vw;
63 | text-align: center;
64 | font-weight: bold;
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/css/tooltip.css:
--------------------------------------------------------------------------------
1 | [data-tooltip] {
2 | position: relative;
3 | z-index: 1000;
4 | }
5 |
6 | /* Positioning and visibility settings of the tooltip */
7 | [data-tooltip]:before,
8 | [data-tooltip]:after {
9 | position: absolute;
10 | visibility: hidden;
11 | opacity: 0;
12 | left: 50%;
13 | bottom: calc(100% + 5px);
14 | pointer-events: none;
15 | transition: 0.2s;
16 | will-change: transform;
17 | }
18 |
19 | /* The actual tooltip with a dynamic width */
20 | [data-tooltip]:before {
21 | content: attr(data-tooltip);
22 | padding: 10px 18px;
23 | min-width: 50px;
24 | max-width: 300px;
25 | width: max-content;
26 | width: -moz-max-content;
27 | border-radius: 6px;
28 | font-size: 14px;
29 | background-color: rgba(59, 72, 80, 0.9);
30 | background-image: linear-gradient(30deg,
31 | rgba(59, 72, 80, 0.44),
32 | rgba(59, 68, 75, 0.44),
33 | rgba(60, 82, 88, 0.44));
34 | box-shadow: 0px 0px 24px rgba(0, 0, 0, 0.2);
35 | color: #fff;
36 | text-align: center;
37 | white-space: pre-wrap;
38 | transform: translate(-50%, -5px) scale(0.5);
39 | }
40 |
41 | /* Tooltip arrow */
42 | [data-tooltip]:after {
43 | content: " ";
44 | border-style: solid;
45 | border-width: 5px 5px 0px 5px;
46 | border-color: rgba(55, 64, 70, 0.9) transparent transparent transparent;
47 | transition-duration: 0s;
48 | /* If the mouse leaves the element,
49 | the transition effects for the
50 | tooltip arrow are "turned off" */
51 | transform-origin: top;
52 | /* Orientation setting for the
53 | slide-down effect */
54 | transform: translateX(-50%) scaleY(0);
55 | }
56 |
57 | /* Tooltip becomes visible at hover */
58 | [data-tooltip]:hover:before,
59 | [data-tooltip]:hover:after {
60 | visibility: visible;
61 | opacity: 1;
62 | }
63 |
64 | /* Scales from 0.5 to 1 -> grow effect */
65 | [data-tooltip]:hover:before {
66 | transition-delay: 0.3s;
67 | transform: translate(-50%, -5px) scale(1);
68 | }
69 |
70 | /* Slide down effect only on mouseenter (NOT on mouseleave) */
71 | [data-tooltip]:hover:after {
72 | transition-delay: 0.5s;
73 | /* Starting after the grow effect */
74 | transition-duration: 0.2s;
75 | transform: translateX(-50%) scaleY(1);
76 | }
77 |
78 | /*
79 | That's it.
80 | */
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | /*
89 | If you want some adjustability
90 | here are some orientation settings you can use:
91 | */
92 |
93 | /* LEFT */
94 | /* Tooltip + arrow */
95 | [data-tooltip-location="left"]:before,
96 | [data-tooltip-location="left"]:after {
97 | left: auto;
98 | right: calc(100% + 5px);
99 | bottom: 50%;
100 | }
101 |
102 | /* Tooltip */
103 | [data-tooltip-location="left"]:before {
104 | transform: translate(-5px, 50%) scale(0.5);
105 | }
106 |
107 | [data-tooltip-location="left"]:hover:before {
108 | transform: translate(-5px, 50%) scale(1);
109 | }
110 |
111 | /* Arrow */
112 | [data-tooltip-location="left"]:after {
113 | border-width: 5px 0px 5px 5px;
114 | border-color: transparent transparent transparent rgba(55, 64, 70, 0.9);
115 | transform-origin: left;
116 | transform: translateY(50%) scaleX(0);
117 | }
118 |
119 | [data-tooltip-location="left"]:hover:after {
120 | transform: translateY(50%) scaleX(1);
121 | }
122 |
123 |
124 |
125 | /* RIGHT */
126 | [data-tooltip-location="right"]:before,
127 | [data-tooltip-location="right"]:after {
128 | left: calc(100% + 5px);
129 | bottom: 50%;
130 | }
131 |
132 | [data-tooltip-location="right"]:before {
133 | transform: translate(5px, 50%) scale(0.5);
134 | }
135 |
136 | [data-tooltip-location="right"]:hover:before {
137 | transform: translate(5px, 50%) scale(1);
138 | }
139 |
140 | [data-tooltip-location="right"]:after {
141 | border-width: 5px 5px 5px 0px;
142 | border-color: transparent rgba(55, 64, 70, 0.9) transparent transparent;
143 | transform-origin: right;
144 | transform: translateY(50%) scaleX(0);
145 | }
146 |
147 | [data-tooltip-location="right"]:hover:after {
148 | transform: translateY(50%) scaleX(1);
149 | }
150 |
151 |
152 |
153 | /* BOTTOM */
154 | [data-tooltip-location="bottom"]:before,
155 | [data-tooltip-location="bottom"]:after {
156 | top: calc(100% + 5px);
157 | bottom: auto;
158 | }
159 |
160 | [data-tooltip-location="bottom"]:before {
161 | transform: translate(-50%, 5px) scale(0.5);
162 | }
163 |
164 | [data-tooltip-location="bottom"]:hover:before {
165 | transform: translate(-50%, 5px) scale(1);
166 | }
167 |
168 | [data-tooltip-location="bottom"]:after {
169 | border-width: 0px 5px 5px 5px;
170 | border-color: transparent transparent rgba(55, 64, 70, 0.9) transparent;
171 | transform-origin: bottom;
172 | }
--------------------------------------------------------------------------------
/css/worlds.css:
--------------------------------------------------------------------------------
1 | /* --- Wolrd --- */
2 | .world {
3 | position: absolute;
4 | width: 21.5vw;
5 | height: 21.5vw;
6 |
7 | cursor: pointer;
8 | }
9 |
10 | .worlds {
11 | background-image: linear-gradient(lightblue, rgb(247, 217, 170));
12 | }
13 |
14 | .world-container {
15 | width: 100%;
16 | height: 100%;
17 | position: absolute;
18 | top: 0;
19 | }
20 |
21 | .worlds>.world:nth-child(2) {
22 | left: 3vw;
23 | top: 17%;
24 | }
25 |
26 | .worlds>.world:nth-child(3) {
27 | left: 24vw;
28 | top: 44%;
29 | }
30 |
31 | .worlds>.world:nth-child(4) {
32 | left: 48vw;
33 | top: 21%;
34 | }
35 |
36 | .worlds>.world:nth-child(5) {
37 | left: 74vw;
38 | top: 39%;
39 | }
40 |
41 | .world-frame {
42 | position: absolute;
43 | width: 100%;
44 | height: 100%;
45 |
46 | background-size: contain;
47 | background-position: center;
48 | background-repeat: no-repeat;
49 | }
50 |
51 | .world-text {
52 | position: absolute;
53 | width: 100%;
54 | height: 100%;
55 |
56 | color: #2F4F4F;
57 |
58 | font-size: 2.5vw;
59 | text-align: center;
60 | font-weight: 1000;
61 | }
62 |
63 | .links {
64 | font-weight: bold;
65 | font-size: 25px;
66 | display: flex;
67 | flex-direction: row;
68 | /* align-content: space-around; */
69 | justify-content: space-around;
70 | position: absolute;
71 | top: 10px;
72 | /* left: 0px; */
73 | right: 10px;
74 | width: 200px;
75 | font-family: 'Playfair Display';
76 | }
77 |
78 | .links>a {
79 | font-weight: normal;
80 | color: black;
81 | text-decoration: none;
82 | cursor: pointer;
83 | line-height: 30px;
84 | }
85 |
86 | .links>a:active {
87 | color: black;
88 | }
89 |
90 | .links>a:visited {
91 | color: purple;
92 | }
93 |
94 | .links>a:hover {
95 | transform: scale(1.02);
96 | }
--------------------------------------------------------------------------------
/favicon/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/aviator/aviator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/images/aviator/aviator.png
--------------------------------------------------------------------------------
/images/aviator/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/images/aviator/logo.png
--------------------------------------------------------------------------------
/images/blockly/logo_built_on.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
24 |
27 |
31 |
32 |
35 |
39 |
40 |
43 |
47 |
48 |
51 |
55 |
56 |
59 |
63 |
64 |
67 |
71 |
72 |
75 |
79 |
80 |
86 |
91 |
96 |
101 |
106 |
107 |
111 |
115 |
116 |
140 |
142 |
143 |
145 | image/svg+xml
146 |
148 |
149 |
150 |
151 |
152 |
157 |
163 |
169 |
173 |
177 |
181 |
185 |
189 |
193 |
197 |
201 |
202 |
206 |
210 |
214 |
218 |
222 |
226 |
230 |
234 |
235 |
236 |
237 |
--------------------------------------------------------------------------------
/images/logo/README.md:
--------------------------------------------------------------------------------
1 | ⚠️
2 |
3 | Icon made by [Smashicons](https://www.flaticon.com/authors/smashicons) from [www.flaticon.com](https://www.flaticon.com) is licensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0).
--------------------------------------------------------------------------------
/images/logo/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/images/screens/game.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/images/screens/game.gif
--------------------------------------------------------------------------------
/images/screens/worlds.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/images/screens/worlds.gif
--------------------------------------------------------------------------------
/images/worlds/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/images/worlds/1.png
--------------------------------------------------------------------------------
/images/worlds/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/images/worlds/2.png
--------------------------------------------------------------------------------
/images/worlds/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/images/worlds/3.png
--------------------------------------------------------------------------------
/images/worlds/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/images/worlds/4.png
--------------------------------------------------------------------------------
/images/worlds/README.md:
--------------------------------------------------------------------------------
1 | ⚠️
2 |
3 | These images were purchased on [Adobe Stock](https://stock.adobe.com/) and are not under the MIT license. If you want to use them for personal purposes, I suggest you visit the website to learn how to get a [license](https://stock.adobe.com/license-terms).
--------------------------------------------------------------------------------
/js/game/game.js:
--------------------------------------------------------------------------------
1 | /* ---- Game ---- */
2 | const Game = class {
3 | constructor(gamepad, gui) {
4 | // link the gamepad
5 | gamepad.setGame(this, this.manageRequest)
6 |
7 | this.gamepad = gamepad
8 | this.gui = gui
9 | }
10 |
11 | // init the states
12 | init() {
13 | // current focused level index
14 | this.currentLevel = 0
15 | // current showing level index
16 | this.showingLevel = 0
17 | // moves done
18 | this.moves = 0
19 |
20 | // auto show next/prior level in the gui
21 | // on START/FINISHED requests
22 | this.autoShowing = true
23 |
24 | // update the gameboard
25 | this.updateGameboard()
26 | }
27 |
28 | // update the gameboard
29 | updateGameboard() {
30 | // moves
31 | Gameboard.setMoves(this.moves)
32 | // taken color
33 | Gameboard.setTaken(this.aviator.taken)
34 | // over color
35 | Gameboard.setOver(this.getCell().blocks.slice(-1)[0])
36 | // level
37 | Gameboard.setLevel(this.showingLevel, this.levels.length)
38 | }
39 |
40 | /* ---- Request management ---- */
41 |
42 | // manage the requests
43 | manageRequest(request, back, old) {
44 | let result
45 |
46 | if (['MOVE', 'TURN', 'TAKE', 'RELEASE', 'TAKEN', 'OVER'].includes(request.method) && !old)
47 | // update the game
48 | result = this[request.method].apply(this, [].concat(request.args, request))
49 |
50 | // check the game status
51 | // update the result if the level has failed
52 | result = this.checkGameState(request, back, old) || result
53 |
54 | // update the gui
55 | return this.currentIsShowing
56 | ? this.gui.manageRequest(request, back).then(() => result)
57 | : this.gui.manageRequest().then(() => result)
58 | }
59 |
60 | /* ---- Level loading ---- */
61 |
62 | // reset the code
63 | reset() {
64 | // reset the gamepad (and the gampead.level)
65 | this.gamepad.load(this.levels.length)
66 | // load the gui
67 | this.gui.load(this.level)
68 | // load the first request
69 | this.gamepad.forward()
70 | // init
71 | this.init()
72 | }
73 | // load the levels
74 | load(levels) {
75 | this.levels = levels
76 | // load the gui
77 | this.gui.load(this.level)
78 | // init
79 | this.init()
80 | }
81 | // load next level
82 | next() {
83 | if (this.currentLevel < this.levels.length - 1) {
84 | this.currentLevel++
85 |
86 | // if autoShowing is enabled load the next level in the gui
87 | if (this.autoShowing) {
88 | this.showingLevel = this.currentLevel
89 | Gameboard.setLevel(this.currentLevel)
90 | return this.gui.load(this.level)
91 | }
92 | }
93 | }
94 | // load prior level
95 | prior() {
96 | if (this.currentLevel > 0) {
97 | this.currentLevel--
98 |
99 | // if autoShowing is enabled load the next level in the gui
100 | if (this.autoShowing) {
101 | this.showingLevel = this.currentLevel
102 | Gameboard.setLevel(this.currentLevel)
103 | return this.gui.load(this.level)
104 | }
105 | }
106 | }
107 |
108 | /* ---- Level showing ---- */
109 |
110 | // get if the current level is showing
111 | get currentIsShowing() {
112 | return this.showingLevel == this.currentLevel
113 | }
114 | // show next level in the gui
115 | showNext() {
116 | // disable autoShowing
117 | this.autoShowing = false
118 |
119 | // update the showingLevel
120 | if (this.showingLevel < this.levels.length - 1) {
121 | this.showingLevel++
122 | // update the gameboard
123 | this.updateGameboard()
124 | return this.gui.load(this.levels[this.showingLevel])
125 | }
126 | }
127 | // show prior level in the gui
128 | showPrior() {
129 | // disable autoShowing
130 | this.autoShowing = false
131 |
132 | // update the showingLevel
133 | if (this.showingLevel > 0) {
134 | this.showingLevel--
135 | // update the gameboard
136 | this.updateGameboard()
137 | return this.gui.load(this.levels[this.showingLevel])
138 | }
139 | }
140 |
141 | /* ---- Game state ---- */
142 |
143 | // return Blockly.Gamepad['STATES']['FINISHED'] if the current level is finished
144 | // otherwhise undefined
145 | get state() {
146 | for (let eCell of this.level.end) {
147 | // get the cell
148 | let sCell = this.level.start.find(c => (c.x == eCell.x) && (c.y == eCell.y))
149 |
150 | // check if the cells are equals
151 | if ((sCell == undefined) || (sCell.blocks.length < eCell.blocks.length)) return
152 | for (let i = 0; i < eCell.blocks.length; i++)
153 | if (eCell.blocks[i].color != sCell.blocks[i].color) return
154 | }
155 |
156 | return Blockly.Gamepad['STATES']['FINISHED']
157 | }
158 | // check the game state
159 | checkGameState(request, back, old) {
160 | // if the level has failed
161 | if (this.state != Blockly.Gamepad['STATES']['FINISHED'] && request.method == Blockly.Gamepad['STATES']['FINISHED'] && !old) {
162 | // show to the user
163 | swal.fire({
164 | type: 'error',
165 | title: 'Level failed!'
166 | })
167 |
168 | // end the code
169 | return {
170 | completed: true
171 | }
172 | }
173 |
174 | // if the level is completed
175 | if (this.currentLevel == this.levels.length - 1 && request.method == Blockly.Gamepad['STATES']['FINISHED'] && !old)
176 | // show to the user
177 | swal.fire({
178 | type: 'success',
179 | title: 'Level completed!',
180 | })
181 |
182 | // if the current level is finished and there's a forward request load the next level
183 | // the level is loaded with the start event
184 | // if there's only one level this method is never triggered
185 | if (request.method == Blockly.Gamepad['STATES']['STARTED'] &&
186 | (this.gamepad.state == Blockly.Gamepad['STATES']['FINISHED'] || this.gamepad.state == Blockly.Gamepad['STATES']['COMPLETED']) &&
187 | !back) this.next();
188 |
189 | // if the current level is started and there's a backward request load the prior level
190 | // the level is loaded with the finished event
191 | // if there's only one level this method is never triggered
192 | if ((request.method == Blockly.Gamepad['STATES']['FINISHED'] || request.method == Blockly.Gamepad['STATES']['COMPLETED']) &&
193 | this.gamepad.state == Blockly.Gamepad['STATES']['STARTED'] &&
194 | back) this.prior();
195 |
196 | if (['MOVE', 'TURN', 'TAKE', 'RELEASE', 'TAKEN', 'OVER'].includes(request.method))
197 | // update moves
198 | this.moves += back ? -1 : 1
199 |
200 | // update the gameboard
201 | this.updateGameboard()
202 | }
203 |
204 | /* ---- Game shortcuts ---- */
205 |
206 | get levels() {
207 | return this.gamepad.levels
208 | }
209 | get level() {
210 | return this.gamepad.level
211 | }
212 | get start() {
213 | return this.level.start
214 | }
215 | get end() {
216 | return this.level.end
217 | }
218 | get aviator() {
219 | return this.level.aviator
220 | }
221 | get width() {
222 | return this.level.dimension.width
223 | }
224 | get height() {
225 | return this.level.dimension.height
226 | }
227 | get holes() {
228 | return this.level.holes
229 | }
230 |
231 | set levels(levels) {
232 | this.gamepad.levels = levels
233 | }
234 |
235 | /* ---- Game utils ---- */
236 |
237 | // update the direction of the aviator
238 | getDirection(direction) {
239 | return (this.aviator.direction + direction) % 4
240 | }
241 | // get the position offset
242 | getOffset(direction) {
243 | return [{
244 | x: 0,
245 | y: 1
246 | },
247 | {
248 | x: -1,
249 | y: 0
250 | },
251 | {
252 | x: 0,
253 | y: -1
254 | },
255 | {
256 | x: 1,
257 | y: 0
258 | }
259 | ][direction]
260 | }
261 | // get the cell under the aviator
262 | getCell() {
263 | return this.start.find(cell => (cell.x == this.aviator.x) && (cell.y == this.aviator.y)) || this.createCell()
264 | }
265 | // create a cell under the aviator
266 | createCell() {
267 | let cell = {
268 | x: this.aviator.x,
269 | y: this.aviator.y,
270 | blocks: []
271 | }
272 |
273 | this.start.push(cell)
274 | return cell
275 | }
276 | // get if the aviator can move
277 | canMove(offset) {
278 | let {
279 | x,
280 | y
281 | } = offset
282 |
283 | return (x + this.aviator.x >= 0) &&
284 | (y + this.aviator.y >= 0) &&
285 | (x + this.aviator.x < this.width) &&
286 | (y + this.aviator.y < this.height) &&
287 | (this.holes.find(hole => (x + this.aviator.x == hole[0]) && (y + this.aviator.y == hole[1])) == undefined)
288 | }
289 |
290 | /* ---- Game methods ---- */
291 |
292 | MOVE(direction, request) {
293 | let relativeDirection = this.getDirection(direction),
294 | offset = this.getOffset(relativeDirection),
295 | canMove = this.canMove(offset),
296 | oldY = this.getCell().blocks.length
297 |
298 | // update aviator position
299 | if (canMove) {
300 | this.aviator.x += offset.x
301 | this.aviator.y += offset.y
302 | }
303 |
304 | request.data = [
305 | canMove, // can move
306 | direction == Blockly.Gamepad['INPUTS']['FORWARD'],
307 | offset.x, // x
308 | offset.y, // z
309 | oldY, // old y
310 | this.getCell().blocks.length // new y
311 | ]
312 | }
313 | TURN(direction, request) {
314 | // update the direction
315 | this.aviator.direction = this.getDirection(direction)
316 |
317 | request.data = [
318 | direction == Blockly.Gamepad['INPUTS']['RIGHT'] // if clockwise
319 | ]
320 | }
321 | TAKE(request) {
322 | let cell = this.getCell(),
323 | block = cell.blocks.pop(),
324 | oldBlock = this.aviator.taken,
325 | blocks = cell.blocks.length
326 |
327 | // update the taken block
328 | this.aviator.taken = block
329 |
330 | request.data = [
331 | cell.x, // x
332 | blocks, // y
333 | cell.y, // z
334 | block, // block
335 | oldBlock // old block
336 | ]
337 | }
338 | RELEASE(request) {
339 | let cell = this.getCell(),
340 | block = this.aviator.taken,
341 | blocks = cell.blocks.length
342 |
343 | // update the taken block
344 | if (block != undefined) {
345 | this.aviator.taken = undefined
346 | cell.blocks.push(block)
347 | }
348 |
349 | request.data = [
350 | cell.x, // x
351 | blocks, // y
352 | cell.y, // z
353 | block, // the released block
354 | ]
355 | }
356 | TAKEN(color) {
357 | let block = this.aviator.taken
358 |
359 | // return true if the block exist and it is of the choosen color
360 | // or the choosen color is the jollycolor
361 | return {
362 | return: block && (block.color === color || color === JollyColor)
363 | }
364 | }
365 | OVER(color) {
366 | let block = this.getCell().blocks.slice(-1)[0]
367 |
368 | // return true if the block exist and it is of the choosen color
369 | // or the choosen color is the jollycolor
370 | return {
371 | return: block && (block.color === color || color === JollyColor)
372 | }
373 | }
374 | }
--------------------------------------------------------------------------------
/js/gui/animations.js:
--------------------------------------------------------------------------------
1 | /* --- Animations --- */
2 | class Animations {
3 | // generate the animation with the given args
4 | // a promise is returned within the .complete() method
5 | static animate(args) {
6 | let complete,
7 | promise = new Promise(onComplete => {
8 | // timepline
9 | let tl = new TimelineLite({
10 | onComplete: function(){
11 | onComplete()
12 | }
13 | })
14 |
15 | // load the animation
16 | args.forEach(animation => tl.to.apply(tl, animation))
17 |
18 | // complete the animation
19 | complete = () => tl.progress(1)
20 | })
21 |
22 | // calling .complete() will end the animation and resolve the promise
23 | promise.complete = complete
24 |
25 | return promise
26 | }
27 | }
--------------------------------------------------------------------------------
/js/gui/gui.js:
--------------------------------------------------------------------------------
1 | /* --- Gui --- */
2 | class Gui {
3 | constructor() {
4 | this.asynchronizer = new Blockly.Gamepad.Asynchronizer(
5 | GUI,
6 | function (stage) {
7 | // bind to this because of the asynchronizer
8 | this.Three = Three
9 | this.Three.clear()
10 |
11 | this.holes = stage.holes
12 | this.width = stage.dimension.width
13 | this.height = stage.dimension.height
14 |
15 | this.grid = new Array(this.width)
16 | this.translucentGrid = new Array(this.width)
17 |
18 | // create the grid
19 | for (let i = 0; i < this.width; i++) {
20 | this.grid[i] = new Array(this.height)
21 | this.translucentGrid[i] = new Array(this.height)
22 |
23 | for (let j = 0; j < this.height; j++) {
24 | this.grid[i][j] = []
25 | this.translucentGrid[i][j] = []
26 | }
27 | }
28 |
29 | this.createGrid()
30 |
31 | // load the blocks (start)
32 | for (const column of stage.start) {
33 | let x = column.x,
34 | y = column.y,
35 | z
36 | for (z = 0; z < column.blocks.length; z++)
37 | this.createBlock(
38 | x,
39 | z,
40 | y,
41 | column.blocks[z],
42 | false
43 | )
44 | }
45 |
46 | // create the airplane
47 | this.createAirPlane(
48 | stage.aviator.x,
49 | this.grid[stage.aviator.x][stage.aviator.y].length,
50 | stage.aviator.y,
51 | stage.aviator.direction,
52 | stage.aviator.taken
53 | )
54 |
55 | // load the blocks (end)
56 | for (const column of stage.end) {
57 | let x = column.x,
58 | y = column.y,
59 | z
60 | for (z = 0; z < column.blocks.length; z++)
61 | this.createBlock(
62 | x,
63 | z,
64 | y,
65 | column.blocks[z],
66 | true
67 | )
68 | }
69 |
70 | // render the canvas
71 | this.render()
72 | })
73 |
74 | // loading promise
75 | this.loading = Blockly.Gamepad.utils.promiseWrapper()
76 | this.loading.resolve()
77 | }
78 |
79 | // manage the requests
80 | manageRequest(request, back) {
81 | let ac = this.asynchronizer.async
82 |
83 | return new Promise(async resolve => {
84 | // if the game is resetting the current request is skipped
85 | const skipRequest = this.loading.isPending()
86 | // await game resetting
87 | await this.loading
88 | // skip the request
89 | if(skipRequest) return resolve()
90 |
91 | // surrounded with try and catch because the GUI crashes when it is resetted
92 | try {
93 | if (request && ['MOVE', 'TURN', 'TAKE', 'RELEASE'].includes(request.method))
94 | // load the animation
95 | await ac[request.method].apply(ac, [back].concat(request.data))
96 | else
97 | // await some time
98 | await ac.timer()
99 | } catch (error) { Blockly.Gamepad.utils.errorHandler(error) }
100 |
101 | resolve()
102 | })
103 | }
104 |
105 | // load a stage
106 | load(stage) {
107 | // if it is resetting return
108 | if (this.loading.isPending()) return
109 |
110 | // set loading promise
111 | this.loading = Blockly.Gamepad.utils.promiseWrapper()
112 | // load the gui
113 | this.asynchronizer.reset()
114 | this.asynchronizer.run(stage)
115 | // solve the promise
116 | this.loading.resolve()
117 | }
118 |
119 | // remove animation
120 | removeAnimation() {
121 | let ac = this.asynchronizer.async, tid
122 |
123 | // if the user click the forward/backward buttons 2 or more times within
124 | // 'clickTime' milliseconds of each other the animation will not show
125 | ac.tid = tid = setTimeout(() => {
126 | if (ac.tid !== tid) {
127 | guiData.time = 0
128 | ac.animations && ac.animations.complete()
129 | }else{
130 | guiData.time = 1
131 | }
132 | }, guiData.clickTime)
133 | }
134 | }
135 |
136 | /* --- GUI --- */
137 | class GUI {
138 | // timer
139 | timer() {
140 | return new Promise(resolve => setTimeout(resolve, this.duration * 400))
141 | }
142 | // render the scene
143 | render() {
144 | try {
145 | // update the sprites
146 | this.airPlane.updatePropeller()
147 | this.airPlane.pilot.updateHairs()
148 | this.Three.render()
149 |
150 | // render
151 | requestAnimationFrame(() => this.render())
152 | } catch (error) {
153 | Blockly.Gamepad.utils.errorHandler(error)
154 | }
155 | }
156 |
157 | // easing
158 | get ease() {
159 | return (guiData.speed < 4) ?
160 | Power2.easeInOut :
161 | Power0.easeNone
162 | }
163 | // duration
164 | get duration() {
165 | return guiData.time / guiData.speed
166 | }
167 |
168 | // half floor width
169 | get hfw() {
170 | return this.width * guiData.size / 2
171 | }
172 | // half floor height
173 | get hfh() {
174 | return this.height * guiData.size / 2
175 | }
176 | // get the y of block or airPlane
177 | getHeight(blocks, ofAirPlane) {
178 | return ofAirPlane
179 | ? blocks * (guiData.blockSpace + guiData.blockSize) + guiData.airPlaneDistance + guiData.blockSpace
180 | : (blocks + 1) * (guiData.blockSpace + guiData.blockSize) - guiData.blockSize / 2
181 | }
182 | // get the rotation angle
183 | getRotation(direction) {
184 | return (Math.PI / 2) * (3 - direction)
185 | }
186 | // get the position { x, z }
187 | getCoordinates(x, z) {
188 | return {
189 | z: z * guiData.size - this.hfh + guiData.size / 2,
190 | x: x * guiData.size - this.hfw + guiData.size / 2
191 | }
192 | }
193 | // get the angle of the rearing
194 | getAngle(newY, oldY, up) {
195 | let delta = (newY || 1) - (oldY || 1)
196 | return Math.atan(delta * (up ? 1 : -1)) / 2
197 | }
198 |
199 | // create the floor grid
200 | createGrid() {
201 | let group = new THREE.Group(),
202 | cube, x, z, type, coords
203 |
204 | for (x = 0; x < this.width; x++) {
205 | for (z = 0; z < this.height; z++) {
206 | // if there isn't a hole
207 | if (this.holes.find(c => (c[0] == x) && (c[1] == z)) == undefined) {
208 |
209 | // generate the cell
210 | type = ((x + z % 2) % 2 == 1) ? 1 : 2
211 | cube = new Textures.Cell(type)
212 |
213 | // set the position
214 | coords = this.getCoordinates(x, z)
215 | cube.mesh.position.set(
216 | coords.x,
217 | -guiData.floorDepth / 2,
218 | coords.z)
219 |
220 | // add the mesh
221 | group.add(cube.mesh)
222 | }
223 | }
224 | }
225 |
226 | this.Three.scene.add(group)
227 | }
228 | // create a block
229 | createBlock(x, y, z, block, translucent) {
230 | let cube = new Textures.Block(block.color, translucent),
231 | coords = this.getCoordinates(x, z)
232 |
233 | // add the mesh in the grid
234 | translucent
235 | ? this.translucentGrid[x][z].push(cube.mesh)
236 | : this.grid[x][z].push(cube.mesh)
237 |
238 | // set the position
239 | cube.mesh.position.set(coords.x, this.getHeight(y), coords.z)
240 |
241 | this.Three.scene.add(cube.mesh)
242 | }
243 | // create the airPlane
244 | createAirPlane(x, y, z, direction, taken) {
245 | this.airPlane = new Textures.AirPlane()
246 |
247 | // set the position
248 | let coord = this.getCoordinates(x, z)
249 | this.airPlane.mesh.position.set(coord.x, this.getHeight(y || 1, true), coord.z)
250 |
251 | // generate the taken block
252 | if (taken) {
253 | let { mesh } = new Textures.Block(taken.color, false)
254 | mesh.scale.set(guiData.takenScale, guiData.takenScale, guiData.takenScale)
255 |
256 | this.airPlane.setBlock(mesh)
257 |
258 | mesh.position.x = -guiData.carrX
259 | mesh.position.y = -guiData.carrY
260 | mesh.position.z = 0
261 | }
262 |
263 | this.airPlane.mesh.rotation.y = this.getRotation(direction)
264 | this.Three.scene.add(this.airPlane.mesh)
265 | }
266 |
267 | /* --- methods --- */
268 |
269 | MOVE(back, canMove, up, offX, offZ, oldY, newY) {
270 | offX *= guiData.size
271 | offZ *= guiData.size
272 |
273 | if (canMove) {
274 | // animations
275 | return this.animations = Animations.animate(
276 | [
277 | [this.airPlane.mesh.position, this.duration, {
278 | x: this.airPlane.mesh.position.x + offX * (back ? -1 : 1),
279 | y: this.getHeight((back ? oldY : newY) || 1, true),
280 | z: this.airPlane.mesh.position.z + offZ * (back ? -1 : 1),
281 | ease: this.ease
282 | }],
283 | [this.airPlane.mesh.rotation, this.duration * .40, {
284 | z: this.getAngle(newY, oldY, up),
285 | ease: Power0.easeIn
286 | }, '-=' + this.duration],
287 | [this.airPlane.mesh.rotation, this.duration * .60, {
288 | z: 0,
289 | ease: Power1.easeOut
290 | }, '-=' + this.duration * .40]
291 | ]
292 | )
293 | } else {
294 | // crash animation
295 | return this.animations = Animations.animate([
296 | [
297 | this.airPlane.mesh.position, this.duration / 2, {
298 | x: this.airPlane.mesh.position.x + offX / 2,
299 | z: this.airPlane.mesh.position.z + offZ / 2,
300 | ease: this.ease
301 | }
302 | ],
303 | [
304 | this.airPlane.mesh.position, this.duration / 2, {
305 | x: this.airPlane.mesh.position.x,
306 | z: this.airPlane.mesh.position.z,
307 | ease: this.ease
308 | }
309 | ]
310 | ])
311 | }
312 | }
313 | TURN(back, clockwise) {
314 | clockwise = back ? !clockwise : clockwise
315 |
316 | // animations vector
317 | let rotationMatrix = new THREE.Matrix4().extractRotation(this.airPlane.mesh.matrixWorld),
318 | vector = new THREE.Vector3(Math.PI / 20 * (clockwise ? 1 : -1), 0, Math.PI / 20),
319 | y = this.airPlane.mesh.rotation.y,
320 | delta = 2 / 3
321 |
322 | // normalize the vector
323 | vector.applyMatrix4(rotationMatrix)
324 |
325 | // animations
326 | return this.animations = Animations.animate([
327 | [
328 | this.airPlane.mesh.rotation, this.duration, {
329 | y: y + Math.PI / 2 * (clockwise ? -1 : 1),
330 | ease: this.ease
331 | }
332 | ],
333 | [
334 | this.airPlane.mesh.rotation, this.duration * delta, {
335 | x: vector.x,
336 | ease: Power2.easeOut
337 | }, "-=" + this.duration
338 | ],
339 | [
340 | this.airPlane.mesh.rotation, this.duration * (1 - delta), {
341 | x: 0,
342 | z: 0,
343 | ease: Power1.easeInOut
344 | }, "-=" + this.duration * (1 - delta)
345 | ]
346 | ])
347 | }
348 | TAKE(back, x, y, z, block, oldBlock) {
349 | // The opposite animation is .RELEASE()
350 | if (back) return this.RELEASE(false, x, y, z, block, oldBlock)
351 |
352 | // animations vector
353 | let mesh = this.grid[x][z].pop(),
354 | rotationMatrix = new THREE.Matrix4().extractRotation(this.airPlane.mesh.matrixWorld),
355 | vector = new THREE.Vector3(-guiData.carrX, guiData.airPlaneDistance - guiData.blockSize / 2 - guiData.carrY, 0)
356 |
357 | // normalize the vector
358 | vector.applyMatrix4(rotationMatrix)
359 |
360 | let animations = [[{}, this.duration, {}]]
361 |
362 | // animations
363 | if (block != undefined)
364 | animations = [
365 | [mesh.scale, this.duration, {
366 | y: guiData.takenScale,
367 | x: guiData.takenScale,
368 | z: guiData.takenScale,
369 | ease: this.ease
370 | }],
371 | [mesh.position, this.duration, {
372 | x: mesh.position.x + vector.x,
373 | y: mesh.position.y + vector.y,
374 | z: mesh.position.z + vector.z,
375 | ease: this.ease
376 | }, "-=" + this.duration,],
377 | [this.airPlane.mesh.position, this.duration, {
378 | y: this.getHeight(y, true),
379 | ease: this.ease,
380 | onComplete: () => {
381 | try {
382 | // hang the block on the plane
383 | this.airPlane.setBlock(mesh)
384 | mesh.position.x = -guiData.carrX
385 | mesh.position.y = -guiData.carrY
386 | mesh.position.z = 0
387 | } catch (error) { }
388 | }
389 | }, "-=" + this.duration]
390 | ]
391 |
392 | // animations to remove the old block
393 | if (oldBlock != undefined)
394 | animations.push([this.airPlane.block.scale, this.duration / 3, {
395 | y: guiData.minScale,
396 | x: guiData.minScale,
397 | z: guiData.minScale,
398 | ease: Power0.easeOut,
399 | onComplete: () => {
400 | try {
401 | this.airPlane.popBlock()
402 | } catch (error) { }
403 | }
404 | }, "-=" + this.duration])
405 |
406 | // animations
407 | if (y == 0 && block)
408 | animations.push([this.airPlane.mesh.position, this.duration / 2, {
409 | y: this.getHeight(1, true),
410 | ease: this.ease,
411 | }])
412 |
413 | return this.animations = Animations.animate(animations)
414 | }
415 | RELEASE(back, x, y, z, block, oldBlock) {
416 | // The opposite animation is .TAKE()
417 | if (back) return this.TAKE(false, x, y, z, block, oldBlock)
418 |
419 | let wf = x * guiData.size - this.hfw + guiData.size / 2,
420 | hf = z * guiData.size - this.hfh + guiData.size / 2,
421 | hy = this.getHeight(y),
422 | mesh = this.airPlane.block,
423 | // animation vector
424 | rotationMatrix = new THREE.Matrix4().extractRotation(this.airPlane.mesh.matrixWorld),
425 | vector = new THREE.Vector3(-guiData.carrX, guiData.airPlaneDistance - guiData.blockSize / 2 - guiData.carrY, 0)
426 |
427 | // normalize the vector
428 | vector.applyMatrix4(rotationMatrix)
429 |
430 | if (oldBlock) {
431 | // generate the old block
432 | oldBlock = new Textures.Block(oldBlock.color, false).mesh
433 | oldBlock.scale.set(guiData.minScale, guiData.minScale, guiData.minScale)
434 | }
435 |
436 | let animations = []
437 |
438 | // animations
439 | if (y == 0 && block)
440 | animations.push([this.airPlane.mesh.position, this.duration / 2, {
441 | y: this.getHeight(0, true),
442 | ease: this.ease
443 | }])
444 |
445 | if (block)
446 | animations.push(
447 | [{}, .1, {
448 | onStart: () => {
449 | try {
450 | this.airPlane.popBlock()
451 | mesh.position.set(
452 | wf + vector.x,
453 | hy + vector.y,
454 | hf + vector.z
455 | )
456 |
457 | this.grid[x][z].push(mesh)
458 | this.Three.scene.add(mesh)
459 | } catch (error) { }
460 | }
461 | }],
462 | [
463 | mesh.scale, this.duration, {
464 | y: 1,
465 | x: 1,
466 | z: 1,
467 | ease: this.ease
468 | }
469 | ],
470 | [
471 | mesh.position, this.duration, {
472 | x: wf,
473 | y: hy,
474 | z: hf,
475 | ease: this.ease
476 | }, "-=" + this.duration
477 | ],
478 | [
479 | this.airPlane.mesh.position, this.duration, {
480 | y: this.getHeight(y + 1, true),
481 | ease: this.ease
482 | }, "-=" + this.duration
483 | ])
484 |
485 | // animations to restore the old block
486 | if (oldBlock)
487 | animations.push([oldBlock.scale, this.duration / 3, {
488 | y: guiData.takenScale,
489 | x: guiData.takenScale,
490 | z: guiData.takenScale,
491 | ease: Power0.easeIn,
492 | onStart: () => {
493 | this.airPlane.setBlock(oldBlock)
494 | oldBlock.position.x = -guiData.carrX
495 | oldBlock.position.y = -guiData.carrY
496 | oldBlock.position.z = 0
497 | }
498 | }, "-=" + (block ? this.duration / 3 : 0)])
499 |
500 | return this.animations = Animations.animate(animations)
501 | }
502 | }
503 |
504 | /* --- data --- */
505 | const guiData = {
506 | time: 1,
507 | speed: 1,
508 | clickTime: 350,
509 | size: 108,
510 | blockSize: 52,
511 | blockSpace: 8,
512 | airPlaneDistance: 50,
513 | carrX: 25,
514 | carrY: 30,
515 | crashDistance: 22,
516 | floorDepth: 4,
517 | takenScale: .4,
518 | minScale: .1
519 | }
--------------------------------------------------------------------------------
/js/index/index.js:
--------------------------------------------------------------------------------
1 | /* --- Inputs --- */
2 | Blockly.Gamepad['INPUTS'] = {
3 | 'FORWARD': '0',
4 | 'RIGHT': '1',
5 | 'BACKWARD': '2',
6 | 'LEFT': '3'
7 | }
8 |
9 | /* --- Init --- */
10 | Blockly.Gamepad.init({
11 | 'blocks': {
12 | 'move': {
13 | method: 'MOVE',
14 | args: [{
15 | field: 'DIRECTION',
16 | get: parseInt
17 | }],
18 | json: {
19 | "message0": "Move %1",
20 | 'args0': [{
21 | 'type': 'field_dropdown',
22 | 'name': 'DIRECTION',
23 | 'options': [
24 | ['forward', Blockly.Gamepad['INPUTS']['FORWARD']],
25 | ['backward', Blockly.Gamepad['INPUTS']['BACKWARD']]
26 | ]
27 | }],
28 | "previousStatement": null,
29 | "nextStatement": null,
30 | "style": "move_blocks",
31 | "tooltip": "Move the plane one step forward or backward",
32 | "helpUrl": "https://dopevog.github.io/aviation-with-code/tutorial/#/4"
33 | }
34 | },
35 | 'turn': {
36 | method: 'TURN',
37 | args: [{
38 | field: 'DIRECTION',
39 | get: parseInt
40 | }],
41 | json: {
42 | "message0": "Turn %1",
43 | 'args0': [{
44 | 'type': 'field_dropdown',
45 | 'name': 'DIRECTION',
46 | 'options': [
47 | ['right ↻', Blockly.Gamepad['INPUTS']['RIGHT']],
48 | ['left ↺', Blockly.Gamepad['INPUTS']['LEFT']]
49 | ]
50 | }],
51 | "previousStatement": null,
52 | "nextStatement": null,
53 | "style": "move_blocks",
54 | "tooltip": "Turn the plane right or left",
55 | "helpUrl": "https://dopevog.github.io/aviation-with-code/tutorial/#/5"
56 | }
57 | },
58 | 'take': {
59 | method: 'TAKE',
60 | json: {
61 | "message0": "take ✊",
62 | "previousStatement": null,
63 | "nextStatement": null,
64 | "style": "action_blocks",
65 | "tooltip": "Take the block under the plane",
66 | "helpUrl": "https://dopevog.github.io/aviation-with-code/tutorial/#/6"
67 | }
68 | },
69 | 'release': {
70 | method: 'RELEASE',
71 | json: {
72 | "message0": "release 🖐",
73 | "previousStatement": null,
74 | "nextStatement": null,
75 | "style": "action_blocks",
76 | "tooltip": "Release the block under the plane",
77 | "helpUrl": "https://dopevog.github.io/aviation-with-code/tutorial/#/7"
78 | }
79 | },
80 | 'taken': {
81 | method: 'TAKEN',
82 | args: [{
83 | field: 'colour',
84 | get: colour => colour.toLowerCase()
85 | }],
86 | order: Blockly.JavaScript.ORDER_NONE,
87 | json: {
88 | "message0": "taken %1",
89 | "args0": [{
90 | "type": "field_colour",
91 | "name": "colour",
92 | "colour": JollyColor
93 | }],
94 | "output": "Boolean",
95 | "style": "logic_blocks",
96 | "tooltip": "Is the block taken of the chosen color?",
97 | "helpUrl": "https://dopevog.github.io/aviation-with-code/tutorial/#/8"
98 | }
99 | },
100 | 'over': {
101 | method: 'OVER',
102 | args: [{
103 | field: 'colour',
104 | get: colour => colour.toLowerCase()
105 | }],
106 | order: Blockly.JavaScript.ORDER_NONE,
107 | json: {
108 | "message0": "over %1",
109 | "args0": [{
110 | "type": "field_colour",
111 | "name": "colour",
112 | "colour": JollyColor
113 | }],
114 | "output": "Boolean",
115 | "style": "logic_blocks",
116 | "tooltip": "Is the airplane over a block of the chosen color?",
117 | "helpUrl": "https://dopevog.github.io/aviation-with-code/tutorial/#/9"
118 | }
119 | }
120 | },
121 | 'wrap': [
122 | 'procedures_defnoreturn',
123 | 'procedures_defreturn',
124 | 'procedures_callreturn',
125 | 'procedures_callnoreturn',
126 | 'procedures_ifreturn',
127 | 'logic_boolean',
128 | 'controls_if',
129 | 'controls_whileUntil',
130 | 'logic_negate'
131 | ],
132 | 'toolbox': ELEMENTS['GAME']['TOOLBOX']
133 | })
134 |
135 | /* --- Inject --- */
136 | Blockly.inject('blockly-div', {
137 | toolbox: ELEMENTS['GAME']['TOOLBOX'],
138 | toolboxPosition: 'end',
139 | scrollbars: true,
140 | horizontalLayout: false,
141 | trashcan: false,
142 | theme: Blockly.Themes.Modern
143 | })
144 |
145 | const
146 | gamepad = new Blockly.Gamepad({
147 | 'customHighlight': true,
148 | 'magicJson': true,
149 | 'start': true
150 | }),
151 | gui = new Gui(),
152 | game = new Game(gamepad, gui)
--------------------------------------------------------------------------------
/js/ui/gameBoard.js:
--------------------------------------------------------------------------------
1 | /* --- Gameboard --- */
2 | const Gameboard = {
3 | // load the gameboard within a given container
4 | load(gameboard){
5 | this.OVER = gameboard['OVER']
6 | this.TAKEN = gameboard['TAKEN']
7 | this.MOVES = gameboard['MOVES']
8 | this.LEVEL = gameboard['LEVEL']
9 | },
10 |
11 | // set the color that represent the taken block color
12 | setTaken(block){
13 | this.TAKEN.style['background-color'] = block ? block.color : JollyColor
14 | },
15 |
16 | // set the color that represent the over block color
17 | setOver(block){
18 | this.OVER.style['background-color'] = block ? block.color : JollyColor
19 | },
20 |
21 | // set the number of moves
22 | setMoves(moves){
23 | this.MOVES.innerHTML = moves
24 | },
25 |
26 | // set the level number
27 | setLevel(level, levels){
28 | this.LEVEL.innerHTML = ++level + '/' + levels
29 | },
30 | }
--------------------------------------------------------------------------------
/js/ui/textures.js:
--------------------------------------------------------------------------------
1 | /* --- Textures data --- */
2 | const texturesData = {
3 | // colors
4 | colors: {
5 | white: 0xd8d0d1,
6 | pink: 0xF5986E,
7 | brown: 0x59332e,
8 | brownDark: 0x23190f,
9 | red: 'red',
10 |
11 | darkgray: "#515A5A",
12 | lightgray: "#707B7C"
13 | }
14 | }
15 |
16 | /* --- Textures --- */
17 | // contains all the preloaded geometries/materials and the sprites classes
18 | const Textures = {
19 | PilotGeometries: {
20 | bodyGeom: new THREE.BoxGeometry(15, 15, 15),
21 | faceGeom: new THREE.BoxGeometry(10, 10, 10),
22 | hairGeom: new THREE.BoxGeometry(4, 4, 4),
23 | hairSideGeom: new THREE.BoxGeometry(12, 4, 2),
24 | hairBackGeom: new THREE.BoxGeometry(2, 8, 10),
25 | glassGeom: new THREE.BoxGeometry(5, 5, 5),
26 | glassAGeom: new THREE.BoxGeometry(11, 1, 11),
27 | earGeom: new THREE.BoxGeometry(2, 3, 2)
28 | },
29 | PilotMaterials: {
30 | bodyMat: new THREE.MeshPhongMaterial({
31 | color: texturesData.colors.brown,
32 | flatShading: THREE.FlatShading
33 | }),
34 | faceMat: new THREE.MeshLambertMaterial({
35 | color: texturesData.colors.pink
36 | }),
37 | hairMat: new THREE.MeshLambertMaterial({
38 | color: texturesData.colors.brown
39 | }),
40 | glassMat: new THREE.MeshLambertMaterial({
41 | color: texturesData.colors.brown
42 | })
43 | },
44 | // pilot class
45 | Pilot: class {
46 | constructor() {
47 | this.mesh = new THREE.Object3D();
48 | this.mesh.name = "pilot";
49 | this.angleHairs = 0;
50 |
51 | var body = new THREE.Mesh(Textures.PilotGeometries.bodyGeom, Textures.PilotMaterials.bodyMat);
52 | body.position.set(2, -12, 0);
53 | this.mesh.add(body);
54 |
55 | var face = new THREE.Mesh(Textures.PilotGeometries.faceGeom, Textures.PilotMaterials.faceMat);
56 | this.mesh.add(face);
57 |
58 | var hair = new THREE.Mesh(Textures.PilotGeometries.hairGeom, Textures.PilotMaterials.hairMat);
59 | var hairs = new THREE.Object3D();
60 |
61 | this.hairsTop = new THREE.Object3D();
62 |
63 | for (var i = 0; i < 12; i++) {
64 | var h = hair.clone();
65 | var col = i % 3;
66 | var row = Math.floor(i / 3);
67 | var startPosZ = -4;
68 | var startPosX = -4;
69 | h.position.set(startPosX + row * 4, 0, startPosZ + col * 4);
70 | this.hairsTop.add(h);
71 | }
72 | hairs.add(this.hairsTop);
73 |
74 | var hairSideR = new THREE.Mesh(Textures.PilotGeometries.hairSideGeom, Textures.PilotMaterials.hairMat);
75 | var hairSideL = hairSideR.clone();
76 | hairSideR.position.set(8, -2, 6);
77 | hairSideL.position.set(8, -2, -6);
78 | hairs.add(hairSideR);
79 | hairs.add(hairSideL);
80 |
81 | var hairBack = new THREE.Mesh(Textures.PilotGeometries.hairBackGeom, Textures.PilotMaterials.hairMat);
82 | hairBack.position.set(-1, -4, 0)
83 | hairs.add(hairBack);
84 | hairs.position.set(-5, 5, 0);
85 |
86 | this.mesh.add(hairs);
87 |
88 | var glassR = new THREE.Mesh(Textures.PilotGeometries.glassGeom, Textures.PilotMaterials.glassMat);
89 | glassR.position.set(6, 0, 3);
90 | var glassL = glassR.clone();
91 | glassL.position.z = -glassR.position.z
92 |
93 | var glassA = new THREE.Mesh(Textures.PilotGeometries.glassAGeom, Textures.PilotMaterials.glassMat);
94 | this.mesh.add(glassR);
95 | this.mesh.add(glassL);
96 | this.mesh.add(glassA);
97 |
98 | var earL = new THREE.Mesh(Textures.PilotGeometries.earGeom, Textures.PilotMaterials.faceMat);
99 | earL.position.set(0, 0, -6);
100 | var earR = earL.clone();
101 | earR.position.set(0, 0, 6);
102 | this.mesh.add(earL);
103 | this.mesh.add(earR);
104 | }
105 |
106 | updateHairs() {
107 | var hairs = this.hairsTop.children;
108 |
109 | var l = hairs.length;
110 | for (var i = 0; i < l; i++) {
111 | var h = hairs[i];
112 | h.scale.y = .75 + Math.cos(this.angleHairs + i / 3) * .25;
113 | }
114 | this.angleHairs += 0.16;
115 | }
116 | },
117 | AirPlaneGeometries: {
118 | geomCockpit: new THREE.BoxGeometry(80, 50, 50, 1, 1, 1),
119 | geomEngine: new THREE.BoxGeometry(20, 50, 50, 1, 1, 1),
120 | geomTailPlane: new THREE.BoxGeometry(15, 20, 5, 1, 1, 1),
121 | geomSideWing: new THREE.BoxGeometry(30, 5, 120, 1, 1, 1),
122 | geomWindshield: new THREE.BoxGeometry(3, 15, 20, 1, 1, 1),
123 | geomPropeller: new THREE.BoxGeometry(20, 10, 10, 1, 1, 1),
124 | geomBlade: new THREE.BoxGeometry(1, 80, 10, 1, 1, 1),
125 | wheelProtecGeom: new THREE.BoxGeometry(30, 15, 10, 1, 1, 1),
126 | wheelTireGeom: new THREE.BoxGeometry(24, 24, 4),
127 | wheelAxisGeom: new THREE.BoxGeometry(10, 10, 6),
128 | suspensionGeom: new THREE.BoxGeometry(4, 20, 4),
129 | popUpGeom: new THREE.CircleGeometry(12, 32),
130 | popUpBorderGeom: new THREE.CircleGeometry(15, 32)
131 | },
132 | AirPlaneMaterials: {
133 | matCockpit: new THREE.MeshPhongMaterial({
134 | color: texturesData.colors.red,
135 | flatShading: THREE.FlatShading
136 | }),
137 | matEngine: new THREE.MeshPhongMaterial({
138 | color: texturesData.colors.white,
139 | flatShading: THREE.FlatShading
140 | }),
141 | matTailPlane: new THREE.MeshPhongMaterial({
142 | color: texturesData.colors.red,
143 | flatShading: THREE.FlatShading
144 | }),
145 | matSideWing: new THREE.MeshPhongMaterial({
146 | color: texturesData.colors.red,
147 | flatShading: THREE.FlatShading
148 | }),
149 | matWindshield: new THREE.MeshPhongMaterial({
150 | color: texturesData.colors.white,
151 | transparent: true,
152 | opacity: .3,
153 | flatShading: THREE.FlatShading
154 | }),
155 | matPropeller: new THREE.MeshPhongMaterial({
156 | color: texturesData.colors.brown,
157 | flatShading: THREE.FlatShading
158 | }),
159 | matBlade: new THREE.MeshPhongMaterial({
160 | color: texturesData.colors.brownDark,
161 | flatShading: THREE.FlatShading
162 | }),
163 | wheelProtecMat: new THREE.MeshPhongMaterial({
164 | color: texturesData.colors.red,
165 | flatShading: THREE.FlatShading
166 | }),
167 | wheelTireMat: new THREE.MeshPhongMaterial({
168 | color: texturesData.colors.brownDark,
169 | flatShading: THREE.FlatShading
170 | }),
171 | wheelAxisMat: new THREE.MeshPhongMaterial({
172 | color: texturesData.colors.brown,
173 | flatShading: THREE.FlatShading
174 | }),
175 | suspensionMat: new THREE.MeshPhongMaterial({
176 | color: texturesData.colors.red,
177 | flatShading: THREE.FlatShading
178 | })
179 | },
180 | // airPlane class
181 | AirPlane: class {
182 | constructor() {
183 | this.blocks = []
184 |
185 | this.mesh = new THREE.Object3D();
186 | this.mesh.name = "airPlane";
187 |
188 | var cockpit = new THREE.Mesh(Textures.AirPlaneGeometries.geomCockpit, Textures.AirPlaneMaterials.matCockpit);
189 | cockpit.castShadow = true;
190 | cockpit.receiveShadow = true;
191 | this.mesh.add(cockpit);
192 |
193 | // Engine
194 | var engine = new THREE.Mesh(Textures.AirPlaneGeometries.geomEngine, Textures.AirPlaneMaterials.matEngine);
195 | engine.position.x = 50;
196 | engine.castShadow = true;
197 | engine.receiveShadow = true;
198 | this.mesh.add(engine);
199 |
200 | // Tail Plane
201 | var tailPlane = new THREE.Mesh(Textures.AirPlaneGeometries.geomTailPlane, Textures.AirPlaneMaterials.matTailPlane);
202 | tailPlane.position.set(-40, 20, 0);
203 | tailPlane.castShadow = true;
204 | tailPlane.receiveShadow = true;
205 | this.mesh.add(tailPlane);
206 |
207 | // Wings
208 | var sideWing = new THREE.Mesh(Textures.AirPlaneGeometries.geomSideWing, Textures.AirPlaneMaterials.matSideWing);
209 | sideWing.position.set(0, 15, 0);
210 | sideWing.castShadow = true;
211 | sideWing.receiveShadow = true;
212 | this.mesh.add(sideWing);
213 |
214 | var windshield = new THREE.Mesh(Textures.AirPlaneGeometries.geomWindshield, Textures.AirPlaneMaterials.matWindshield);
215 | windshield.position.set(5, 27, 0);
216 | windshield.castShadow = true;
217 | windshield.receiveShadow = true;
218 | this.mesh.add(windshield);
219 |
220 | this.propeller = new THREE.Mesh(Textures.AirPlaneGeometries.geomPropeller, Textures.AirPlaneMaterials.matPropeller);
221 |
222 | this.propeller.castShadow = true;
223 | this.propeller.receiveShadow = true;
224 |
225 | var blade1 = new THREE.Mesh(Textures.AirPlaneGeometries.geomBlade, Textures.AirPlaneMaterials.matBlade);
226 | blade1.position.set(8, 0, 0);
227 |
228 | blade1.castShadow = true;
229 | blade1.receiveShadow = true;
230 |
231 | var blade2 = blade1.clone();
232 | blade2.rotation.x = Math.PI / 2;
233 |
234 | blade2.castShadow = true;
235 | blade2.receiveShadow = true;
236 |
237 | this.propeller.add(blade1);
238 | this.propeller.add(blade2);
239 | this.propeller.position.set(60, 0, 0);
240 | this.mesh.add(this.propeller);
241 |
242 | var wheelProtecR = new THREE.Mesh(Textures.AirPlaneGeometries.wheelProtecGeom, Textures.AirPlaneMaterials.wheelProtecMat);
243 | wheelProtecR.position.set(25, -20, 25);
244 | this.mesh.add(wheelProtecR);
245 |
246 | var wheelTireR = new THREE.Mesh(Textures.AirPlaneGeometries.wheelTireGeom, Textures.AirPlaneMaterials.wheelTireMat);
247 | wheelTireR.position.set(25, -28, 25);
248 |
249 | var wheelAxis = new THREE.Mesh(Textures.AirPlaneGeometries.wheelAxisGeom, Textures.AirPlaneMaterials.wheelAxisMat);
250 | wheelTireR.add(wheelAxis);
251 | this.mesh.add(wheelTireR);
252 |
253 | var wheelProtecL = wheelProtecR.clone();
254 | wheelProtecL.position.z = -wheelProtecR.position.z;
255 | this.mesh.add(wheelProtecL);
256 |
257 | var wheelTireL = wheelTireR.clone();
258 | wheelTireL.position.z = -wheelTireR.position.z;
259 | this.mesh.add(wheelTireL);
260 |
261 | var wheelTireB = wheelTireR.clone();
262 | wheelTireB.scale.set(.5, .5, .5);
263 | wheelTireB.position.set(-35, -5, 0);
264 | this.mesh.add(wheelTireB);
265 |
266 | var suspension = new THREE.Mesh(Textures.AirPlaneGeometries.suspensionGeom, Textures.AirPlaneMaterials.suspensionMat);
267 | suspension.position.set(-35, -5, 0);
268 | suspension.rotation.z = -.3;
269 | this.mesh.add(suspension);
270 |
271 | this.pilot = new Textures.Pilot();
272 | this.pilot.mesh.position.set(-10, 27, 0);
273 | this.mesh.add(this.pilot.mesh);
274 |
275 | this.mesh.castShadow = true;
276 | this.mesh.receiveShadow = true;
277 |
278 | var popUp = new THREE.Mesh(Textures.AirPlaneGeometries.popUpGeom, new THREE.MeshBasicMaterial({
279 | color: 0xffff00
280 | }))
281 | var border = new THREE.Mesh(Textures.AirPlaneGeometries.popUpBorderGeom, new THREE.MeshBasicMaterial({
282 | color: 0x23190f
283 | }))
284 | popUp.add(border)
285 | border.position.set(0, 0, -1)
286 | popUp.position.set(0, 40, 0)
287 | this.mesh.add(popUp)
288 | this.popUp = popUp
289 | popUp.scale.set(0.01, 0.01, 0.01)
290 | popUp.visible = false
291 | }
292 |
293 | updatePropeller() {
294 | this.propeller.rotation.x += 0.3;
295 | }
296 |
297 | setBlock(mesh) {
298 | this.popBlock()
299 | this.block = mesh
300 | this.mesh.add(mesh)
301 | }
302 |
303 | popBlock() {
304 | if (this.block) {
305 | this.mesh.remove(this.block)
306 | let block = this.block
307 | this.block = undefined
308 | return block
309 | }
310 | }
311 |
312 | static setColor(color) {
313 | ['matCockpit', 'matTailPlane', 'matSideWing', 'wheelProtecMat', 'suspensionMat']
314 | .forEach(value => Textures.AirPlaneMaterials[value].color.set(color))
315 | }
316 | },
317 | CellGeometries: {
318 | geometry: new THREE.BoxBufferGeometry(108, 4, 108)
319 | },
320 | CellMaterials: {
321 | mat1: new THREE.MeshPhongMaterial({
322 | color: texturesData.colors.darkgray
323 | }),
324 | mat2: new THREE.MeshPhongMaterial({
325 | color: texturesData.colors.lightgray
326 | }),
327 | },
328 | // cell class
329 | Cell: class {
330 | constructor(type) {
331 | this.mesh = new THREE.Mesh(Textures.CellGeometries.geometry, type == 1 ? Textures.CellMaterials.mat1 : Textures.CellMaterials.mat2)
332 | this.mesh.receiveShadow = true
333 | }
334 | },
335 | BlockGeometries: {
336 | geometry: new THREE.BoxGeometry(52, 52, 52)
337 | },
338 | BlockMaterials: {
339 | 'translucent': {
340 | transparent: true,
341 | opacity: 0.5
342 | }
343 | },
344 | // block class
345 | Block: class {
346 | constructor(color, translucent) {
347 | const material = new THREE.MeshPhongMaterial(translucent ? Textures.BlockMaterials['translucent'] : {})
348 | material.color.set(color)
349 |
350 | this.mesh = new THREE.Mesh(Textures.BlockGeometries.geometry, material)
351 | this.mesh.receiveShadow = true
352 | this.mesh.castShadow = !translucent
353 | }
354 | },
355 | // load some setting
356 | load: function () {
357 | Textures.PilotGeometries.hairGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 2, 0));
358 | Textures.PilotGeometries.hairSideGeom.applyMatrix(new THREE.Matrix4().makeTranslation(-6, 0, 0));
359 |
360 | Textures.AirPlaneGeometries.geomCockpit.vertices[4].y -= 10;
361 | Textures.AirPlaneGeometries.geomCockpit.vertices[4].z += 20;
362 | Textures.AirPlaneGeometries.geomCockpit.vertices[5].y -= 10;
363 | Textures.AirPlaneGeometries.geomCockpit.vertices[5].z -= 20;
364 | Textures.AirPlaneGeometries.geomCockpit.vertices[6].y += 30;
365 | Textures.AirPlaneGeometries.geomCockpit.vertices[6].z += 20;
366 | Textures.AirPlaneGeometries.geomCockpit.vertices[7].y += 30;
367 | Textures.AirPlaneGeometries.geomCockpit.vertices[7].z -= 20;
368 |
369 | Textures.AirPlaneGeometries.geomPropeller.vertices[4].y -= 5;
370 | Textures.AirPlaneGeometries.geomPropeller.vertices[4].z += 5;
371 | Textures.AirPlaneGeometries.geomPropeller.vertices[5].y -= 5;
372 | Textures.AirPlaneGeometries.geomPropeller.vertices[5].z -= 5;
373 | Textures.AirPlaneGeometries.geomPropeller.vertices[6].y += 5;
374 | Textures.AirPlaneGeometries.geomPropeller.vertices[6].z += 5;
375 | Textures.AirPlaneGeometries.geomPropeller.vertices[7].y += 5;
376 | Textures.AirPlaneGeometries.geomPropeller.vertices[7].z -= 5;
377 |
378 | Textures.AirPlaneGeometries.suspensionGeom.applyMatrix(new THREE.Matrix4().makeTranslation(0, 10, 0))
379 |
380 | Textures.BlockGeometries.edges = new THREE.EdgesGeometry(Textures.BlockGeometries.geometry)
381 | }
382 | }
--------------------------------------------------------------------------------
/js/ui/three.js:
--------------------------------------------------------------------------------
1 | /* --- Three --- */
2 | // The Three object manage the THREE components (scene, camera, lights...)
3 | const Three = {
4 | // load components in a given container
5 | load: container => {
6 | // components
7 | var scene,
8 | camera, cameraSetting = {
9 | fieldOfView: 60,
10 | nearPlane: 1,
11 | farPlane: 10000,
12 | x: -252,
13 | z: -582,
14 | y: 630
15 | },
16 | controls,
17 | renderer
18 |
19 | // create the scene
20 | function createScene() {
21 | scene = new THREE.Scene();
22 |
23 | camera = new THREE.PerspectiveCamera(
24 | cameraSetting.fieldOfView,
25 | container.offsetWidth / container.offsetHeight,
26 | cameraSetting.nearPlane,
27 | cameraSetting.farPlane
28 | );
29 | camera.position.set(cameraSetting.x, cameraSetting.y, cameraSetting.z) //-30, 35, 0
30 | camera.lookAt(scene.position)
31 |
32 | renderer = new THREE.WebGLRenderer({
33 | alpha: true,
34 | antialias: true
35 | });
36 | renderer.setSize(container.offsetWidth, container.offsetHeight);
37 | renderer.shadowMap.enabled = true;
38 | renderer.render(scene, camera);
39 | container.appendChild(renderer.domElement);
40 |
41 | controls = new THREE.OrbitControls(camera, renderer.domElement)
42 | controls.maxPolarAngle = Math.PI / 2.5
43 | controls.update()
44 | }
45 |
46 | // resize the canvas
47 | function handleWindowResize() {
48 | height = container.offsetHeight;
49 | width = container.offsetWidth;
50 |
51 | renderer.setSize(width, height);
52 | camera.aspect = width / height;
53 | camera.updateProjectionMatrix();
54 | }
55 |
56 | // lights
57 | var ambientLight, al = {
58 | color: 0xdc8874,
59 | intensity: .6
60 | },
61 | hemisphereLight, hl = {
62 | skyColor: 0xaaaaaa,
63 | groundColor: 0x000000,
64 | intensity: .9
65 | },
66 | shadowLight, sl = {
67 | color: 0xffffff,
68 | intensity: .7,
69 | castShadow: true,
70 | x: 0,
71 | y: 1,
72 | z: 0,
73 | left: -400,
74 | right: 400,
75 | top: 400,
76 | bottom: -400,
77 | near: 1,
78 | far: 1000,
79 | width: 2048,
80 | height: 2048
81 | };
82 |
83 | // create the lights
84 | function createLights() {
85 | hemisphereLight = new THREE.HemisphereLight(hl.skyColor, hl.groundColor, hl.intensity);
86 |
87 | ambientLight = new THREE.AmbientLight(al.color, al.intensity);
88 |
89 | shadowLight = new THREE.DirectionalLight(sl.color, sl.intensity);
90 | shadowLight.position.set(150, 350, 350);
91 | shadowLight.castShadow = sl.castShadow;
92 | shadowLight.shadow.camera.left = sl.left;
93 | shadowLight.shadow.camera.right = sl.right;
94 | shadowLight.shadow.camera.top = sl.top;
95 | shadowLight.shadow.camera.bottom = sl.bottom;
96 | shadowLight.shadow.camera.near = sl.near;
97 | shadowLight.shadow.camera.far = sl.far;
98 | shadowLight.shadow.mapSize.width = sl.width;
99 | shadowLight.shadow.mapSize.height = sl.height;
100 |
101 | scene.add(hemisphereLight);
102 | scene.add(shadowLight);
103 | scene.add(ambientLight);
104 | }
105 |
106 | // set the hemisphereLight color
107 | function setLightColor(color) {
108 | hemisphereLight.color = new THREE.Color(color)
109 | }
110 |
111 | // render the scene
112 | function render() {
113 | renderer.render(scene, camera)
114 | }
115 |
116 | // clear all elements excepts the lights
117 | function clear() {
118 | for (let i = scene.children.length - 1; i >= 0; i--) {
119 | let mesh = scene.children[i]
120 | if (!mesh.type.includes('Light'))
121 | scene.remove(mesh)
122 | }
123 |
124 | //camera.lookAt(0, 0, 0)
125 | }
126 |
127 | createScene()
128 | createLights()
129 |
130 | // add listeners
131 | window.addEventListener('resize', handleWindowResize, false)
132 | window.addEventListener('load', handleWindowResize, false)
133 |
134 | Object.assign(Three, {
135 | scene,
136 | camera,
137 | render,
138 | controls,
139 | clear,
140 | handleWindowResize
141 | })
142 | }
143 | }
--------------------------------------------------------------------------------
/js/worlds/jollycolor.js:
--------------------------------------------------------------------------------
1 | /* --- Jolly Color --- */
2 |
3 | // the jollycolor indicates each color in the game
4 | const JollyColor = '#f5f5f5'
--------------------------------------------------------------------------------
/js/worlds/parser.js:
--------------------------------------------------------------------------------
1 | /* --- Parser --- */
2 |
3 | // parse each stage with the level colors
4 | const Parser = function (stage, colors) {
5 |
6 | // load the aviator
7 | function loadAviator(stage) {
8 | if (stage.aviator.taken !== undefined)
9 | stage.aviator.taken = createBlock(stage.aviator.taken)
10 |
11 | stage.aviator.direction = getDirection(stage.aviator.direction)
12 | }
13 |
14 | function getDirection(direction){
15 | switch(direction){
16 | case 'up': return 0
17 | case 'right': return 1
18 | case 'down': return 2
19 | case 'left': return 3
20 | default: return 0
21 | }
22 | }
23 |
24 | // create a block
25 | function createBlock(block) {
26 | return { color: colors[block].toLowerCase() }
27 | }
28 |
29 | // load all the blocks
30 | function loadBlocks(cells) {
31 | for (let cell of cells) {
32 | for (let i = 0; i < cell.blocks.length; i++)
33 | cell.blocks[i] = createBlock(cell.blocks[i])
34 | }
35 | }
36 |
37 | loadAviator(stage)
38 | loadBlocks(stage.end)
39 | loadBlocks(stage.start)
40 |
41 | // set the holes
42 | stage.holes = stage.holes || []
43 |
44 | return stage
45 | }
--------------------------------------------------------------------------------
/libs/blockly/theme.js:
--------------------------------------------------------------------------------
1 | Blockly.Themes.Modern = new Blockly.Theme({
2 | "colour_blocks": {
3 | "colourPrimary": "#a5745b",
4 | "colourSecondary": "#dbc7bd",
5 | "colourTertiary": "#845d49"
6 | },
7 | "list_blocks": {
8 | "colourPrimary": "#745ba5",
9 | "colourSecondary": "#c7bddb",
10 | "colourTertiary": "#5d4984"
11 | },
12 | "logic_blocks": {
13 | "colourPrimary": "#5b80a5",
14 | "colourSecondary": "#bdccdb",
15 | "colourTertiary": "#496684"
16 | },
17 | "loop_blocks": {
18 | "colourPrimary": "#5ba55b",
19 | "colourSecondary": "#bddbbd",
20 | "colourTertiary": "#498449"
21 | },
22 | "math_blocks": {
23 | "colourPrimary": "#5b67a5",
24 | "colourSecondary": "#bdc2db",
25 | "colourTertiary": "#495284"
26 | },
27 | "procedure_blocks": {
28 | "colourPrimary": "#995ba5",
29 | "colourSecondary": "#d6bddb",
30 | "colourTertiary": "#7a4984"
31 | },
32 | "text_blocks": {
33 | "colourPrimary": "#5ba58c",
34 | "colourSecondary": "#bddbd1",
35 | "colourTertiary": "#498470"
36 | },
37 | "variable_blocks": {
38 | "colourPrimary": "#a55b99",
39 | "colourSecondary": "#dbbdd6",
40 | "colourTertiary": "#84497a"
41 | },
42 | "variable_dynamic_blocks": {
43 | "colourPrimary": "#a55b99",
44 | "colourSecondary": "#dbbdd6",
45 | "colourTertiary": "#84497a"
46 | },
47 | "hat_blocks": {
48 | "colourPrimary": "#a55b99",
49 | "colourSecondary": "#dbbdd6",
50 | "colourTertiary": "#84497a",
51 | "hat": "cap"
52 | },
53 | "move_blocks": {
54 | "colourPrimary": "65",
55 | "colourSecondary": "65",
56 | "colourTertiary": "#808000",
57 | },
58 | "action_blocks": {
59 | "colourPrimary": "25",
60 | "colourSecondary": "25",
61 | "colourTertiary": "#664E35",
62 | }
63 | }, {
64 | "colour_category": {
65 | "colour": "#a5745b",
66 | },
67 | "list_category": {
68 | "colour": "#745ba5",
69 | },
70 | "logic_category": {
71 | "colour": "#5b80a5",
72 | },
73 | "loop_category": {
74 | "colour": "#5ba55b",
75 | },
76 | "math_category": {
77 | "colour": "#5b67a5",
78 | },
79 | "procedure_category": {
80 | "colour": "#995ba5",
81 | },
82 | "text_category": {
83 | "colour": "#5ba58c",
84 | },
85 | "variable_category": {
86 | "colour": "#a55b99",
87 | },
88 | "variable_dynamic_category": {
89 | "colour": "#a55b99",
90 | }
91 | });
--------------------------------------------------------------------------------
/libs/github/index.js:
--------------------------------------------------------------------------------
1 | const GitHub = class{
2 | static inject(domElement){
3 | const style =
4 | ' .github-corner:hover .octo-arm { ' +
5 | ' animation: octocat-wave 560ms ease-in-out ' +
6 | ' } ' +
7 | ' ' +
8 | ' @keyframes octocat-wave { ' +
9 | ' ' +
10 | ' 0%, ' +
11 | ' 100% { ' +
12 | ' transform: rotate(0) ' +
13 | ' } ' +
14 | ' ' +
15 | ' 20%, ' +
16 | ' 60% { ' +
17 | ' transform: rotate(-25deg) ' +
18 | ' } ' +
19 | ' ' +
20 | ' 40%, ' +
21 | ' 80% { ' +
22 | ' transform: rotate(10deg) ' +
23 | ' } ' +
24 | ' } ' +
25 | ' ' +
26 | ' @media (max-width:500px) { ' +
27 | ' .github-corner:hover .octo-arm { ' +
28 | ' animation: none ' +
29 | ' } ' +
30 | ' ' +
31 | ' .github-corner .octo-arm { ' +
32 | ' animation: octocat-wave 560ms ease-in-out ' +
33 | ' } ' +
34 | ' } ';
35 |
36 | const link = ' ' +
37 | ' ' +
39 | ' ' +
40 | ' ' +
43 | ' ' +
46 | ' ' +
47 | ' ' ;
48 |
49 | const styleEl = document.createElement('style')
50 | const linkEl = document.createElement('a')
51 |
52 | styleEl.innerHTML = style
53 | linkEl.innerHTML = link
54 |
55 | linkEl.setAttribute('herf', 'https://github.com/dopevog/gamepad.js')
56 | linkEl.setAttribute('class', 'github-corner')
57 | linkEl.setAttribute('aria-label', 'View source on GitHub')
58 | linkEl.setAttribute('onclick', 'event.stopPropagation()')
59 |
60 | document.head.appendChild(styleEl)
61 | domElement.appendChild(linkEl)
62 | }
63 | }
--------------------------------------------------------------------------------
/libs/parallax/parallax.min.js:
--------------------------------------------------------------------------------
1 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Parallax=t()}}(function(){return function t(e,i,n){function o(r,a){if(!i[r]){if(!e[r]){var l="function"==typeof require&&require;if(!a&&l)return l(r,!0);if(s)return s(r,!0);var h=new Error("Cannot find module '"+r+"'");throw h.code="MODULE_NOT_FOUND",h}var u=i[r]={exports:{}};e[r][0].call(u.exports,function(t){var i=e[r][1][t];return o(i||t)},u,u.exports,t,e,i,n)}return i[r].exports}for(var s="function"==typeof require&&require,r=0;r1)for(var i=1;ii?i:t:te?e:t},data:function(t,e){return a.deserialize(t.getAttribute("data-"+e))},deserialize:function(t){return"true"===t||"false"!==t&&("null"===t?null:!isNaN(parseFloat(t))&&isFinite(t)?parseFloat(t):t)},camelCase:function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},accelerate:function(t){a.css(t,"transform","translate3d(0,0,0) rotate(0.0001deg)"),a.css(t,"transform-style","preserve-3d"),a.css(t,"backface-visibility","hidden")},transformSupport:function(t){for(var e=document.createElement("div"),i=!1,n=null,o=!1,s=null,r=null,l=0,h=a.vendors.length;l0&&"none"!==n,c.style.overflow=d,u.removeChild(e),m&&(u.removeAttribute("style"),u.parentNode.removeChild(u))}}return o},css:function(t,e,i){var n=a.propertyCache[e];if(!n)for(var o=0,s=a.vendors.length;othis.calibrationThreshold||Math.abs(e)>this.calibrationThreshold)&&this.queueCalibration(0),this.portrait?(this.motionX=this.calibrateX?e:this.inputY,this.motionY=this.calibrateY?t:this.inputX):(this.motionX=this.calibrateX?t:this.inputX,this.motionY=this.calibrateY?e:this.inputY),this.motionX*=this.elementWidth*(this.scalarX/100),this.motionY*=this.elementHeight*(this.scalarY/100),isNaN(parseFloat(this.limitX))||(this.motionX=a.clamp(this.motionX,-this.limitX,this.limitX)),isNaN(parseFloat(this.limitY))||(this.motionY=a.clamp(this.motionY,-this.limitY,this.limitY)),this.velocityX+=(this.motionX-this.velocityX)*this.frictionX,this.velocityY+=(this.motionY-this.velocityY)*this.frictionY;for(var i=0;ithis.windowWidth;this.portrait!==o&&(this.portrait=o,this.calibrationFlag=!0),this.calibrationFlag&&(this.calibrationFlag=!1,this.calibrationX=i,this.calibrationY=n),this.inputX=i,this.inputY=n}},{key:"onDeviceOrientation",value:function(t){var e=t.beta,i=t.gamma;null!==e&&null!==i&&(this.orientationStatus=1,this.rotate(e,i))}},{key:"onDeviceMotion",value:function(t){var e=t.rotationRate.beta,i=t.rotationRate.gamma;null!==e&&null!==i&&(this.motionStatus=1,this.rotate(e,i))}},{key:"onMouseMove",value:function(t){var e=t.clientX,i=t.clientY;if(this.hoverOnly&&(ethis.elementPositionX+this.elementWidth||ithis.elementPositionY+this.elementHeight))return this.inputX=0,void(this.inputY=0);this.relativeInput?(this.clipRelativeInput&&(e=Math.max(e,this.elementPositionX),e=Math.min(e,this.elementPositionX+this.elementWidth),i=Math.max(i,this.elementPositionY),i=Math.min(i,this.elementPositionY+this.elementHeight)),this.elementRangeX&&this.elementRangeY&&(this.inputX=(e-this.elementPositionX-this.elementCenterX)/this.elementRangeX,this.inputY=(i-this.elementPositionY-this.elementCenterY)/this.elementRangeY)):this.windowRadiusX&&this.windowRadiusY&&(this.inputX=(e-this.windowCenterX)/this.windowRadiusX,this.inputY=(i-this.windowCenterY)/this.windowRadiusY)}},{key:"destroy",value:function(){this.disable(),clearTimeout(this.calibrationTimer),clearTimeout(this.detectionTimer),this.element.removeAttribute("style");for(var t=0;to)return s;var a=0,u=[],e=s.map(function(e,t){var n=o*e/100,r=G(v,0===t,t===s.length-1,p),i=d[t]+r;return n=this.size-(r.minSize+y+this._c)&&(t=this.size-(r.minSize+this._c)),U.call(this,t),Y(i,"onDrag",I)())}.bind(t),t.stop=function(){var e=this,t=a[e.a].element,n=a[e.b].element;e.dragging&&Y(i,"onDragEnd",I)(x()),e.dragging=!1,L[R]("mouseup",e.stop),L[R]("touchend",e.stop),L[R]("touchcancel",e.stop),L[R]("mousemove",e.move),L[R]("touchmove",e.move),e.stop=null,e.move=null,t[R]("selectstart",I),t[R]("dragstart",I),n[R]("selectstart",I),n[R]("dragstart",I),t.style.userSelect="",t.style.webkitUserSelect="",t.style.MozUserSelect="",t.style.pointerEvents="",n.style.userSelect="",n.style.webkitUserSelect="",n.style.MozUserSelect="",n.style.pointerEvents="",e.gutter.style.cursor="",e.parent.style.cursor="",T.body.style.cursor=""}.bind(t),L[N]("mouseup",t.stop),L[N]("touchend",t.stop),L[N]("touchcancel",t.stop),L[N]("mousemove",t.move),L[N]("touchmove",t.move),n[N]("selectstart",I),n[N]("dragstart",I),r[N]("selectstart",I),r[N]("dragstart",I),n.style.userSelect="none",n.style.webkitUserSelect="none",n.style.MozUserSelect="none",n.style.pointerEvents="none",r.style.userSelect="none",r.style.webkitUserSelect="none",r.style.MozUserSelect="none",r.style.pointerEvents="none",t.gutter.style.cursor=b,t.parent.style.cursor=b,T.body.style.cursor=b,O.call(t),t.dragOffset=M(e)-t.end}}S===H?(u="width",t="clientX",s="left",o="right",r="clientWidth"):"vertical"===S&&(u="height",t="clientY",s="top",o="bottom",r="clientHeight"),m=C(m);var A=[];function j(e){var t=e.i===A.length,n=t?A[e.i-1]:A[e.i];O.call(n);var r=t?n.size-e.minSize-n._c:e.minSize+n._b;U.call(n,r)}function F(e){var s=C(e);s.forEach(function(e,t){if(0p||8*(1-r.dot(s.object.quaternion))>p)&&(s.dispatchEvent(c),i.copy(s.object.position),r.copy(s.object.quaternion),f=!1,!0)}),this.dispose=function(){s.domElement.removeEventListener("contextmenu",_,!1),s.domElement.removeEventListener("mousedown",U,!1),s.domElement.removeEventListener("wheel",z,!1),s.domElement.removeEventListener("touchstart",I,!1),s.domElement.removeEventListener("touchend",K,!1),s.domElement.removeEventListener("touchmove",X,!1),document.removeEventListener("mousemove",Y,!1),document.removeEventListener("mouseup",Z,!1),window.removeEventListener("keydown",F,!1)};var s=this,c={type:"change"},l={type:"start"},m={type:"end"},u={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_DOLLY_PAN:4},d=u.NONE,p=1e-6,h=new THREE.Spherical,E=new THREE.Spherical,b=1,g=new THREE.Vector3,f=!1,T=new THREE.Vector2,v=new THREE.Vector2,y=new THREE.Vector2,R=new THREE.Vector2,O=new THREE.Vector2,H=new THREE.Vector2,w=new THREE.Vector2,P=new THREE.Vector2,j=new THREE.Vector2;function L(){return Math.pow(.95,s.zoomSpeed)}function M(e){E.theta-=e}function C(e){E.phi-=e}var N,S=(N=new THREE.Vector3,function(e,t){N.setFromMatrixColumn(t,0),N.multiplyScalar(-e),g.add(N)}),A=function(){var e=new THREE.Vector3;return function(t,n){!0===s.screenSpacePanning?e.setFromMatrixColumn(n,1):(e.setFromMatrixColumn(n,0),e.crossVectors(s.object.up,e)),e.multiplyScalar(t),g.add(e)}}(),D=function(){var e=new THREE.Vector3;return function(t,n){var o=s.domElement===document?s.domElement.body:s.domElement;if(s.object.isPerspectiveCamera){var a=s.object.position;e.copy(a).sub(s.target);var i=e.length();i*=Math.tan(s.object.fov/2*Math.PI/180),S(2*t*i/o.clientHeight,s.object.matrix),A(2*n*i/o.clientHeight,s.object.matrix)}else s.object.isOrthographicCamera?(S(t*(s.object.right-s.object.left)/s.object.zoom/o.clientWidth,s.object.matrix),A(n*(s.object.top-s.object.bottom)/s.object.zoom/o.clientHeight,s.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),s.enablePan=!1)}}();function x(e){s.object.isPerspectiveCamera?b/=e:s.object.isOrthographicCamera?(s.object.zoom=Math.max(s.minZoom,Math.min(s.maxZoom,s.object.zoom*e)),s.object.updateProjectionMatrix(),f=!0):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),s.enableZoom=!1)}function k(e){s.object.isPerspectiveCamera?b*=e:s.object.isOrthographicCamera?(s.object.zoom=Math.max(s.minZoom,Math.min(s.maxZoom,s.object.zoom/e)),s.object.updateProjectionMatrix(),f=!0):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),s.enableZoom=!1)}function V(e){R.set(e.clientX,e.clientY)}function U(e){if(!1!==s.enabled){switch(e.preventDefault(),e.button){case s.mouseButtons.LEFT:if(e.ctrlKey||e.metaKey){if(!1===s.enablePan)return;V(e),d=u.PAN}else{if(!1===s.enableRotate)return;!function(e){T.set(e.clientX,e.clientY)}(e),d=u.ROTATE}break;case s.mouseButtons.MIDDLE:if(!1===s.enableZoom)return;!function(e){w.set(e.clientX,e.clientY)}(e),d=u.DOLLY;break;case s.mouseButtons.RIGHT:if(!1===s.enablePan)return;V(e),d=u.PAN}d!==u.NONE&&(document.addEventListener("mousemove",Y,!1),document.addEventListener("mouseup",Z,!1),s.dispatchEvent(l))}}function Y(e){if(!1!==s.enabled)switch(e.preventDefault(),d){case u.ROTATE:if(!1===s.enableRotate)return;!function(e){v.set(e.clientX,e.clientY),y.subVectors(v,T).multiplyScalar(s.rotateSpeed);var t=s.domElement===document?s.domElement.body:s.domElement;M(2*Math.PI*y.x/t.clientHeight),C(2*Math.PI*y.y/t.clientHeight),T.copy(v),s.update()}(e);break;case u.DOLLY:if(!1===s.enableZoom)return;!function(e){P.set(e.clientX,e.clientY),j.subVectors(P,w),j.y>0?x(L()):j.y<0&&k(L()),w.copy(P),s.update()}(e);break;case u.PAN:if(!1===s.enablePan)return;!function(e){O.set(e.clientX,e.clientY),H.subVectors(O,R).multiplyScalar(s.panSpeed),D(H.x,H.y),R.copy(O),s.update()}(e)}}function Z(e){!1!==s.enabled&&(document.removeEventListener("mousemove",Y,!1),document.removeEventListener("mouseup",Z,!1),s.dispatchEvent(m),d=u.NONE)}function z(e){!1===s.enabled||!1===s.enableZoom||d!==u.NONE&&d!==u.ROTATE||(e.preventDefault(),e.stopPropagation(),s.dispatchEvent(l),function(e){e.deltaY<0?k(L()):e.deltaY>0&&x(L()),s.update()}(e),s.dispatchEvent(m))}function F(e){!1!==s.enabled&&!1!==s.enableKeys&&!1!==s.enablePan&&function(e){switch(e.keyCode){case s.keys.UP:D(0,s.keyPanSpeed),s.update();break;case s.keys.BOTTOM:D(0,-s.keyPanSpeed),s.update();break;case s.keys.LEFT:D(s.keyPanSpeed,0),s.update();break;case s.keys.RIGHT:D(-s.keyPanSpeed,0),s.update()}}(e)}function I(e){if(!1!==s.enabled){switch(e.preventDefault(),e.touches.length){case 1:if(!1===s.enableRotate)return;!function(e){T.set(e.touches[0].pageX,e.touches[0].pageY)}(e),d=u.TOUCH_ROTATE;break;case 2:if(!1===s.enableZoom&&!1===s.enablePan)return;!function(e){if(s.enableZoom){var t=e.touches[0].pageX-e.touches[1].pageX,n=e.touches[0].pageY-e.touches[1].pageY,o=Math.sqrt(t*t+n*n);w.set(0,o)}if(s.enablePan){var a=.5*(e.touches[0].pageX+e.touches[1].pageX),i=.5*(e.touches[0].pageY+e.touches[1].pageY);R.set(a,i)}}(e),d=u.TOUCH_DOLLY_PAN;break;default:d=u.NONE}d!==u.NONE&&s.dispatchEvent(l)}}function X(e){if(!1!==s.enabled)switch(e.preventDefault(),e.stopPropagation(),e.touches.length){case 1:if(!1===s.enableRotate)return;if(d!==u.TOUCH_ROTATE)return;!function(e){v.set(e.touches[0].pageX,e.touches[0].pageY),y.subVectors(v,T).multiplyScalar(s.rotateSpeed);var t=s.domElement===document?s.domElement.body:s.domElement;M(2*Math.PI*y.x/t.clientHeight),C(2*Math.PI*y.y/t.clientHeight),T.copy(v),s.update()}(e);break;case 2:if(!1===s.enableZoom&&!1===s.enablePan)return;if(d!==u.TOUCH_DOLLY_PAN)return;!function(e){if(s.enableZoom){var t=e.touches[0].pageX-e.touches[1].pageX,n=e.touches[0].pageY-e.touches[1].pageY,o=Math.sqrt(t*t+n*n);P.set(0,o),j.set(0,Math.pow(P.y/w.y,s.zoomSpeed)),x(j.y),w.copy(P)}if(s.enablePan){var a=.5*(e.touches[0].pageX+e.touches[1].pageX),i=.5*(e.touches[0].pageY+e.touches[1].pageY);O.set(a,i),H.subVectors(O,R).multiplyScalar(s.panSpeed),D(H.x,H.y),R.copy(O)}s.update()}(e);break;default:d=u.NONE}}function K(e){!1!==s.enabled&&(s.dispatchEvent(m),d=u.NONE)}function _(e){!1!==s.enabled&&e.preventDefault()}s.domElement.addEventListener("contextmenu",_,!1),s.domElement.addEventListener("mousedown",U,!1),s.domElement.addEventListener("wheel",z,!1),s.domElement.addEventListener("touchstart",I,!1),s.domElement.addEventListener("touchend",K,!1),s.domElement.addEventListener("touchmove",X,!1),window.addEventListener("keydown",F,!1),this.update()},THREE.OrbitControls.prototype=Object.create(THREE.EventDispatcher.prototype),THREE.OrbitControls.prototype.constructor=THREE.OrbitControls,Object.defineProperties(THREE.OrbitControls.prototype,{center:{get:function(){return console.warn("THREE.OrbitControls: .center has been renamed to .target"),this.target}},noZoom:{get:function(){return console.warn("THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead."),!this.enableZoom},set:function(e){console.warn("THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead."),this.enableZoom=!e}},noRotate:{get:function(){return console.warn("THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead."),!this.enableRotate},set:function(e){console.warn("THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead."),this.enableRotate=!e}},noPan:{get:function(){return console.warn("THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead."),!this.enablePan},set:function(e){console.warn("THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead."),this.enablePan=!e}},noKeys:{get:function(){return console.warn("THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead."),!this.enableKeys},set:function(e){console.warn("THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead."),this.enableKeys=!e}},staticMoving:{get:function(){return console.warn("THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead."),!this.enableDamping},set:function(e){console.warn("THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead."),this.enableDamping=!e}},dynamicDampingFactor:{get:function(){return console.warn("THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead."),this.dampingFactor},set:function(e){console.warn("THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead."),this.dampingFactor=e}}});
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aviation-with-code",
3 | "version": "1.0.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "git+https://github.com/dopevog/aviation-with-code.git"
7 | },
8 | "dependencies": {
9 | "blockly": "github:google/blockly",
10 | "blockly-gamepad": "github:dopevog/blockly-gamepad"
11 | },
12 | "author": "dopevog",
13 | "license": "MIT",
14 | "homepage": "https://github.com/dopevog/aviation-with-code#readme"
15 | }
16 |
--------------------------------------------------------------------------------
/solution/README.md:
--------------------------------------------------------------------------------
1 | ## Yep, the last level [solution](https://dopevog.github.io/aviation-with-code/solution/).
--------------------------------------------------------------------------------
/solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Load the solution
6 |
165 |
166 |
167 |
170 |
195 |
196 |
197 |
198 | 0 UNTIL 2 calc Describe this function... #80E9E7 TRUE TRUE TRUE FALSE 0 0 TRUE TRUE 0 TRUE FALSE update Describe this function... UNTIL #f7d9aa 2 2 2 0 #f7d9aa UNTIL #f7d9aa 2 go Describe this function... UNTIL #f5f5f5 2 UNTIL #7D669E 0 checker Describe this function... 0 #f7d9aa 2 TRUE TRUE #80E9E7 2 TRUE FALSE 2 TRUE TRUE 2 TRUE FALSE find lightblue Describe this function... 0 UNTIL #80E9E7 0 left Describe this function... 3 0 1 right Describe this function... 1 0 3 find violet Describe this function... UNTIL #7D669E 2
199 |
200 |
⚠️⚠️⚠️ Clicking the button below you will load the solution of the final level of the
201 |   Impossible ocean
202 | 🐳   world. I advise you to try again to solve it before loading the solution.
203 |
204 |
210 |
211 |
Don't forget to star the project 😎
212 |
213 |
219 |
220 |
221 |
222 |
223 |
--------------------------------------------------------------------------------
/tutorial/css/black.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Black theme for reveal.js. This is the opposite of the 'white' theme.
3 | *
4 | * By Hakim El Hattab, http://hakim.se
5 | */
6 | @import url(../font/source-sans-pro.css);
7 | section.has-light-background, section.has-light-background h1, section.has-light-background h2, section.has-light-background h3, section.has-light-background h4, section.has-light-background h5, section.has-light-background h6 {
8 | color: #222; }
9 |
10 | /*********************************************
11 | * GLOBAL STYLES
12 | *********************************************/
13 | body {
14 | background: #191919;
15 | background-color: #191919; }
16 |
17 | .reveal {
18 | font-family: "Source Sans Pro", Helvetica, sans-serif;
19 | font-size: 42px;
20 | font-weight: normal;
21 | color: #fff; }
22 |
23 | ::selection {
24 | color: #fff;
25 | background: #bee4fd;
26 | text-shadow: none; }
27 |
28 | ::-moz-selection {
29 | color: #fff;
30 | background: #bee4fd;
31 | text-shadow: none; }
32 |
33 | .reveal .slides section,
34 | .reveal .slides section > section {
35 | line-height: 1.3;
36 | font-weight: inherit; }
37 |
38 | /*********************************************
39 | * HEADERS
40 | *********************************************/
41 | .reveal h1,
42 | .reveal h2,
43 | .reveal h3,
44 | .reveal h4,
45 | .reveal h5,
46 | .reveal h6 {
47 | margin: 0 0 20px 0;
48 | color: #fff;
49 | font-family: "Source Sans Pro", Helvetica, sans-serif;
50 | font-weight: 600;
51 | line-height: 1.2;
52 | letter-spacing: normal;
53 | text-transform: uppercase;
54 | text-shadow: none;
55 | word-wrap: break-word; }
56 |
57 | .reveal h1 {
58 | font-size: 2.5em; }
59 |
60 | .reveal h2 {
61 | font-size: 1.6em; }
62 |
63 | .reveal h3 {
64 | font-size: 1.3em; }
65 |
66 | .reveal h4 {
67 | font-size: 1em; }
68 |
69 | .reveal h1 {
70 | text-shadow: none; }
71 |
72 | /*********************************************
73 | * OTHER
74 | *********************************************/
75 | .reveal p {
76 | margin: 20px 0;
77 | line-height: 1.3; }
78 |
79 | /* Ensure certain elements are never larger than the slide itself */
80 | .reveal img,
81 | .reveal video,
82 | .reveal iframe {
83 | max-width: 95%;
84 | max-height: 95%; }
85 |
86 | .reveal strong,
87 | .reveal b {
88 | font-weight: bold; }
89 |
90 | .reveal em {
91 | font-style: italic; }
92 |
93 | .reveal ol,
94 | .reveal dl,
95 | .reveal ul {
96 | display: inline-block;
97 | text-align: left;
98 | margin: 0 0 0 1em; }
99 |
100 | .reveal ol {
101 | list-style-type: decimal; }
102 |
103 | .reveal ul {
104 | list-style-type: disc; }
105 |
106 | .reveal ul ul {
107 | list-style-type: square; }
108 |
109 | .reveal ul ul ul {
110 | list-style-type: circle; }
111 |
112 | .reveal ul ul,
113 | .reveal ul ol,
114 | .reveal ol ol,
115 | .reveal ol ul {
116 | display: block;
117 | margin-left: 40px; }
118 |
119 | .reveal dt {
120 | font-weight: bold; }
121 |
122 | .reveal dd {
123 | margin-left: 40px; }
124 |
125 | .reveal blockquote {
126 | display: block;
127 | position: relative;
128 | width: 70%;
129 | margin: 20px auto;
130 | padding: 5px;
131 | font-style: italic;
132 | background: rgba(255, 255, 255, 0.05);
133 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); }
134 |
135 | .reveal blockquote p:first-child,
136 | .reveal blockquote p:last-child {
137 | display: inline-block; }
138 |
139 | .reveal q {
140 | font-style: italic; }
141 |
142 | .reveal pre {
143 | display: block;
144 | position: relative;
145 | width: 90%;
146 | margin: 20px auto;
147 | text-align: left;
148 | font-size: 0.55em;
149 | font-family: monospace;
150 | line-height: 1.2em;
151 | word-wrap: break-word;
152 | box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15); }
153 |
154 | .reveal code {
155 | font-family: monospace;
156 | text-transform: none; }
157 |
158 | .reveal pre code {
159 | display: block;
160 | padding: 5px;
161 | overflow: auto;
162 | max-height: 400px;
163 | word-wrap: normal; }
164 |
165 | .reveal table {
166 | margin: auto;
167 | border-collapse: collapse;
168 | border-spacing: 0; }
169 |
170 | .reveal table th {
171 | font-weight: bold; }
172 |
173 | .reveal table th,
174 | .reveal table td {
175 | text-align: left;
176 | padding: 0.2em 0.5em 0.2em 0.5em;
177 | border-bottom: 1px solid; }
178 |
179 | .reveal table th[align="center"],
180 | .reveal table td[align="center"] {
181 | text-align: center; }
182 |
183 | .reveal table th[align="right"],
184 | .reveal table td[align="right"] {
185 | text-align: right; }
186 |
187 | .reveal table tbody tr:last-child th,
188 | .reveal table tbody tr:last-child td {
189 | border-bottom: none; }
190 |
191 | .reveal sup {
192 | vertical-align: super;
193 | font-size: smaller; }
194 |
195 | .reveal sub {
196 | vertical-align: sub;
197 | font-size: smaller; }
198 |
199 | .reveal small {
200 | display: inline-block;
201 | font-size: 0.6em;
202 | line-height: 1.2em;
203 | vertical-align: top; }
204 |
205 | .reveal small * {
206 | vertical-align: top; }
207 |
208 | /*********************************************
209 | * LINKS
210 | *********************************************/
211 | .reveal a {
212 | color: #42affa;
213 | text-decoration: none;
214 | -webkit-transition: color .15s ease;
215 | -moz-transition: color .15s ease;
216 | transition: color .15s ease; }
217 |
218 | .reveal a:hover {
219 | color: #8dcffc;
220 | text-shadow: none;
221 | border: none; }
222 |
223 | .reveal .roll span:after {
224 | color: #fff;
225 | background: #068de9; }
226 |
227 | /*********************************************
228 | * IMAGES
229 | *********************************************/
230 | .reveal section img {
231 | margin: 15px 0px;
232 | background: rgba(255, 255, 255, 0.12);
233 | border: 4px solid #fff;
234 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); }
235 |
236 | .reveal section img.plain {
237 | border: 0;
238 | box-shadow: none; }
239 |
240 | .reveal a img {
241 | -webkit-transition: all .15s linear;
242 | -moz-transition: all .15s linear;
243 | transition: all .15s linear; }
244 |
245 | .reveal a:hover img {
246 | background: rgba(255, 255, 255, 0.2);
247 | border-color: #42affa;
248 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); }
249 |
250 | /*********************************************
251 | * NAVIGATION CONTROLS
252 | *********************************************/
253 | .reveal .controls {
254 | color: #42affa; }
255 |
256 | /*********************************************
257 | * PROGRESS BAR
258 | *********************************************/
259 | .reveal .progress {
260 | background: rgba(0, 0, 0, 0.2);
261 | color: #42affa; }
262 |
263 | .reveal .progress span {
264 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
265 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
266 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }
267 |
268 | /*********************************************
269 | * PRINT BACKGROUND
270 | *********************************************/
271 | @media print {
272 | .backgrounds {
273 | background-color: #191919; } }
274 |
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-italic.eot
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-italic.ttf
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-italic.woff
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-regular.eot
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-regular.ttf
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-regular.woff
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-semibold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-semibold.eot
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-semibold.ttf
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-semibold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-semibold.woff
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-semibolditalic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-semibolditalic.eot
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-semibolditalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-semibolditalic.ttf
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro-semibolditalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/font/source-sans-pro-semibolditalic.woff
--------------------------------------------------------------------------------
/tutorial/font/source-sans-pro.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Source Sans Pro';
3 | src: url('source-sans-pro-regular.eot');
4 | src: url('source-sans-pro-regular.eot?#iefix') format('embedded-opentype'),
5 | url('source-sans-pro-regular.woff') format('woff'),
6 | url('source-sans-pro-regular.ttf') format('truetype');
7 | font-weight: normal;
8 | font-style: normal;
9 | }
10 |
11 | @font-face {
12 | font-family: 'Source Sans Pro';
13 | src: url('source-sans-pro-italic.eot');
14 | src: url('source-sans-pro-italic.eot?#iefix') format('embedded-opentype'),
15 | url('source-sans-pro-italic.woff') format('woff'),
16 | url('source-sans-pro-italic.ttf') format('truetype');
17 | font-weight: normal;
18 | font-style: italic;
19 | }
20 |
21 | @font-face {
22 | font-family: 'Source Sans Pro';
23 | src: url('source-sans-pro-semibold.eot');
24 | src: url('source-sans-pro-semibold.eot?#iefix') format('embedded-opentype'),
25 | url('source-sans-pro-semibold.woff') format('woff'),
26 | url('source-sans-pro-semibold.ttf') format('truetype');
27 | font-weight: 600;
28 | font-style: normal;
29 | }
30 |
31 | @font-face {
32 | font-family: 'Source Sans Pro';
33 | src: url('source-sans-pro-semibolditalic.eot');
34 | src: url('source-sans-pro-semibolditalic.eot?#iefix') format('embedded-opentype'),
35 | url('source-sans-pro-semibolditalic.woff') format('woff'),
36 | url('source-sans-pro-semibolditalic.ttf') format('truetype');
37 | font-weight: 600;
38 | font-style: italic;
39 | }
--------------------------------------------------------------------------------
/tutorial/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/1.png
--------------------------------------------------------------------------------
/tutorial/images/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/2.png
--------------------------------------------------------------------------------
/tutorial/images/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/3.png
--------------------------------------------------------------------------------
/tutorial/images/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/4.png
--------------------------------------------------------------------------------
/tutorial/images/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/5.png
--------------------------------------------------------------------------------
/tutorial/images/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/6.png
--------------------------------------------------------------------------------
/tutorial/images/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/7.png
--------------------------------------------------------------------------------
/tutorial/images/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/arrow.png
--------------------------------------------------------------------------------
/tutorial/images/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/code.png
--------------------------------------------------------------------------------
/tutorial/images/debug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/debug.png
--------------------------------------------------------------------------------
/tutorial/images/final1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/final1.png
--------------------------------------------------------------------------------
/tutorial/images/final2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/final2.png
--------------------------------------------------------------------------------
/tutorial/images/gover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/gover.png
--------------------------------------------------------------------------------
/tutorial/images/gover2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/gover2.png
--------------------------------------------------------------------------------
/tutorial/images/gtake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/gtake.png
--------------------------------------------------------------------------------
/tutorial/images/gtaken2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/gtaken2.png
--------------------------------------------------------------------------------
/tutorial/images/iftaken.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/iftaken.png
--------------------------------------------------------------------------------
/tutorial/images/load.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/load.png
--------------------------------------------------------------------------------
/tutorial/images/menu.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/menu.gif
--------------------------------------------------------------------------------
/tutorial/images/movebackward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/movebackward.png
--------------------------------------------------------------------------------
/tutorial/images/moveforward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/moveforward.png
--------------------------------------------------------------------------------
/tutorial/images/over.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/over.png
--------------------------------------------------------------------------------
/tutorial/images/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/play.png
--------------------------------------------------------------------------------
/tutorial/images/release.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/release.png
--------------------------------------------------------------------------------
/tutorial/images/show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/show.png
--------------------------------------------------------------------------------
/tutorial/images/take.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/take.png
--------------------------------------------------------------------------------
/tutorial/images/taken.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/taken.png
--------------------------------------------------------------------------------
/tutorial/images/turnleft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/turnleft.png
--------------------------------------------------------------------------------
/tutorial/images/turnright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/turnright.png
--------------------------------------------------------------------------------
/tutorial/images/whileover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/whileover.png
--------------------------------------------------------------------------------
/tutorial/images/worlds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/worlds.png
--------------------------------------------------------------------------------
/tutorial/images/wow.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/aviation-with-code/885dce2221df27898ac693fdb96465128ec3edc3/tutorial/images/wow.gif
--------------------------------------------------------------------------------
/tutorial/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Tutorial
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Tutorial
20 |
21 | Welcome to the tutorial of Aviation With Coding .
22 | In the next slides you will be explained the
23 | mechanics of the game.
24 |
25 |
26 | Created by
28 | Vedant K
30 |
31 |
32 |
33 |
34 | Rules
35 |
36 | The Game consists of blocks placed on a grid, some of them are fully
37 | colored and other are
38 | translucent . The Game is
39 | solved when all the colored blocks are moved in the position of the
40 | corrisponding translucent ones. Here's an example:
41 |
42 |
61 |
62 |
63 | Rules
64 |
65 | To solve the Game you have to assemble the
66 | code . Through the code you can interact with the
68 | Aviator and
69 | therefore with the blocks.
70 |
71 |
75 |
76 |
77 | example
78 |
79 | This is the screen of a
80 | level .
81 |
82 |
86 |
87 |
88 |
89 | These are the methods you can use to interact with the
92 | Aviator
95 |
96 |
97 |
98 | Move forward
109 |
110 |
111 | Move backward
122 |
123 |
124 | Turn right
135 |
136 |
137 | Turn left
148 |
149 |
150 | Take
161 |
162 |
163 | Release
174 |
175 |
176 | Over
187 |
188 |
189 | Taken
200 |
201 |
202 |
203 |
204 |
205 | Move forward & backward
206 |
207 |
208 |
209 | Move the Aviator one step forward or backward.
210 |
211 |
212 |
231 |
232 |
233 |
234 | Turn right & left
235 |
236 |
237 |
238 | Turn the Aviator right or left.
239 |
240 |
241 |
260 |
261 |
262 | Take
263 |
264 | If the Aviator is over a column of blocks, the top block of the
265 | column will be removed. That block is now
266 | taken . The block
267 | taken will be under the
268 | Aviator, you can carry it around the grid and then release it. If
269 | two blocks are taken in a row, the first one will be lost. The
270 | Game board the board shows
271 | the color of the block taken.
272 |
273 |
274 |
281 |
282 |
291 |
292 |
301 |
302 |
303 |
304 | Release
305 |
306 |
307 | Release the taken block
308 | under the Aviator. If the Aviator is over a column of blocks the
309 | taken block is released on
310 | the top.
311 |
312 |
313 |
332 |
333 |
334 | Taken
335 |
336 |
337 | This is a control method
338 | for colored blocks. You can choose any color and this method
339 | will check if the
340 | taken block is of that
341 | color.
342 | If white is selected this
343 | method will check if there's a taken block of any color.
344 |
345 |
346 |
353 |
354 |
363 |
373 |
374 |
375 |
384 |
385 |
386 |
387 |
388 | Over
389 |
390 |
391 | This is a control method
392 | for colored blocks. You can choose any color and this method
393 | will check if the Aviator is
394 | over a block of that
395 | color. If white is
396 | selected this method will check if the Aviator is over a block of
397 | any color.
398 |
399 |
400 | If the Aviator is over a column of blocks the top block is
401 | checked.
402 |
403 |
404 |
411 |
421 |
422 |
423 |
432 |
433 |
442 |
443 |
444 |
445 | The worlds
446 |
447 |
448 | There are 4 worlds .
449 | Each world is made up of playable
450 | levels .
451 |
452 |
453 |
462 |
463 |
464 | The worlds
465 |
466 |
467 | Every world has its
468 | difficulty .
469 | The last world contains an almost
470 | impossible level to solve.
471 |
472 |
473 |
482 |
483 |
484 | The levels
485 |
486 |
487 | Each level is composed of
488 | sub-levels . To solve
489 | a level the same code must
490 | complete each sub-level.
491 | You can see each sub-level using the buttons below.
492 |
493 |
494 |
505 |
506 |
507 | Load the code
508 |
509 |
510 | Every time you write
511 | new code and want to try
512 | it, remember to load it
513 | before starting the Game.
514 |
515 |
516 |
527 |
528 |
529 | Try the code
530 |
531 |
532 | Once you have loaded your code you can try it, use the button
533 | below to Play / Pause the
534 | Game. You can also use the time travel debugger to load one
535 | block of code at a time
536 | (the next one or the previous one).
537 |
538 |
539 |
550 |
551 |
552 | Debug
553 |
554 | Select a block and use it as a
555 | breakpoint .
557 | The Game will start (forward or backward) until that block is
558 | reached.
559 |
560 |
561 |
565 |
566 |
567 | Menu
568 |
569 | Don't forget to open the
570 | menu .
571 |
572 |
573 |
574 |
578 |
579 |
582 |
583 |
587 | ... You're ready to code!
588 |
589 |
590 |
591 |
592 |
593 |
603 |
604 |
605 |
--------------------------------------------------------------------------------