├── .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 |
16 | 17 |
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 | ' ' + 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 | 0UNTIL2calcDescribe this function...#80E9E7TRUETRUETRUEFALSE00TRUETRUE0TRUEFALSEupdateDescribe this function...UNTIL#f7d9aa2220#f7d9aaUNTIL#f7d9aa2goDescribe this function...UNTIL#f5f5f52UNTIL#7D669E0checkerDescribe this function...0#f7d9aa2TRUETRUE#80E9E72TRUEFALSE2TRUETRUE2TRUEFALSEfind lightblueDescribe this function...0UNTIL#80E9E70leftDescribe this function...301rightDescribe this function...103find violetDescribe this function...UNTIL#7D669E2 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 |
49 | 50 | 59 | 60 |
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 |
219 | 220 | 229 | 230 |
231 |
232 |
233 |

234 | Turn right & left 235 |

236 |

237 | 238 | Turn the Aviator right or left. 239 | 240 |

241 |
248 | 249 | 258 | 259 |
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 |
320 | 321 | 330 | 331 |
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 |
580 |

And now...

581 |
582 |
583 |

587 | ... You're ready to code! 588 |

589 |
590 |
591 |
592 | 593 | 603 | 604 | 605 | --------------------------------------------------------------------------------