├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── app_icons │ ├── icon_1024.png │ ├── icon_114.png │ ├── icon_120.png │ ├── icon_144.png │ ├── icon_152.png │ ├── icon_167.png │ ├── icon_180.png │ ├── icon_192.png │ ├── icon_36.png │ ├── icon_48.png │ ├── icon_57.png │ ├── icon_72.png │ ├── icon_76.png │ └── icon_96.png ├── fonts │ ├── Kenney Pixel.ttf │ └── instructions.font ├── game.tilesource └── images │ └── tilemap.png ├── docs ├── PixelLinePlatformer.wasm ├── PixelLinePlatformer_asmjs.js ├── PixelLinePlatformer_wasm.js ├── archive │ ├── archive_files.json │ ├── game.arcd0 │ ├── game.arci0 │ ├── game.dmanifest0 │ ├── game.projectc0 │ └── game.public.der0 ├── dmloader.js ├── index.html └── screenshot.png ├── game.project ├── game ├── bee.go ├── bee.script ├── bluebee.go ├── bluebee.script ├── bullet.go ├── dust.particlefx ├── game.collection ├── jump.particlefx ├── level.script ├── level.tilemap ├── player.collection ├── player.script ├── slime.go └── slime.script └── input └── game.input_binding /.gitattributes: -------------------------------------------------------------------------------- 1 | # Defold Protocol Buffer Text Files (https://github.com/github/linguist/issues/5091) 2 | *.animationset linguist-language=JSON5 3 | *.atlas linguist-language=JSON5 4 | *.camera linguist-language=JSON5 5 | *.collection linguist-language=JSON5 6 | *.collectionfactory linguist-language=JSON5 7 | *.collectionproxy linguist-language=JSON5 8 | *.collisionobject linguist-language=JSON5 9 | *.cubemap linguist-language=JSON5 10 | *.display_profiles linguist-language=JSON5 11 | *.factory linguist-language=JSON5 12 | *.font linguist-language=JSON5 13 | *.gamepads linguist-language=JSON5 14 | *.go linguist-language=JSON5 15 | *.gui linguist-language=JSON5 16 | *.input_binding linguist-language=JSON5 17 | *.label linguist-language=JSON5 18 | *.material linguist-language=JSON5 19 | *.mesh linguist-language=JSON5 20 | *.model linguist-language=JSON5 21 | *.particlefx linguist-language=JSON5 22 | *.render linguist-language=JSON5 23 | *.sound linguist-language=JSON5 24 | *.sprite linguist-language=JSON5 25 | *.spinemodel linguist-language=JSON5 26 | *.spinescene linguist-language=JSON5 27 | *.texture_profiles linguist-language=JSON5 28 | *.tilemap linguist-language=JSON5 29 | *.tilesource linguist-language=JSON5 30 | 31 | # Defold JSON Files 32 | *.buffer linguist-language=JSON 33 | 34 | # Defold GLSL Shaders 35 | *.fp linguist-language=GLSL 36 | *.vp linguist-language=GLSL 37 | 38 | # Defold Lua Files 39 | *.editor_script linguist-language=Lua 40 | *.render_script linguist-language=Lua 41 | *.script linguist-language=Lua 42 | *.gui_script linguist-language=Lua 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.editor_settings 2 | /.internal 3 | /build 4 | .externalToolBuilders 5 | .DS_Store 6 | Thumbs.db 7 | .lock-wscript 8 | *.pyc 9 | .project 10 | .cproject 11 | builtins -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Defold 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixel Line Platformer sample 2 | Defold sample project for a platformer game. 3 | 4 | ![](/docs/screenshot.png) 5 | 6 | # Demo 7 | Try the HTML5 demo here: https://defold.com/sample-pixel-line-platformer/ 8 | 9 | # Credits 10 | * Graphics - [Pixel Line Platformer](https://kenney.nl/assets/pixel-line-platformer) by [Kenney](https://kenney.nl) 11 | * Font - Kenney Pixel from [Kenney Fonts](https://kenney.nl/assets/kenney-fonts) by [Kenney](https://kenney.nl) 12 | -------------------------------------------------------------------------------- /assets/app_icons/icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_1024.png -------------------------------------------------------------------------------- /assets/app_icons/icon_114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_114.png -------------------------------------------------------------------------------- /assets/app_icons/icon_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_120.png -------------------------------------------------------------------------------- /assets/app_icons/icon_144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_144.png -------------------------------------------------------------------------------- /assets/app_icons/icon_152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_152.png -------------------------------------------------------------------------------- /assets/app_icons/icon_167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_167.png -------------------------------------------------------------------------------- /assets/app_icons/icon_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_180.png -------------------------------------------------------------------------------- /assets/app_icons/icon_192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_192.png -------------------------------------------------------------------------------- /assets/app_icons/icon_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_36.png -------------------------------------------------------------------------------- /assets/app_icons/icon_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_48.png -------------------------------------------------------------------------------- /assets/app_icons/icon_57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_57.png -------------------------------------------------------------------------------- /assets/app_icons/icon_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_72.png -------------------------------------------------------------------------------- /assets/app_icons/icon_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_76.png -------------------------------------------------------------------------------- /assets/app_icons/icon_96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/app_icons/icon_96.png -------------------------------------------------------------------------------- /assets/fonts/Kenney Pixel.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/fonts/Kenney Pixel.ttf -------------------------------------------------------------------------------- /assets/fonts/instructions.font: -------------------------------------------------------------------------------- 1 | font: "/assets/fonts/Kenney Pixel.ttf" 2 | material: "/builtins/fonts/font.material" 3 | size: 16 4 | antialias: 0 5 | alpha: 1.0 6 | outline_alpha: 0.0 7 | outline_width: 0.0 8 | shadow_alpha: 0.0 9 | shadow_blur: 0 10 | shadow_x: 0.0 11 | shadow_y: 0.0 12 | extra_characters: "" 13 | output_format: TYPE_BITMAP 14 | all_chars: false 15 | cache_width: 0 16 | cache_height: 0 17 | render_mode: MODE_SINGLE_LAYER 18 | -------------------------------------------------------------------------------- /assets/game.tilesource: -------------------------------------------------------------------------------- 1 | image: "/assets/images/tilemap.png" 2 | tile_width: 16 3 | tile_height: 16 4 | tile_margin: 0 5 | tile_spacing: 1 6 | collision: "/assets/images/tilemap.png" 7 | material_tag: "tile" 8 | convex_hulls { 9 | index: 0 10 | count: 4 11 | collision_group: "" 12 | } 13 | convex_hulls { 14 | index: 4 15 | count: 4 16 | collision_group: "" 17 | } 18 | convex_hulls { 19 | index: 8 20 | count: 4 21 | collision_group: "" 22 | } 23 | convex_hulls { 24 | index: 12 25 | count: 4 26 | collision_group: "ground" 27 | } 28 | convex_hulls { 29 | index: 16 30 | count: 4 31 | collision_group: "ground" 32 | } 33 | convex_hulls { 34 | index: 20 35 | count: 4 36 | collision_group: "ground" 37 | } 38 | convex_hulls { 39 | index: 24 40 | count: 4 41 | collision_group: "ground" 42 | } 43 | convex_hulls { 44 | index: 28 45 | count: 4 46 | collision_group: "ground" 47 | } 48 | convex_hulls { 49 | index: 32 50 | count: 4 51 | collision_group: "ground" 52 | } 53 | convex_hulls { 54 | index: 36 55 | count: 4 56 | collision_group: "ground" 57 | } 58 | convex_hulls { 59 | index: 40 60 | count: 4 61 | collision_group: "" 62 | } 63 | convex_hulls { 64 | index: 44 65 | count: 4 66 | collision_group: "" 67 | } 68 | convex_hulls { 69 | index: 48 70 | count: 4 71 | collision_group: "" 72 | } 73 | convex_hulls { 74 | index: 52 75 | count: 4 76 | collision_group: "ground" 77 | } 78 | convex_hulls { 79 | index: 56 80 | count: 4 81 | collision_group: "ground" 82 | } 83 | convex_hulls { 84 | index: 60 85 | count: 4 86 | collision_group: "ground" 87 | } 88 | convex_hulls { 89 | index: 64 90 | count: 4 91 | collision_group: "ground" 92 | } 93 | convex_hulls { 94 | index: 68 95 | count: 4 96 | collision_group: "ground" 97 | } 98 | convex_hulls { 99 | index: 72 100 | count: 4 101 | collision_group: "ground" 102 | } 103 | convex_hulls { 104 | index: 76 105 | count: 4 106 | collision_group: "ground" 107 | } 108 | convex_hulls { 109 | index: 80 110 | count: 4 111 | collision_group: "ground" 112 | } 113 | convex_hulls { 114 | index: 84 115 | count: 4 116 | collision_group: "ground" 117 | } 118 | convex_hulls { 119 | index: 88 120 | count: 4 121 | collision_group: "ground" 122 | } 123 | convex_hulls { 124 | index: 92 125 | count: 4 126 | collision_group: "ground" 127 | } 128 | convex_hulls { 129 | index: 96 130 | count: 4 131 | collision_group: "ground" 132 | } 133 | convex_hulls { 134 | index: 100 135 | count: 4 136 | collision_group: "ground" 137 | } 138 | convex_hulls { 139 | index: 104 140 | count: 4 141 | collision_group: "ground" 142 | } 143 | convex_hulls { 144 | index: 108 145 | count: 4 146 | collision_group: "ground" 147 | } 148 | convex_hulls { 149 | index: 112 150 | count: 4 151 | collision_group: "ground" 152 | } 153 | convex_hulls { 154 | index: 116 155 | count: 4 156 | collision_group: "ground" 157 | } 158 | convex_hulls { 159 | index: 120 160 | count: 4 161 | collision_group: "" 162 | } 163 | convex_hulls { 164 | index: 124 165 | count: 4 166 | collision_group: "" 167 | } 168 | convex_hulls { 169 | index: 128 170 | count: 4 171 | collision_group: "" 172 | } 173 | convex_hulls { 174 | index: 132 175 | count: 4 176 | collision_group: "" 177 | } 178 | convex_hulls { 179 | index: 136 180 | count: 4 181 | collision_group: "" 182 | } 183 | convex_hulls { 184 | index: 140 185 | count: 4 186 | collision_group: "" 187 | } 188 | convex_hulls { 189 | index: 144 190 | count: 4 191 | collision_group: "" 192 | } 193 | convex_hulls { 194 | index: 148 195 | count: 4 196 | collision_group: "" 197 | } 198 | convex_hulls { 199 | index: 152 200 | count: 4 201 | collision_group: "" 202 | } 203 | convex_hulls { 204 | index: 156 205 | count: 4 206 | collision_group: "" 207 | } 208 | convex_hulls { 209 | index: 160 210 | count: 7 211 | collision_group: "" 212 | } 213 | convex_hulls { 214 | index: 167 215 | count: 6 216 | collision_group: "" 217 | } 218 | convex_hulls { 219 | index: 173 220 | count: 8 221 | collision_group: "" 222 | } 223 | convex_hulls { 224 | index: 181 225 | count: 8 226 | collision_group: "" 227 | } 228 | convex_hulls { 229 | index: 189 230 | count: 6 231 | collision_group: "" 232 | } 233 | convex_hulls { 234 | index: 195 235 | count: 10 236 | collision_group: "" 237 | } 238 | convex_hulls { 239 | index: 205 240 | count: 8 241 | collision_group: "" 242 | } 243 | convex_hulls { 244 | index: 213 245 | count: 4 246 | collision_group: "" 247 | } 248 | convex_hulls { 249 | index: 217 250 | count: 4 251 | collision_group: "" 252 | } 253 | convex_hulls { 254 | index: 221 255 | count: 4 256 | collision_group: "" 257 | } 258 | convex_hulls { 259 | index: 225 260 | count: 7 261 | collision_group: "" 262 | } 263 | convex_hulls { 264 | index: 232 265 | count: 8 266 | collision_group: "" 267 | } 268 | convex_hulls { 269 | index: 240 270 | count: 8 271 | collision_group: "" 272 | } 273 | convex_hulls { 274 | index: 248 275 | count: 6 276 | collision_group: "" 277 | } 278 | convex_hulls { 279 | index: 254 280 | count: 6 281 | collision_group: "" 282 | } 283 | convex_hulls { 284 | index: 260 285 | count: 8 286 | collision_group: "" 287 | } 288 | convex_hulls { 289 | index: 268 290 | count: 8 291 | collision_group: "" 292 | } 293 | convex_hulls { 294 | index: 276 295 | count: 4 296 | collision_group: "" 297 | } 298 | convex_hulls { 299 | index: 280 300 | count: 4 301 | collision_group: "" 302 | } 303 | convex_hulls { 304 | index: 284 305 | count: 4 306 | collision_group: "" 307 | } 308 | collision_groups: "ground" 309 | animations { 310 | id: "bee" 311 | start_tile: 52 312 | end_tile: 53 313 | playback: PLAYBACK_LOOP_FORWARD 314 | fps: 10 315 | flip_horizontal: 0 316 | flip_vertical: 0 317 | } 318 | animations { 319 | id: "bluebee" 320 | start_tile: 54 321 | end_tile: 55 322 | playback: PLAYBACK_LOOP_FORWARD 323 | fps: 10 324 | flip_horizontal: 0 325 | flip_vertical: 0 326 | } 327 | animations { 328 | id: "bullet" 329 | start_tile: 44 330 | end_tile: 45 331 | playback: PLAYBACK_ONCE_FORWARD 332 | fps: 10 333 | flip_horizontal: 0 334 | flip_vertical: 0 335 | } 336 | animations { 337 | id: "player_fall" 338 | start_tile: 42 339 | end_tile: 42 340 | playback: PLAYBACK_ONCE_FORWARD 341 | fps: 10 342 | flip_horizontal: 0 343 | flip_vertical: 0 344 | } 345 | animations { 346 | id: "player_idle" 347 | start_tile: 41 348 | end_tile: 41 349 | playback: PLAYBACK_LOOP_FORWARD 350 | fps: 10 351 | flip_horizontal: 0 352 | flip_vertical: 0 353 | } 354 | animations { 355 | id: "player_jump" 356 | start_tile: 41 357 | end_tile: 42 358 | playback: PLAYBACK_ONCE_FORWARD 359 | fps: 10 360 | flip_horizontal: 0 361 | flip_vertical: 0 362 | } 363 | animations { 364 | id: "player_walk" 365 | start_tile: 41 366 | end_tile: 43 367 | playback: PLAYBACK_LOOP_FORWARD 368 | fps: 10 369 | flip_horizontal: 0 370 | flip_vertical: 0 371 | } 372 | animations { 373 | id: "slime" 374 | start_tile: 56 375 | end_tile: 57 376 | playback: PLAYBACK_LOOP_FORWARD 377 | fps: 10 378 | flip_horizontal: 0 379 | flip_vertical: 0 380 | } 381 | extrude_borders: 2 382 | inner_padding: 0 383 | sprite_trim_mode: SPRITE_TRIM_MODE_OFF 384 | -------------------------------------------------------------------------------- /assets/images/tilemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/assets/images/tilemap.png -------------------------------------------------------------------------------- /docs/PixelLinePlatformer.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/docs/PixelLinePlatformer.wasm -------------------------------------------------------------------------------- /docs/archive/archive_files.json: -------------------------------------------------------------------------------- 1 | {"content":[{"name":"game.projectc","size":3932,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":4448,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":46382,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":4226,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]} -------------------------------------------------------------------------------- /docs/archive/game.arcd0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/docs/archive/game.arcd0 -------------------------------------------------------------------------------- /docs/archive/game.arci0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/docs/archive/game.arci0 -------------------------------------------------------------------------------- /docs/archive/game.dmanifest0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/docs/archive/game.dmanifest0 -------------------------------------------------------------------------------- /docs/archive/game.projectc0: -------------------------------------------------------------------------------- 1 | [project] 2 | title = PixelLinePlatformer 3 | version = 1.0 4 | write_log = 0 5 | compress_archive = 1 6 | publisher = unnamed 7 | developer = unnamed 8 | 9 | [display] 10 | width = 960 11 | height = 640 12 | high_dpi = 0 13 | samples = 0 14 | fullscreen = 0 15 | update_frequency = 0 16 | vsync = 1 17 | display_profiles = /builtins/render/default.display_profilesc 18 | dynamic_orientation = 0 19 | display_device_info = 0 20 | 21 | [render] 22 | clear_color_red = 0 23 | clear_color_green = 0 24 | clear_color_blue = 0 25 | clear_color_alpha = 0 26 | 27 | [physics] 28 | type = 2D 29 | gravity_y = -1000.0 30 | debug = 0 31 | debug_alpha = 0.9 32 | world_count = 4 33 | gravity_x = 0 34 | gravity_z = 0 35 | scale = 0.1 36 | allow_dynamic_transforms = 1 37 | debug_scale = 30 38 | max_collisions = 64 39 | max_contacts = 128 40 | contact_impulse_limit = 0 41 | ray_cast_limit_2d = 64 42 | ray_cast_limit_3d = 128 43 | trigger_overlap_capacity = 16 44 | 45 | [bootstrap] 46 | main_collection = /game/game.collectionc 47 | render = /builtins/render/default.renderc 48 | 49 | [graphics] 50 | default_texture_min_filter = nearest 51 | default_texture_mag_filter = nearest 52 | max_draw_calls = 1024 53 | max_characters = 8192 54 | max_debug_vertices = 10000 55 | texture_profiles = /builtins/graphics/default.texture_profiles 56 | verify_graphics_calls = 1 57 | memory_size = 512 58 | 59 | [shader] 60 | output_spirv = 0 61 | 62 | [sound] 63 | gain = 1 64 | max_sound_data = 128 65 | max_sound_buffers = 32 66 | max_sound_sources = 16 67 | max_sound_instances = 256 68 | max_component_count = 32 69 | use_thread = 1 70 | 71 | [resource] 72 | http_cache = 0 73 | max_resources = 1024 74 | 75 | [input] 76 | repeat_delay = 0.5 77 | repeat_interval = 0.2 78 | gamepads = /builtins/input/default.gamepadsc 79 | game_binding = /input/game.input_bindingc 80 | use_accelerometer = 0 81 | 82 | [sprite] 83 | max_count = 500 84 | subpixels = 1 85 | 86 | [spine] 87 | max_count = 128 88 | 89 | [model] 90 | max_count = 128 91 | 92 | [mesh] 93 | max_count = 128 94 | 95 | [gui] 96 | max_count = 64 97 | max_particlefx_count = 64 98 | max_particle_count = 1024 99 | 100 | [collection] 101 | max_instances = 1024 102 | max_input_stack_entries = 16 103 | 104 | [collection_proxy] 105 | max_count = 8 106 | 107 | [collectionfactory] 108 | max_count = 128 109 | 110 | [factory] 111 | max_count = 128 112 | 113 | [ios] 114 | launch_screen = /builtins/manifests/ios/LaunchScreen.storyboardc 115 | pre_renderered_icons = 0 116 | bundle_identifier = com.example.todo 117 | infoplist = /builtins/manifests/ios/Info.plist 118 | default_language = en 119 | localizations = en 120 | app_icon_120x120 = /assets/app_icons/icon_120.png 121 | app_icon_180x180 = /assets/app_icons/icon_180.png 122 | app_icon_76x76 = /assets/app_icons/icon_76.png 123 | app_icon_152x152 = /assets/app_icons/icon_152.png 124 | app_icon_57x57 = /assets/app_icons/icon_57.png 125 | app_icon_114x114 = /assets/app_icons/icon_114.png 126 | app_icon_72x72 = /assets/app_icons/icon_72.png 127 | app_icon_144x144 = /assets/app_icons/icon_144.png 128 | app_icon_167x167 = /assets/app_icons/icon_167.png 129 | 130 | [android] 131 | version_code = 1 132 | minimum_sdk_version = 16 133 | target_sdk_version = 30 134 | package = com.example.todo 135 | manifest = /builtins/manifests/android/AndroidManifest.xml 136 | iap_provider = GooglePlay 137 | input_method = HiddenInputField 138 | immersive_mode = 0 139 | display_cutout = 1 140 | debuggable = 0 141 | app_icon_36x36 = /assets/app_icons/icon_36.png 142 | app_icon_48x48 = /assets/app_icons/icon_48.png 143 | app_icon_72x72 = /assets/app_icons/icon_72.png 144 | app_icon_96x96 = /assets/app_icons/icon_96.png 145 | app_icon_144x144 = /assets/app_icons/icon_144.png 146 | app_icon_192x192 = /assets/app_icons/icon_192.png 147 | 148 | [osx] 149 | infoplist = /builtins/manifests/osx/Info.plist 150 | bundle_identifier = com.example.todo 151 | bundle_version = 1 152 | default_language = en 153 | localizations = en 154 | 155 | [windows] 156 | 157 | [html5] 158 | custom_heap_size = 0 159 | heap_size = 256 160 | htmlfile = /builtins/manifests/web/engine_template.html 161 | cssfile = /builtins/manifests/web/light_theme.css 162 | archive_location_prefix = archive 163 | show_fullscreen_button = 1 164 | show_made_with_defold = 1 165 | show_console_banner = 1 166 | scale_mode = downscale_fit 167 | 168 | [particle_fx] 169 | max_count = 64 170 | max_particle_count = 1024 171 | 172 | [iap] 173 | auto_finish_transactions = 1 174 | 175 | [network] 176 | http_timeout = 0 177 | http_thread_count = 4 178 | http_cache_enabled = 1 179 | 180 | [library] 181 | 182 | [script] 183 | shared_state = 1 184 | 185 | [label] 186 | max_count = 64 187 | subpixels = 1 188 | 189 | [profiler] 190 | track_cpu = 0 191 | 192 | [liveupdate] 193 | settings = /liveupdate.settings 194 | enabled = 1 195 | 196 | [tilemap] 197 | max_count = 16 198 | max_tile_count = 2048 199 | 200 | [engine] 201 | run_while_iconified = 0 202 | 203 | -------------------------------------------------------------------------------- /docs/archive/game.public.der0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/docs/archive/game.public.der0 -------------------------------------------------------------------------------- /docs/dmloader.js: -------------------------------------------------------------------------------- 1 | // file downloader 2 | // wraps XMLHttpRequest and adds retry support and progress updates when the 3 | // content is gzipped (gzipped content doesn't report a computable content length 4 | // on Google Chrome) 5 | var FileLoader = { 6 | options: { 7 | retryCount: 4, 8 | retryInterval: 1000, 9 | }, 10 | // do xhr request with retries 11 | request: function(url, method, responseType, currentAttempt) { 12 | if (typeof method === 'undefined') throw "No method specified"; 13 | if (typeof method === 'responseType') throw "No responseType specified"; 14 | if (typeof currentAttempt === 'undefined') currentAttempt = 0; 15 | var obj = { 16 | send: function() { 17 | var onprogress = this.onprogress; 18 | var onload = this.onload; 19 | var onerror = this.onerror; 20 | 21 | var xhr = new XMLHttpRequest(); 22 | xhr.open(method, url, true); 23 | xhr.responseType = responseType; 24 | xhr.onprogress = function(e) { 25 | if (onprogress) onprogress(xhr, e); 26 | }; 27 | xhr.onerror = function(e) { 28 | if (currentAttempt == FileLoader.options.retryCount) { 29 | if (onerror) onerror(xhr, e); 30 | return; 31 | } 32 | currentAttempt = currentAttempt + 1; 33 | setTimeout(obj.send.bind(obj), FileLoader.options.retryInterval); 34 | }; 35 | xhr.onload = function(e) { 36 | if (onload) onload(xhr, e); 37 | }; 38 | xhr.send(null); 39 | } 40 | }; 41 | return obj; 42 | }, 43 | // Do HTTP HEAD request to get size of resource 44 | // callback will receive size or undefined in case of an error 45 | size: function(url, callback) { 46 | var request = FileLoader.request(url, "HEAD", "text"); 47 | request.onerror = function(xhr, e) { 48 | callback(undefined); 49 | }; 50 | request.onload = function(xhr, e) { 51 | if (xhr.readyState === 4) { 52 | if (xhr.status === 200) { 53 | var total = xhr.getResponseHeader('content-length'); 54 | callback(total); 55 | } else { 56 | callback(undefined); 57 | } 58 | } 59 | }; 60 | request.send(); 61 | }, 62 | // Do HTTP GET request 63 | // onprogress(loaded, total) 64 | // onerror(error) 65 | // onload(response) 66 | load: function(url, responseType, estimatedSize, onprogress, onerror, onload) { 67 | var request = FileLoader.request(url, "GET", responseType); 68 | request.onprogress = function(xhr, e) { 69 | if (e.lengthComputable) { 70 | onprogress(e.loaded, e.total); 71 | return; 72 | } 73 | var contentLength = xhr.getResponseHeader('content-length'); 74 | var size = contentLength != undefined ? contentLength : estimatedSize; 75 | if (size) { 76 | onprogress(e.loaded, size); 77 | } else { 78 | onprogress(e.loaded, e.loaded); 79 | } 80 | }; 81 | request.onerror = function(xhr, e) { 82 | onerror("Error loading '" + url + "' (" + e + ")"); 83 | }; 84 | request.onload = function(xhr, e) { 85 | if (xhr.readyState === 4) { 86 | if (xhr.status === 200) { 87 | var res = xhr.response; 88 | if (responseType == "json" && typeof res === "string") { 89 | onload(JSON.parse(res)); 90 | } else { 91 | onload(res); 92 | } 93 | } else { 94 | onerror("Error loading '" + url + "' (" + e + ")"); 95 | } 96 | } 97 | }; 98 | request.send(); 99 | } 100 | }; 101 | 102 | 103 | var EngineLoader = { 104 | wasm_size: 2000000, 105 | wasm_from: 0, 106 | wasm_to: 40, 107 | 108 | wasmjs_size: 250000, 109 | wasmjs_from: 40, 110 | wasmjs_to: 50, 111 | 112 | asmjs_size: 4000000, 113 | asmjs_from: 0, 114 | asmjs_to: 50, 115 | 116 | // load .wasm and set Module.instantiateWasm to use the loaded .wasm file 117 | // https://github.com/emscripten-core/emscripten/blob/master/tests/manual_wasm_instantiate.html#L170 118 | loadWasmAsync: function(src, fromProgress, toProgress, callback) { 119 | FileLoader.load(src, "arraybuffer", EngineLoader.wasm_size, 120 | function(loaded, total) { Progress.calculateProgress(fromProgress, toProgress, loaded, total); }, 121 | function(error) { throw error; }, 122 | function(wasm) { 123 | Module.instantiateWasm = function(imports, successCallback) { 124 | var wasmInstantiate = WebAssembly.instantiate(new Uint8Array(wasm), imports).then(function(output) { 125 | successCallback(output.instance); 126 | }).catch(function(e) { 127 | console.log('wasm instantiation failed! ' + e); 128 | throw e; 129 | }); 130 | return {}; // Compiling asynchronously, no exports. 131 | } 132 | callback(); 133 | }); 134 | }, 135 | 136 | // load and start engine script (asm.js or wasm.js) 137 | loadScriptAsync: function(src, estimatedSize, fromProgress, toProgress) { 138 | FileLoader.load(src, "text", estimatedSize, 139 | function(loaded, total) { Progress.calculateProgress(fromProgress, toProgress, loaded, total); }, 140 | function(error) { throw error; }, 141 | function(response) { 142 | var tag = document.createElement("script"); 143 | tag.text = response; 144 | document.head.appendChild(tag); 145 | }); 146 | }, 147 | 148 | // load engine (asm.js or wasm.js + wasm) 149 | // engine load progress goes from 1-50% for ams.js 150 | // engine load progress goes from 0-40% for .wasm and 40-50% for wasm.js 151 | load: function(appCanvasId, exeName) { 152 | Progress.addProgress(Module.setupCanvas(appCanvasId)); 153 | if (Module['isWASMSupported']) { 154 | EngineLoader.loadWasmAsync(exeName + ".wasm", EngineLoader.wasm_from, EngineLoader.wasm_to, function(wasm) { 155 | EngineLoader.loadScriptAsync(exeName + '_wasm.js', EngineLoader.wasmjs_size, EngineLoader.wasmjs_from, EngineLoader.wasmjs_to); 156 | }); 157 | } else { 158 | EngineLoader.loadScriptAsync(exeName + '_asmjs.js', EngineLoader.asmjs_size, EngineLoader.asmjs_from, EngineLoader.asmjs_to); 159 | } 160 | } 161 | } 162 | 163 | 164 | /* ********************************************************************* */ 165 | /* Load and combine game archive data that is split into archives */ 166 | /* ********************************************************************* */ 167 | 168 | var GameArchiveLoader = { 169 | // which files to load 170 | _files: [], 171 | _fileIndex: 0, 172 | // file 173 | // name: intended filepath of built object 174 | // size: expected size of built object. 175 | // data: combined pieces 176 | // downloaded: total bytes downloaded 177 | // pieces: array of name, offset and data objects 178 | // numExpectedFiles: total number of files expected in description 179 | // lastRequestedPiece: index of last data file requested (strictly ascending) 180 | // totalLoadedPieces: counts the number pieces received 181 | 182 | //MAX_CONCURRENT_XHR: 6, // remove comment if throttling of XHR is desired. 183 | 184 | isCompleted: false, // status of process 185 | 186 | _onFileLoadedListeners: [], // signature: name, data. 187 | _onArchiveLoadedListeners:[], // signature: void 188 | _onFileDownloadErrorListeners: [], // signature: name 189 | 190 | _currentDownloadBytes: 0, 191 | _totalDownloadBytes: 0, 192 | 193 | _archiveLocationFilter: function(path) { return "split" + path; }, 194 | 195 | cleanUp: function() { 196 | this._files = []; 197 | this._fileIndex = 0; 198 | this.isCompleted = false; 199 | this._onGameArchiveLoaderCompletedListeners = []; 200 | this._onAllTargetsBuiltListeners = []; 201 | this._onFileDownloadErrorListeners = []; 202 | 203 | this._currentDownloadBytes = 0; 204 | this._totalDownloadBytes = 0; 205 | }, 206 | 207 | addListener: function(list, callback) { 208 | if (typeof callback !== 'function') throw "Invalid callback registration"; 209 | list.push(callback); 210 | }, 211 | notifyListeners: function(list, data) { 212 | for (i=0; i 1) { 272 | file.data = new Uint8Array(file.size); 273 | } 274 | // how many pieces to download at a time 275 | var limit = file.pieces.length; 276 | if (typeof this.MAX_CONCURRENT_XHR !== 'undefined') { 277 | limit = Math.min(limit, this.MAX_CONCURRENT_XHR); 278 | } 279 | // download pieces 280 | for (var i=0; i start) { 331 | throw "Buffer underflow"; 332 | } 333 | if (end > file.data.length) { 334 | throw "Buffer overflow"; 335 | } 336 | file.data.set(piece.data, piece.offset); 337 | } 338 | }, 339 | 340 | onPieceLoaded: function(file, piece) { 341 | this.addPieceToFile(file, piece); 342 | 343 | ++file.totalLoadedPieces; 344 | // is all pieces of the file loaded? 345 | if (file.totalLoadedPieces == file.pieces.length) { 346 | this.onFileLoaded(file); 347 | } 348 | // continue loading more pieces of the file 349 | // if not all pieces are already in progress 350 | else { 351 | var next = file.lastRequestedPiece + 1; 352 | if (next < file.pieces.length) { 353 | this.downloadPiece(file, next); 354 | } 355 | } 356 | }, 357 | 358 | verifyFile: function(file) { 359 | // verify that we downloaded as much as we were supposed to 360 | var actualSize = 0; 361 | for (var i=0;i 1) { 370 | var output = file.data; 371 | var pieces = file.pieces; 372 | for (i=0; i start) { 380 | throw "Segment underflow"; 381 | } 382 | } 383 | if (pieces.length - 2 > i) { 384 | var next = pieces[i + 1]; 385 | if (end > next.offset) { 386 | throw "Segment overflow"; 387 | } 388 | } 389 | } 390 | } 391 | }, 392 | 393 | onFileLoaded: function(file) { 394 | this.verifyFile(file); 395 | this.notifyFileLoaded(file); 396 | ++this._fileIndex; 397 | if (this._fileIndex == this._files.length) { 398 | this.onArchiveLoaded(); 399 | } else { 400 | this.downloadContent(); 401 | } 402 | }, 403 | 404 | onArchiveLoaded: function() { 405 | this.isCompleted = true; 406 | this.notifyArchiveLoaded(); 407 | } 408 | }; 409 | 410 | /* ********************************************************************* */ 411 | /* Default splash and progress visualisation */ 412 | /* ********************************************************************* */ 413 | 414 | var Progress = { 415 | progress_id: "defold-progress", 416 | bar_id: "defold-progress-bar", 417 | 418 | listeners: [], 419 | 420 | addListener: function(callback) { 421 | if (typeof callback !== 'function') throw "Invalid callback registration"; 422 | this.listeners.push(callback); 423 | }, 424 | 425 | notifyListeners: function(percentage) { 426 | for (i=0; i
'); 434 | Progress.bar = document.getElementById(Progress.bar_id); 435 | Progress.progress = document.getElementById(Progress.progress_id); 436 | }, 437 | 438 | updateProgress: function(percentage) { 439 | if (Progress.bar) { 440 | Progress.bar.style.width = percentage + "%"; 441 | } 442 | Progress.notifyListeners(percentage); 443 | }, 444 | 445 | calculateProgress: function (from, to, current, total) { 446 | this.updateProgress(from + (current / total) * (to - from)); 447 | }, 448 | 449 | removeProgress: function () { 450 | if (Progress.progress.parentElement !== null) { 451 | Progress.progress.parentElement.removeChild(Progress.progress); 452 | 453 | // Remove any background/splash image that was set in runApp(). 454 | // Workaround for Safari bug DEF-3061. 455 | Module.canvas.style.background = ""; 456 | } 457 | } 458 | }; 459 | 460 | /* ********************************************************************* */ 461 | /* Default input override */ 462 | /* ********************************************************************* */ 463 | 464 | var CanvasInput = { 465 | arrowKeysHandler : function(e) { 466 | switch(e.keyCode) { 467 | case 37: case 38: case 39: case 40: // Arrow keys 468 | case 32: e.preventDefault(); e.stopPropagation(); // Space 469 | default: break; // do not block other keys 470 | } 471 | }, 472 | 473 | onFocusIn : function(e) { 474 | window.addEventListener("keydown", CanvasInput.arrowKeysHandler, false); 475 | }, 476 | 477 | onFocusOut: function(e) { 478 | window.removeEventListener("keydown", CanvasInput.arrowKeysHandler, false); 479 | }, 480 | 481 | addToCanvas : function(canvas) { 482 | canvas.addEventListener("focus", CanvasInput.onFocusIn, false); 483 | canvas.addEventListener("blur", CanvasInput.onFocusOut, false); 484 | canvas.focus(); 485 | CanvasInput.onFocusIn(); 486 | } 487 | }; 488 | 489 | /* ********************************************************************* */ 490 | /* Module is Emscripten namespace */ 491 | /* ********************************************************************* */ 492 | 493 | var Module = { 494 | noInitialRun: true, 495 | 496 | _filesToPreload: [], 497 | _archiveLoaded: false, 498 | _preLoadDone: false, 499 | _waitingForArchive: false, 500 | 501 | // Persistent storage 502 | persistentStorage: true, 503 | _syncInProgress: false, 504 | _syncNeeded: false, 505 | _syncInitial: false, 506 | _syncMaxTries: 3, 507 | _syncTries: 0, 508 | 509 | arguments: [], 510 | 511 | print: function(text) { console.log(text); }, 512 | printErr: function(text) { console.error(text); }, 513 | 514 | setStatus: function(text) { console.log(text); }, 515 | 516 | isWASMSupported: (function() { 517 | try { 518 | if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") { 519 | const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)); 520 | if (module instanceof WebAssembly.Module) 521 | return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; 522 | } 523 | } catch (e) { 524 | } 525 | return false; 526 | })(), 527 | 528 | prepareErrorObject: function (err, url, line, column, errObj) { 529 | line = typeof line == "undefined" ? 0 : line; 530 | column = typeof column == "undefined" ? 0 : column; 531 | url = typeof url == "undefined" ? "" : url; 532 | var errorLine = url + ":" + line + ":" + column; 533 | 534 | var error = errObj || (typeof window.event != "undefined" ? window.event.error : "" ) || err || "Undefined Error"; 535 | var message = ""; 536 | var stack = ""; 537 | var backtrace = ""; 538 | 539 | if (typeof error == "object" && typeof error.stack != "undefined" && typeof error.message != "undefined") { 540 | stack = String(error.stack); 541 | message = String(error.message); 542 | } else { 543 | stack = String(error).split("\n"); 544 | message = stack.shift(); 545 | stack = stack.join("\n"); 546 | } 547 | stack = stack || errorLine; 548 | 549 | var callLine = /at (\S+:\d*$)/.exec(message); 550 | if (callLine) { 551 | message = message.replace(/(at \S+:\d*$)/, ""); 552 | stack = callLine[1] + "\n" + stack; 553 | } 554 | 555 | message = message.replace(/(abort\(.+\)) at .+/, "$1"); 556 | stack = stack.replace(/\?{1}\S+(:\d+:\d+)/g, "$1"); 557 | stack = stack.replace(/ *at (\S+)$/gm, "@$1"); 558 | stack = stack.replace(/ *at (\S+)(?: \[as \S+\])? +\((.+)\)/g, "$1@$2"); 559 | stack = stack.replace(/^((?:Object|Array)\.)/gm, ""); 560 | stack = stack.split("\n"); 561 | 562 | return { stack:stack, message:message }; 563 | }, 564 | 565 | hasWebGLSupport: function() { 566 | var webgl_support = false; 567 | try { 568 | var canvas = document.createElement("canvas"); 569 | var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); 570 | if (gl && gl instanceof WebGLRenderingContext) { 571 | webgl_support = true; 572 | } 573 | } catch (error) { 574 | console.log("An error occurred while detecting WebGL support: " + error); 575 | webgl_support = false; 576 | } 577 | 578 | return webgl_support; 579 | }, 580 | 581 | handleVisibilityChange: function () { 582 | GLFW.onFocusChanged(document[Module.hiddenProperty] ? 0 : 1); 583 | }, 584 | 585 | getHiddenProperty: function () { 586 | if ('hidden' in document) return 'hidden'; 587 | var prefixes = ['webkit','moz','ms','o']; 588 | for (var i = 0; i < prefixes.length; i++) { 589 | if ((prefixes[i] + 'Hidden') in document) 590 | return prefixes[i] + 'Hidden'; 591 | } 592 | return null; 593 | }, 594 | 595 | setupVisibilityChangeListener: function() { 596 | Module.hiddenProperty = Module.getHiddenProperty(); 597 | if( Module.hiddenProperty ) { 598 | var eventName = Module.hiddenProperty.replace(/[H|h]idden/,'') + 'visibilitychange'; 599 | document.addEventListener(eventName, Module.handleVisibilityChange, false); 600 | } else { 601 | console.log("No document.hidden property found. The focus events won't be enabled.") 602 | } 603 | }, 604 | 605 | setupCanvas: function(appCanvasId) { 606 | appCanvasId = (typeof appCanvasId === 'undefined') ? 'canvas' : appCanvasId; 607 | Module.canvas = document.getElementById(appCanvasId); 608 | return Module.canvas; 609 | }, 610 | 611 | 612 | /** 613 | * Module.runApp - Starts the application given a canvas element id 614 | * 615 | * 'extra_params' is an optional object that can have the following fields: 616 | * 617 | * 'archive_location_filter': 618 | * Filter function that will run for each archive path. 619 | * 620 | * 'unsupported_webgl_callback': 621 | * Function that is called if WebGL is not supported. 622 | * 623 | * 'engine_arguments': 624 | * List of arguments (strings) that will be passed to the engine. 625 | * 626 | * 'persistent_storage': 627 | * Boolean toggling the usage of persistent storage. 628 | * 629 | * 'custom_heap_size': 630 | * Number of bytes specifying the memory heap size. 631 | * 632 | * 'disable_context_menu': 633 | * Disables the right-click context menu on the canvas element if true. 634 | * 635 | * 'retry_time': 636 | * Pause before retry file loading after error. 637 | * 638 | * 'retry_count': 639 | * How many attempts we do when trying to download a file. 640 | * 641 | * 'can_not_download_file_callback': 642 | * Function that is called if you can't download file after 'retry_count' attempts. 643 | **/ 644 | runApp: function(appCanvasId, extra_params) { 645 | Module.setupCanvas(appCanvasId); 646 | 647 | var params = { 648 | archive_location_filter: function(path) { return 'split' + path; }, 649 | unsupported_webgl_callback: undefined, 650 | engine_arguments: [], 651 | persistent_storage: true, 652 | custom_heap_size: undefined, 653 | disable_context_menu: true, 654 | retry_time: 1, 655 | retry_count: 10, 656 | can_not_download_file_callback: undefined, 657 | }; 658 | 659 | for (var k in extra_params) { 660 | if (extra_params.hasOwnProperty(k)) { 661 | params[k] = extra_params[k]; 662 | } 663 | } 664 | 665 | Module.arguments = params["engine_arguments"]; 666 | Module.persistentStorage = params["persistent_storage"]; 667 | 668 | var fullScreenContainer = params["full_screen_container"]; 669 | if (typeof fullScreenContainer === "string") { 670 | fullScreenContainer = document.querySelector(fullScreenContainer); 671 | } 672 | Module.fullScreenContainer = fullScreenContainer || Module.canvas; 673 | 674 | if (Module.hasWebGLSupport()) { 675 | // Override game keys 676 | CanvasInput.addToCanvas(Module.canvas); 677 | 678 | Module.setupVisibilityChangeListener(); 679 | 680 | // Add context menu hide-handler if requested 681 | if (params["disable_context_menu"]) 682 | { 683 | Module.canvas.oncontextmenu = function(e) { 684 | e.preventDefault(); 685 | }; 686 | } 687 | 688 | FileLoader.options.retryCount = params["retry_count"]; 689 | FileLoader.options.retryInterval = params["retry_time"] * 1000; 690 | if (typeof params["can_not_download_file_callback"] === "function") { 691 | GameArchiveLoader.addFileDownloadErrorListener(params["can_not_download_file_callback"]); 692 | } 693 | // Load and assemble archive 694 | GameArchiveLoader.addFileLoadedListener(Module.onArchiveFileLoaded); 695 | GameArchiveLoader.addArchiveLoadedListener(Module.onArchiveLoaded); 696 | GameArchiveLoader.setFileLocationFilter(params["archive_location_filter"]); 697 | GameArchiveLoader.loadArchiveDescription('/archive_files.json'); 698 | } else { 699 | Progress.updateProgress(100, "Unable to start game, WebGL not supported"); 700 | Module.setStatus = function(text) { 701 | if (text) Module.printErr('[missing WebGL] ' + text); 702 | }; 703 | 704 | if (typeof params["unsupported_webgl_callback"] === "function") { 705 | params["unsupported_webgl_callback"](); 706 | } 707 | } 708 | }, 709 | 710 | onArchiveFileLoaded: function(file) { 711 | Module._filesToPreload.push({path: file.name, data: file.data}); 712 | }, 713 | 714 | onArchiveLoaded: function() { 715 | GameArchiveLoader.cleanUp(); 716 | Module._archiveLoaded = true; 717 | Progress.updateProgress(100, "Starting..."); 718 | 719 | if (Module._waitingForArchive) { 720 | Module._preloadAndCallMain(); 721 | } 722 | }, 723 | 724 | toggleFullscreen: function(element) { 725 | if (GLFW.isFullscreen) { 726 | GLFW.cancelFullScreen(); 727 | } else { 728 | GLFW.requestFullScreen(element); 729 | } 730 | }, 731 | 732 | preSync: function(done) { 733 | // Initial persistent sync before main is called 734 | FS.syncfs(true, function(err) { 735 | if(err) { 736 | Module._syncTries += 1; 737 | console.error("FS syncfs error: " + err); 738 | if (Module._syncMaxTries > Module._syncTries) { 739 | Module.preSync(done); 740 | } else { 741 | Module._syncInitial = true; 742 | done(); 743 | } 744 | } else { 745 | Module._syncInitial = true; 746 | if (done !== undefined) { 747 | done(); 748 | } 749 | } 750 | }); 751 | }, 752 | 753 | preloadAll: function() { 754 | if (Module._preLoadDone) { 755 | return; 756 | } 757 | Module._preLoadDone = true; 758 | for (var i = 0; i < Module._filesToPreload.length; ++i) { 759 | var item = Module._filesToPreload[i]; 760 | FS.createPreloadedFile("", item.path, item.data, true, true); 761 | } 762 | }, 763 | 764 | // Tries to do a MEM->IDB sync 765 | // It will flag that another one is needed if there is already one sync running. 766 | persistentSync: function() { 767 | 768 | // Need to wait for the initial sync to finish since it 769 | // will call close on all its file streams which will trigger 770 | // new persistentSync for each. 771 | if (Module._syncInitial) { 772 | if (Module._syncInProgress) { 773 | Module._syncNeeded = true; 774 | } else { 775 | Module._startSyncFS(); 776 | } 777 | } 778 | }, 779 | 780 | preInit: [function() { 781 | /* Mount filesystem on preinit */ 782 | var dir = DMSYS.GetUserPersistentDataRoot(); 783 | FS.mkdir(dir); 784 | 785 | // If IndexedDB is supported we mount the persistent data root as IDBFS, 786 | // then try to do a IDB->MEM sync before we start the engine to get 787 | // previously saved data before boot. 788 | window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; 789 | if (Module.persistentStorage && window.indexedDB) { 790 | FS.mount(IDBFS, {}, dir); 791 | 792 | // Patch FS.close so it will try to sync MEM->IDB 793 | var _close = FS.close; FS.close = function(stream) { var r = _close(stream); Module.persistentSync(); return r; } 794 | 795 | // Sync IDB->MEM before calling main() 796 | Module.preSync(function() { 797 | Module._preloadAndCallMain(); 798 | }); 799 | } else { 800 | Module._preloadAndCallMain(); 801 | } 802 | }], 803 | 804 | preRun: [function() { 805 | /* If archive is loaded, preload all its files */ 806 | if(Module._archiveLoaded) { 807 | Module.preloadAll(); 808 | } 809 | }], 810 | 811 | postRun: [function() { 812 | if(Module._archiveLoaded) { 813 | Progress.removeProgress(); 814 | } 815 | }], 816 | 817 | _preloadAndCallMain: function() { 818 | // If the archive isn't loaded, 819 | // we will have to wait with calling main. 820 | if (!Module._archiveLoaded) { 821 | Module._waitingForArchive = true; 822 | } else { 823 | Module.preloadAll(); 824 | Progress.removeProgress(); 825 | if (Module.callMain === undefined) { 826 | Module.noInitialRun = false; 827 | } else { 828 | Module.callMain(Module.arguments); 829 | } 830 | } 831 | }, 832 | 833 | // Wrap IDBFS syncfs call with logic to avoid multiple syncs 834 | // running at the same time. 835 | _startSyncFS: function() { 836 | Module._syncInProgress = true; 837 | 838 | if (Module._syncMaxTries > Module._syncTries) { 839 | FS.syncfs(false, function(err) { 840 | Module._syncInProgress = false; 841 | 842 | if (err) { 843 | console.error("Module._startSyncFS error: " + err); 844 | Module._syncTries += 1; 845 | } 846 | 847 | if (Module._syncNeeded) { 848 | Module._syncNeeded = false; 849 | Module._startSyncFS(); 850 | } 851 | 852 | }); 853 | } 854 | }, 855 | }; 856 | 857 | window.onerror = function(err, url, line, column, errObj) { 858 | if (typeof Module.ccall !== 'undefined') { 859 | var errorObject = Module.prepareErrorObject(err, url, line, column, errObj); 860 | Module.ccall('JSWriteDump', 'null', ['string'], [JSON.stringify(errorObject.stack)]); 861 | } 862 | Module.setStatus('Exception thrown, see JavaScript console'); 863 | Module.setStatus = function(text) { 864 | if (text) Module.printErr('[post-exception status] ' + text); 865 | }; 866 | }; 867 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | PixelLinePlatformer 1.0 11 | 145 | 146 | 147 | 148 |
149 |
150 | 151 |
152 |
153 |
Fullscreen
154 | 155 |
156 |
157 | 158 | 159 | 160 | 247 | 248 | 251 | 252 | 253 | -------------------------------------------------------------------------------- /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/sample-pixel-line-platformer/298586942f592c2f6219d016fc904e841b79df9f/docs/screenshot.png -------------------------------------------------------------------------------- /game.project: -------------------------------------------------------------------------------- 1 | [project] 2 | title = PixelLinePlatformer 3 | 4 | [bootstrap] 5 | main_collection = /game/game.collectionc 6 | 7 | [input] 8 | game_binding = /input/game.input_bindingc 9 | use_accelerometer = 0 10 | 11 | [display] 12 | width = 960 13 | height = 640 14 | vsync = 0 15 | update_frequency = 60 16 | 17 | [ios] 18 | app_icon_120x120 = /assets/app_icons/icon_120.png 19 | app_icon_180x180 = /assets/app_icons/icon_180.png 20 | app_icon_76x76 = /assets/app_icons/icon_76.png 21 | app_icon_152x152 = /assets/app_icons/icon_152.png 22 | app_icon_57x57 = /assets/app_icons/icon_57.png 23 | app_icon_114x114 = /assets/app_icons/icon_114.png 24 | app_icon_72x72 = /assets/app_icons/icon_72.png 25 | app_icon_144x144 = /assets/app_icons/icon_144.png 26 | app_icon_167x167 = /assets/app_icons/icon_167.png 27 | bundle_identifier = com.example.todo 28 | 29 | [osx] 30 | bundle_identifier = com.example.todo 31 | 32 | [android] 33 | app_icon_36x36 = /assets/app_icons/icon_36.png 34 | app_icon_48x48 = /assets/app_icons/icon_48.png 35 | app_icon_72x72 = /assets/app_icons/icon_72.png 36 | app_icon_96x96 = /assets/app_icons/icon_96.png 37 | app_icon_144x144 = /assets/app_icons/icon_144.png 38 | app_icon_192x192 = /assets/app_icons/icon_192.png 39 | input_method = HiddenInputField 40 | 41 | [script] 42 | shared_state = 1 43 | 44 | [physics] 45 | gravity_y = -1000.0 46 | scale = 0.1 47 | use_fixed_timestep = 1 48 | 49 | [graphics] 50 | default_texture_min_filter = nearest 51 | default_texture_mag_filter = nearest 52 | 53 | [sprite] 54 | max_count = 500 55 | 56 | -------------------------------------------------------------------------------- /game/bee.go: -------------------------------------------------------------------------------- 1 | components { 2 | id: "bee" 3 | component: "/game/bee.script" 4 | position { 5 | x: 0.0 6 | y: 0.0 7 | z: 0.0 8 | } 9 | rotation { 10 | x: 0.0 11 | y: 0.0 12 | z: 0.0 13 | w: 1.0 14 | } 15 | } 16 | embedded_components { 17 | id: "sprite" 18 | type: "sprite" 19 | data: "tile_set: \"/assets/game.tilesource\"\n" 20 | "default_animation: \"bee\"\n" 21 | "material: \"/builtins/materials/sprite.material\"\n" 22 | "blend_mode: BLEND_MODE_ALPHA\n" 23 | "" 24 | position { 25 | x: 0.0 26 | y: 0.0 27 | z: 0.0 28 | } 29 | rotation { 30 | x: 0.0 31 | y: 0.0 32 | z: 0.0 33 | w: 1.0 34 | } 35 | } 36 | embedded_components { 37 | id: "collisionobject" 38 | type: "collisionobject" 39 | data: "collision_shape: \"\"\n" 40 | "type: COLLISION_OBJECT_TYPE_KINEMATIC\n" 41 | "mass: 0.0\n" 42 | "friction: 0.1\n" 43 | "restitution: 0.5\n" 44 | "group: \"enemy\"\n" 45 | "mask: \"player\"\n" 46 | "mask: \"bullet\"\n" 47 | "embedded_collision_shape {\n" 48 | " shapes {\n" 49 | " shape_type: TYPE_SPHERE\n" 50 | " position {\n" 51 | " x: 0.0\n" 52 | " y: 0.0\n" 53 | " z: 0.0\n" 54 | " }\n" 55 | " rotation {\n" 56 | " x: 0.0\n" 57 | " y: 0.0\n" 58 | " z: 0.0\n" 59 | " w: 1.0\n" 60 | " }\n" 61 | " index: 0\n" 62 | " count: 1\n" 63 | " }\n" 64 | " data: 6.0\n" 65 | "}\n" 66 | "linear_damping: 0.0\n" 67 | "angular_damping: 0.0\n" 68 | "locked_rotation: false\n" 69 | "bullet: false\n" 70 | "" 71 | position { 72 | x: 0.0 73 | y: 0.0 74 | z: 0.0 75 | } 76 | rotation { 77 | x: 0.0 78 | y: 0.0 79 | z: 0.0 80 | w: 1.0 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /game/bee.script: -------------------------------------------------------------------------------- 1 | go.property("distance", 50) 2 | 3 | local SPEED = 10 4 | local DEAD_SPEED = 200 5 | 6 | local COLLISION_RESPONSE = hash("collision_response") 7 | local BULLET = hash("bullet") 8 | 9 | function init(self) 10 | -- move up and down 11 | local pos = go.get_position() 12 | local to = pos.y + self.distance 13 | local duration = self.distance / SPEED 14 | go.animate(".", "position.y", go.PLAYBACK_LOOP_PINGPONG, to, go.EASING_INOUTQUAD, duration) 15 | 16 | -- flip sprite 17 | local flip = false 18 | timer.delay(duration / 2, true, function() 19 | flip = not flip 20 | sprite.set_hflip("#sprite", flip) 21 | end) 22 | end 23 | 24 | function on_message(self, message_id, message, sender) 25 | if self.dead then return end 26 | if message_id == COLLISION_RESPONSE then 27 | if message.other_group == BULLET then 28 | -- remove the bullet that hit the bee 29 | go.delete(message.other_id) 30 | 31 | -- turn the bee upside down and make it drop dead! 32 | -- also flag it as dead and ignore any additional messages 33 | self.dead = true 34 | sprite.set_vflip("#sprite", true) 35 | local pos = go.get_position() 36 | local duration = pos.y / DEAD_SPEED 37 | go.cancel_animations(".", "position.y") 38 | go.animate(".", "position.y", go.PLAYBACK_ONCE_FORWARD, 0, go.EASING_INQUAD, duration, 0, function() 39 | go.delete() 40 | end) 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /game/bluebee.go: -------------------------------------------------------------------------------- 1 | components { 2 | id: "bluebee" 3 | component: "/game/bluebee.script" 4 | position { 5 | x: 0.0 6 | y: 0.0 7 | z: 0.0 8 | } 9 | rotation { 10 | x: 0.0 11 | y: 0.0 12 | z: 0.0 13 | w: 1.0 14 | } 15 | } 16 | embedded_components { 17 | id: "sprite" 18 | type: "sprite" 19 | data: "tile_set: \"/assets/game.tilesource\"\n" 20 | "default_animation: \"bluebee\"\n" 21 | "material: \"/builtins/materials/sprite.material\"\n" 22 | "blend_mode: BLEND_MODE_ALPHA\n" 23 | "" 24 | position { 25 | x: 0.0 26 | y: 0.0 27 | z: 0.0 28 | } 29 | rotation { 30 | x: 0.0 31 | y: 0.0 32 | z: 0.0 33 | w: 1.0 34 | } 35 | } 36 | embedded_components { 37 | id: "collisionobject" 38 | type: "collisionobject" 39 | data: "collision_shape: \"\"\n" 40 | "type: COLLISION_OBJECT_TYPE_KINEMATIC\n" 41 | "mass: 0.0\n" 42 | "friction: 0.1\n" 43 | "restitution: 0.5\n" 44 | "group: \"enemy\"\n" 45 | "mask: \"player\"\n" 46 | "mask: \"bullet\"\n" 47 | "embedded_collision_shape {\n" 48 | " shapes {\n" 49 | " shape_type: TYPE_SPHERE\n" 50 | " position {\n" 51 | " x: 0.0\n" 52 | " y: 0.0\n" 53 | " z: 0.0\n" 54 | " }\n" 55 | " rotation {\n" 56 | " x: 0.0\n" 57 | " y: 0.0\n" 58 | " z: 0.0\n" 59 | " w: 1.0\n" 60 | " }\n" 61 | " index: 0\n" 62 | " count: 1\n" 63 | " }\n" 64 | " data: 6.0\n" 65 | "}\n" 66 | "linear_damping: 0.0\n" 67 | "angular_damping: 0.0\n" 68 | "locked_rotation: false\n" 69 | "bullet: false\n" 70 | "" 71 | position { 72 | x: 0.0 73 | y: 0.0 74 | z: 0.0 75 | } 76 | rotation { 77 | x: 0.0 78 | y: 0.0 79 | z: 0.0 80 | w: 1.0 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /game/bluebee.script: -------------------------------------------------------------------------------- 1 | go.property("distance", 50) 2 | 3 | local SPEED = 10 4 | local DEAD_SPEED = 200 5 | 6 | local COLLISION_RESPONSE = hash("collision_response") 7 | local BULLET = hash("bullet") 8 | 9 | function init(self) 10 | -- move back and forth 11 | -- bob up and down 12 | local pos = go.get_position() 13 | local to = pos.x + self.distance 14 | local duration = self.distance / SPEED 15 | go.animate(".", "position.y", go.PLAYBACK_LOOP_PINGPONG, pos.y + 2, go.EASING_INOUTQUAD, 0.5) 16 | go.animate(".", "position.x", go.PLAYBACK_LOOP_PINGPONG, to, go.EASING_LINEAR, duration) 17 | 18 | -- flip sprite 19 | local flip = false 20 | timer.delay(duration / 2, true, function() 21 | flip = not flip 22 | sprite.set_hflip("#sprite", flip) 23 | end) 24 | end 25 | 26 | function on_message(self, message_id, message, sender) 27 | if self.dead then return end 28 | if message_id == COLLISION_RESPONSE then 29 | if message.other_group == BULLET then 30 | -- remove the bullet 31 | go.delete(message.other_id) 32 | 33 | -- turn upside down and make it drop dead! 34 | -- also flag it as dead and ignore any additional messages 35 | self.dead = true 36 | sprite.set_vflip("#sprite", true) 37 | local pos = go.get_position() 38 | local duration = pos.y / DEAD_SPEED 39 | go.cancel_animations(".", "position.x") 40 | go.animate(".", "position.y", go.PLAYBACK_ONCE_FORWARD, 0, go.EASING_INQUAD, duration, 0, function() 41 | go.delete() 42 | end) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /game/bullet.go: -------------------------------------------------------------------------------- 1 | embedded_components { 2 | id: "sprite" 3 | type: "sprite" 4 | data: "tile_set: \"/assets/game.tilesource\"\n" 5 | "default_animation: \"bullet\"\n" 6 | "material: \"/builtins/materials/sprite.material\"\n" 7 | "blend_mode: BLEND_MODE_ALPHA\n" 8 | "" 9 | position { 10 | x: 0.0 11 | y: 0.0 12 | z: 0.0 13 | } 14 | rotation { 15 | x: 0.0 16 | y: 0.0 17 | z: 0.0 18 | w: 1.0 19 | } 20 | } 21 | embedded_components { 22 | id: "collisionobject" 23 | type: "collisionobject" 24 | data: "collision_shape: \"\"\n" 25 | "type: COLLISION_OBJECT_TYPE_KINEMATIC\n" 26 | "mass: 0.0\n" 27 | "friction: 0.1\n" 28 | "restitution: 0.5\n" 29 | "group: \"bullet\"\n" 30 | "mask: \"enemy\"\n" 31 | "embedded_collision_shape {\n" 32 | " shapes {\n" 33 | " shape_type: TYPE_BOX\n" 34 | " position {\n" 35 | " x: 0.0\n" 36 | " y: 0.0\n" 37 | " z: 0.0\n" 38 | " }\n" 39 | " rotation {\n" 40 | " x: 0.0\n" 41 | " y: 0.0\n" 42 | " z: 0.0\n" 43 | " w: 1.0\n" 44 | " }\n" 45 | " index: 0\n" 46 | " count: 3\n" 47 | " }\n" 48 | " data: 6.0\n" 49 | " data: 1.0\n" 50 | " data: 10.0\n" 51 | "}\n" 52 | "linear_damping: 0.0\n" 53 | "angular_damping: 0.0\n" 54 | "locked_rotation: false\n" 55 | "bullet: false\n" 56 | "" 57 | position { 58 | x: 0.0 59 | y: 0.0 60 | z: 0.0 61 | } 62 | rotation { 63 | x: 0.0 64 | y: 0.0 65 | z: 0.0 66 | w: 1.0 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /game/dust.particlefx: -------------------------------------------------------------------------------- 1 | emitters { 2 | id: "left" 3 | mode: PLAY_MODE_ONCE 4 | duration: 0.2 5 | space: EMISSION_SPACE_WORLD 6 | position { 7 | x: 0.0 8 | y: 0.0 9 | z: 0.0 10 | } 11 | rotation { 12 | x: 0.0 13 | y: 0.0 14 | z: 0.70710677 15 | w: 0.70710677 16 | } 17 | tile_source: "/builtins/graphics/particle_blob.tilesource" 18 | animation: "anim" 19 | material: "/builtins/materials/particlefx.material" 20 | blend_mode: BLEND_MODE_ADD 21 | particle_orientation: PARTICLE_ORIENTATION_DEFAULT 22 | inherit_velocity: 0.0 23 | max_particle_count: 2 24 | type: EMITTER_TYPE_2DCONE 25 | start_delay: 0.0 26 | properties { 27 | key: EMITTER_KEY_SPAWN_RATE 28 | points { 29 | x: 0.0 30 | y: 30.0 31 | t_x: 1.0 32 | t_y: 0.0 33 | } 34 | spread: 20.0 35 | } 36 | properties { 37 | key: EMITTER_KEY_SIZE_X 38 | points { 39 | x: 0.0 40 | y: 7.0 41 | t_x: 1.0 42 | t_y: 0.0 43 | } 44 | spread: 0.0 45 | } 46 | properties { 47 | key: EMITTER_KEY_SIZE_Y 48 | points { 49 | x: 0.0 50 | y: 7.0 51 | t_x: 1.0 52 | t_y: 0.0 53 | } 54 | spread: 0.0 55 | } 56 | properties { 57 | key: EMITTER_KEY_SIZE_Z 58 | points { 59 | x: 0.0 60 | y: 0.0 61 | t_x: 1.0 62 | t_y: 0.0 63 | } 64 | spread: 0.0 65 | } 66 | properties { 67 | key: EMITTER_KEY_PARTICLE_LIFE_TIME 68 | points { 69 | x: 0.0 70 | y: 1.0 71 | t_x: 1.0 72 | t_y: 0.0 73 | } 74 | spread: 0.5 75 | } 76 | properties { 77 | key: EMITTER_KEY_PARTICLE_SPEED 78 | points { 79 | x: 0.0 80 | y: 3.0 81 | t_x: 1.0 82 | t_y: 0.0 83 | } 84 | spread: 1.0 85 | } 86 | properties { 87 | key: EMITTER_KEY_PARTICLE_SIZE 88 | points { 89 | x: 0.0 90 | y: 2.0 91 | t_x: 1.0 92 | t_y: 0.0 93 | } 94 | spread: 1.0 95 | } 96 | properties { 97 | key: EMITTER_KEY_PARTICLE_RED 98 | points { 99 | x: 0.0 100 | y: 1.0 101 | t_x: 1.0 102 | t_y: 0.0 103 | } 104 | spread: 0.0 105 | } 106 | properties { 107 | key: EMITTER_KEY_PARTICLE_GREEN 108 | points { 109 | x: 0.0 110 | y: 1.0 111 | t_x: 1.0 112 | t_y: 0.0 113 | } 114 | spread: 0.0 115 | } 116 | properties { 117 | key: EMITTER_KEY_PARTICLE_BLUE 118 | points { 119 | x: 0.0 120 | y: 1.0 121 | t_x: 1.0 122 | t_y: 0.0 123 | } 124 | spread: 0.0 125 | } 126 | properties { 127 | key: EMITTER_KEY_PARTICLE_ALPHA 128 | points { 129 | x: 0.0 130 | y: 1.0 131 | t_x: 1.0 132 | t_y: 0.0 133 | } 134 | spread: 0.0 135 | } 136 | properties { 137 | key: EMITTER_KEY_PARTICLE_ROTATION 138 | points { 139 | x: 0.0 140 | y: 0.0 141 | t_x: 1.0 142 | t_y: 0.0 143 | } 144 | spread: 0.0 145 | } 146 | properties { 147 | key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X 148 | points { 149 | x: 0.0 150 | y: 0.0 151 | t_x: 1.0 152 | t_y: 0.0 153 | } 154 | spread: 0.0 155 | } 156 | properties { 157 | key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y 158 | points { 159 | x: 0.0 160 | y: 0.0 161 | t_x: 1.0 162 | t_y: 0.0 163 | } 164 | spread: 0.0 165 | } 166 | properties { 167 | key: EMITTER_KEY_PARTICLE_ANGULAR_VELOCITY 168 | points { 169 | x: 0.0 170 | y: 0.0 171 | t_x: 1.0 172 | t_y: 0.0 173 | } 174 | spread: 0.0 175 | } 176 | particle_properties { 177 | key: PARTICLE_KEY_SCALE 178 | points { 179 | x: 0.0 180 | y: 0.47391304 181 | t_x: 0.12695746 182 | t_y: 0.99190813 183 | } 184 | points { 185 | x: 1.0 186 | y: 2.0 187 | t_x: 1.0 188 | t_y: 0.0 189 | } 190 | } 191 | particle_properties { 192 | key: PARTICLE_KEY_RED 193 | points { 194 | x: 0.0 195 | y: 1.0 196 | t_x: 1.0 197 | t_y: 0.0 198 | } 199 | } 200 | particle_properties { 201 | key: PARTICLE_KEY_GREEN 202 | points { 203 | x: 0.0 204 | y: 1.0 205 | t_x: 1.0 206 | t_y: 0.0 207 | } 208 | } 209 | particle_properties { 210 | key: PARTICLE_KEY_BLUE 211 | points { 212 | x: 0.0 213 | y: 1.0 214 | t_x: 1.0 215 | t_y: 0.0 216 | } 217 | } 218 | particle_properties { 219 | key: PARTICLE_KEY_ALPHA 220 | points { 221 | x: 0.0 222 | y: 0.0 223 | t_x: 0.07194582 224 | t_y: 0.99740857 225 | } 226 | points { 227 | x: 0.11320755 228 | y: 0.99277455 229 | t_x: 0.99418455 230 | t_y: 0.10768964 231 | } 232 | points { 233 | x: 0.7112546 234 | y: 0.555656 235 | t_x: 0.5694311 236 | t_y: -0.82203907 237 | } 238 | points { 239 | x: 1.0 240 | y: 0.0072254334 241 | t_x: 0.4737472 242 | t_y: -0.8806609 243 | } 244 | } 245 | particle_properties { 246 | key: PARTICLE_KEY_ROTATION 247 | points { 248 | x: 0.0 249 | y: 0.0 250 | t_x: 1.0 251 | t_y: 0.0 252 | } 253 | } 254 | particle_properties { 255 | key: PARTICLE_KEY_STRETCH_FACTOR_X 256 | points { 257 | x: 0.0 258 | y: 0.0 259 | t_x: 1.0 260 | t_y: 0.0 261 | } 262 | } 263 | particle_properties { 264 | key: PARTICLE_KEY_STRETCH_FACTOR_Y 265 | points { 266 | x: 0.0 267 | y: 0.0 268 | t_x: 1.0 269 | t_y: 0.0 270 | } 271 | } 272 | particle_properties { 273 | key: PARTICLE_KEY_ANGULAR_VELOCITY 274 | points { 275 | x: 0.0 276 | y: 1.0 277 | t_x: 1.0 278 | t_y: 0.0 279 | } 280 | } 281 | size_mode: SIZE_MODE_MANUAL 282 | start_delay_spread: 0.0 283 | duration_spread: 0.0 284 | stretch_with_velocity: false 285 | start_offset: 0.0 286 | } 287 | emitters { 288 | id: "right" 289 | mode: PLAY_MODE_ONCE 290 | duration: 0.2 291 | space: EMISSION_SPACE_WORLD 292 | position { 293 | x: 0.0 294 | y: 0.0 295 | z: 0.0 296 | } 297 | rotation { 298 | x: 0.0 299 | y: 0.0 300 | z: -0.70710677 301 | w: 0.70710677 302 | } 303 | tile_source: "/builtins/graphics/particle_blob.tilesource" 304 | animation: "anim" 305 | material: "/builtins/materials/particlefx.material" 306 | blend_mode: BLEND_MODE_ADD 307 | particle_orientation: PARTICLE_ORIENTATION_DEFAULT 308 | inherit_velocity: 0.0 309 | max_particle_count: 2 310 | type: EMITTER_TYPE_2DCONE 311 | start_delay: 0.0 312 | properties { 313 | key: EMITTER_KEY_SPAWN_RATE 314 | points { 315 | x: 0.0 316 | y: 30.0 317 | t_x: 1.0 318 | t_y: 0.0 319 | } 320 | spread: 20.0 321 | } 322 | properties { 323 | key: EMITTER_KEY_SIZE_X 324 | points { 325 | x: 0.0 326 | y: 7.0 327 | t_x: 1.0 328 | t_y: 0.0 329 | } 330 | spread: 0.0 331 | } 332 | properties { 333 | key: EMITTER_KEY_SIZE_Y 334 | points { 335 | x: 0.0 336 | y: 7.0 337 | t_x: 1.0 338 | t_y: 0.0 339 | } 340 | spread: 0.0 341 | } 342 | properties { 343 | key: EMITTER_KEY_SIZE_Z 344 | points { 345 | x: 0.0 346 | y: 0.0 347 | t_x: 1.0 348 | t_y: 0.0 349 | } 350 | spread: 0.0 351 | } 352 | properties { 353 | key: EMITTER_KEY_PARTICLE_LIFE_TIME 354 | points { 355 | x: 0.0 356 | y: 1.0 357 | t_x: 1.0 358 | t_y: 0.0 359 | } 360 | spread: 0.5 361 | } 362 | properties { 363 | key: EMITTER_KEY_PARTICLE_SPEED 364 | points { 365 | x: 0.0 366 | y: 3.0 367 | t_x: 1.0 368 | t_y: 0.0 369 | } 370 | spread: 1.0 371 | } 372 | properties { 373 | key: EMITTER_KEY_PARTICLE_SIZE 374 | points { 375 | x: 0.0 376 | y: 2.0 377 | t_x: 1.0 378 | t_y: 0.0 379 | } 380 | spread: 1.0 381 | } 382 | properties { 383 | key: EMITTER_KEY_PARTICLE_RED 384 | points { 385 | x: 0.0 386 | y: 1.0 387 | t_x: 1.0 388 | t_y: 0.0 389 | } 390 | spread: 0.0 391 | } 392 | properties { 393 | key: EMITTER_KEY_PARTICLE_GREEN 394 | points { 395 | x: 0.0 396 | y: 1.0 397 | t_x: 1.0 398 | t_y: 0.0 399 | } 400 | spread: 0.0 401 | } 402 | properties { 403 | key: EMITTER_KEY_PARTICLE_BLUE 404 | points { 405 | x: 0.0 406 | y: 1.0 407 | t_x: 1.0 408 | t_y: 0.0 409 | } 410 | spread: 0.0 411 | } 412 | properties { 413 | key: EMITTER_KEY_PARTICLE_ALPHA 414 | points { 415 | x: 0.0 416 | y: 1.0 417 | t_x: 1.0 418 | t_y: 0.0 419 | } 420 | spread: 0.0 421 | } 422 | properties { 423 | key: EMITTER_KEY_PARTICLE_ROTATION 424 | points { 425 | x: 0.0 426 | y: 0.0 427 | t_x: 1.0 428 | t_y: 0.0 429 | } 430 | spread: 0.0 431 | } 432 | properties { 433 | key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X 434 | points { 435 | x: 0.0 436 | y: 0.0 437 | t_x: 1.0 438 | t_y: 0.0 439 | } 440 | spread: 0.0 441 | } 442 | properties { 443 | key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y 444 | points { 445 | x: 0.0 446 | y: 0.0 447 | t_x: 1.0 448 | t_y: 0.0 449 | } 450 | spread: 0.0 451 | } 452 | properties { 453 | key: EMITTER_KEY_PARTICLE_ANGULAR_VELOCITY 454 | points { 455 | x: 0.0 456 | y: 0.0 457 | t_x: 1.0 458 | t_y: 0.0 459 | } 460 | spread: 0.0 461 | } 462 | particle_properties { 463 | key: PARTICLE_KEY_SCALE 464 | points { 465 | x: 0.0 466 | y: 0.47391304 467 | t_x: 0.12695746 468 | t_y: 0.99190813 469 | } 470 | points { 471 | x: 1.0 472 | y: 2.0 473 | t_x: 1.0 474 | t_y: 0.0 475 | } 476 | } 477 | particle_properties { 478 | key: PARTICLE_KEY_RED 479 | points { 480 | x: 0.0 481 | y: 1.0 482 | t_x: 1.0 483 | t_y: 0.0 484 | } 485 | } 486 | particle_properties { 487 | key: PARTICLE_KEY_GREEN 488 | points { 489 | x: 0.0 490 | y: 1.0 491 | t_x: 1.0 492 | t_y: 0.0 493 | } 494 | } 495 | particle_properties { 496 | key: PARTICLE_KEY_BLUE 497 | points { 498 | x: 0.0 499 | y: 1.0 500 | t_x: 1.0 501 | t_y: 0.0 502 | } 503 | } 504 | particle_properties { 505 | key: PARTICLE_KEY_ALPHA 506 | points { 507 | x: 0.0 508 | y: 0.0 509 | t_x: 0.07194582 510 | t_y: 0.99740857 511 | } 512 | points { 513 | x: 0.11320755 514 | y: 0.99277455 515 | t_x: 0.99418455 516 | t_y: 0.10768964 517 | } 518 | points { 519 | x: 0.7112546 520 | y: 0.555656 521 | t_x: 0.5694311 522 | t_y: -0.82203907 523 | } 524 | points { 525 | x: 1.0 526 | y: 0.0072254334 527 | t_x: 0.4737472 528 | t_y: -0.8806609 529 | } 530 | } 531 | particle_properties { 532 | key: PARTICLE_KEY_ROTATION 533 | points { 534 | x: 0.0 535 | y: 0.0 536 | t_x: 1.0 537 | t_y: 0.0 538 | } 539 | } 540 | particle_properties { 541 | key: PARTICLE_KEY_STRETCH_FACTOR_X 542 | points { 543 | x: 0.0 544 | y: 0.0 545 | t_x: 1.0 546 | t_y: 0.0 547 | } 548 | } 549 | particle_properties { 550 | key: PARTICLE_KEY_STRETCH_FACTOR_Y 551 | points { 552 | x: 0.0 553 | y: 0.0 554 | t_x: 1.0 555 | t_y: 0.0 556 | } 557 | } 558 | particle_properties { 559 | key: PARTICLE_KEY_ANGULAR_VELOCITY 560 | points { 561 | x: 0.0 562 | y: 1.0 563 | t_x: 1.0 564 | t_y: 0.0 565 | } 566 | } 567 | size_mode: SIZE_MODE_MANUAL 568 | start_delay_spread: 0.0 569 | duration_spread: 0.0 570 | stretch_with_velocity: false 571 | start_offset: 0.0 572 | } 573 | modifiers { 574 | type: MODIFIER_TYPE_ACCELERATION 575 | use_direction: 0 576 | position { 577 | x: 0.0 578 | y: 0.0 579 | z: 0.0 580 | } 581 | rotation { 582 | x: 0.0 583 | y: 0.0 584 | z: 0.0 585 | w: 1.0 586 | } 587 | properties { 588 | key: MODIFIER_KEY_MAGNITUDE 589 | points { 590 | x: 0.0 591 | y: -10.0 592 | t_x: 1.0 593 | t_y: 0.0 594 | } 595 | spread: 0.0 596 | } 597 | } 598 | -------------------------------------------------------------------------------- /game/game.collection: -------------------------------------------------------------------------------- 1 | name: "game" 2 | instances { 3 | id: "bee2" 4 | prototype: "/game/bee.go" 5 | position { 6 | x: 301.0 7 | y: 174.0 8 | z: 0.0 9 | } 10 | rotation { 11 | x: 0.0 12 | y: 0.0 13 | z: 0.0 14 | w: 1.0 15 | } 16 | scale3 { 17 | x: 1.0 18 | y: 1.0 19 | z: 1.0 20 | } 21 | } 22 | instances { 23 | id: "bee1" 24 | prototype: "/game/bee.go" 25 | position { 26 | x: 542.0 27 | y: 301.0 28 | z: 0.0 29 | } 30 | rotation { 31 | x: 0.0 32 | y: 0.0 33 | z: 0.0 34 | w: 1.0 35 | } 36 | scale3 { 37 | x: 1.0 38 | y: 1.0 39 | z: 1.0 40 | } 41 | } 42 | instances { 43 | id: "slime" 44 | prototype: "/game/slime.go" 45 | position { 46 | x: 792.0 47 | y: 291.0 48 | z: 0.0 49 | } 50 | rotation { 51 | x: 0.0 52 | y: 0.0 53 | z: 0.0 54 | w: 1.0 55 | } 56 | scale3 { 57 | x: 1.0 58 | y: 1.0 59 | z: 1.0 60 | } 61 | } 62 | instances { 63 | id: "slime1" 64 | prototype: "/game/slime.go" 65 | position { 66 | x: -8.0 67 | y: 211.0 68 | z: 0.0 69 | } 70 | rotation { 71 | x: 0.0 72 | y: 0.0 73 | z: 0.0 74 | w: 1.0 75 | } 76 | scale3 { 77 | x: 1.0 78 | y: 1.0 79 | z: 1.0 80 | } 81 | } 82 | instances { 83 | id: "slime3" 84 | prototype: "/game/slime.go" 85 | position { 86 | x: 585.0 87 | y: 227.0 88 | z: 0.0 89 | } 90 | rotation { 91 | x: 0.0 92 | y: 0.0 93 | z: 0.0 94 | w: 1.0 95 | } 96 | scale3 { 97 | x: 1.0 98 | y: 1.0 99 | z: 1.0 100 | } 101 | } 102 | instances { 103 | id: "bluebee2" 104 | prototype: "/game/bluebee.go" 105 | position { 106 | x: 329.0 107 | y: 281.0 108 | z: 0.0 109 | } 110 | rotation { 111 | x: 0.0 112 | y: 0.0 113 | z: 0.0 114 | w: 1.0 115 | } 116 | component_properties { 117 | id: "bluebee" 118 | properties { 119 | id: "distance" 120 | value: "120.0" 121 | type: PROPERTY_TYPE_NUMBER 122 | } 123 | } 124 | scale3 { 125 | x: 1.0 126 | y: 1.0 127 | z: 1.0 128 | } 129 | } 130 | instances { 131 | id: "bluebee1" 132 | prototype: "/game/bluebee.go" 133 | position { 134 | x: 602.0 135 | y: 328.0 136 | z: 0.0 137 | } 138 | rotation { 139 | x: 0.0 140 | y: 0.0 141 | z: 0.0 142 | w: 1.0 143 | } 144 | component_properties { 145 | id: "bluebee" 146 | properties { 147 | id: "distance" 148 | value: "145.0" 149 | type: PROPERTY_TYPE_NUMBER 150 | } 151 | } 152 | scale3 { 153 | x: 1.0 154 | y: 1.0 155 | z: 1.0 156 | } 157 | } 158 | instances { 159 | id: "bluebee3" 160 | prototype: "/game/bluebee.go" 161 | position { 162 | x: 492.0 163 | y: 269.0 164 | z: 0.0 165 | } 166 | rotation { 167 | x: 0.0 168 | y: 0.0 169 | z: 0.0 170 | w: 1.0 171 | } 172 | component_properties { 173 | id: "bluebee" 174 | properties { 175 | id: "distance" 176 | value: "120.0" 177 | type: PROPERTY_TYPE_NUMBER 178 | } 179 | } 180 | scale3 { 181 | x: 1.0 182 | y: 1.0 183 | z: 1.0 184 | } 185 | } 186 | collection_instances { 187 | id: "player" 188 | collection: "/game/player.collection" 189 | position { 190 | x: 256.0 191 | y: 165.0 192 | z: 1.0 193 | } 194 | rotation { 195 | x: 0.0 196 | y: 0.0 197 | z: 0.0 198 | w: 1.0 199 | } 200 | scale3 { 201 | x: 1.0 202 | y: 1.0 203 | z: 1.0 204 | } 205 | } 206 | scale_along_z: 0 207 | embedded_instances { 208 | id: "level" 209 | data: "components {\n" 210 | " id: \"level\"\n" 211 | " component: \"/game/level.tilemap\"\n" 212 | " position {\n" 213 | " x: 0.0\n" 214 | " y: 0.0\n" 215 | " z: 0.0\n" 216 | " }\n" 217 | " rotation {\n" 218 | " x: 0.0\n" 219 | " y: 0.0\n" 220 | " z: 0.0\n" 221 | " w: 1.0\n" 222 | " }\n" 223 | " property_decls {\n" 224 | " }\n" 225 | "}\n" 226 | "components {\n" 227 | " id: \"script\"\n" 228 | " component: \"/game/level.script\"\n" 229 | " position {\n" 230 | " x: 0.0\n" 231 | " y: 0.0\n" 232 | " z: 0.0\n" 233 | " }\n" 234 | " rotation {\n" 235 | " x: 0.0\n" 236 | " y: 0.0\n" 237 | " z: 0.0\n" 238 | " w: 1.0\n" 239 | " }\n" 240 | " property_decls {\n" 241 | " }\n" 242 | "}\n" 243 | "embedded_components {\n" 244 | " id: \"collisionobject\"\n" 245 | " type: \"collisionobject\"\n" 246 | " data: \"collision_shape: \\\"/game/level.tilemap\\\"\\n" 247 | "type: COLLISION_OBJECT_TYPE_STATIC\\n" 248 | "mass: 0.0\\n" 249 | "friction: 0.1\\n" 250 | "restitution: 0.5\\n" 251 | "group: \\\"\\\"\\n" 252 | "mask: \\\"player\\\"\\n" 253 | "linear_damping: 0.0\\n" 254 | "angular_damping: 0.0\\n" 255 | "locked_rotation: false\\n" 256 | "bullet: false\\n" 257 | "\"\n" 258 | " position {\n" 259 | " x: 0.0\n" 260 | " y: 0.0\n" 261 | " z: 0.0\n" 262 | " }\n" 263 | " rotation {\n" 264 | " x: 0.0\n" 265 | " y: 0.0\n" 266 | " z: 0.0\n" 267 | " w: 1.0\n" 268 | " }\n" 269 | "}\n" 270 | "embedded_components {\n" 271 | " id: \"respawn\"\n" 272 | " type: \"collisionobject\"\n" 273 | " data: \"collision_shape: \\\"\\\"\\n" 274 | "type: COLLISION_OBJECT_TYPE_STATIC\\n" 275 | "mass: 0.0\\n" 276 | "friction: 0.1\\n" 277 | "restitution: 0.5\\n" 278 | "group: \\\"respawn\\\"\\n" 279 | "mask: \\\"player\\\"\\n" 280 | "embedded_collision_shape {\\n" 281 | " shapes {\\n" 282 | " shape_type: TYPE_BOX\\n" 283 | " position {\\n" 284 | " x: 547.0\\n" 285 | " y: 0.0\\n" 286 | " z: 0.0\\n" 287 | " }\\n" 288 | " rotation {\\n" 289 | " x: 0.0\\n" 290 | " y: 0.0\\n" 291 | " z: 0.0\\n" 292 | " w: 1.0\\n" 293 | " }\\n" 294 | " index: 0\\n" 295 | " count: 3\\n" 296 | " }\\n" 297 | " data: 1000.0\\n" 298 | " data: 50.0\\n" 299 | " data: 10.0\\n" 300 | "}\\n" 301 | "linear_damping: 0.0\\n" 302 | "angular_damping: 0.0\\n" 303 | "locked_rotation: false\\n" 304 | "bullet: false\\n" 305 | "\"\n" 306 | " position {\n" 307 | " x: 0.0\n" 308 | " y: 0.0\n" 309 | " z: 0.0\n" 310 | " }\n" 311 | " rotation {\n" 312 | " x: 0.0\n" 313 | " y: 0.0\n" 314 | " z: 0.0\n" 315 | " w: 1.0\n" 316 | " }\n" 317 | "}\n" 318 | "" 319 | position { 320 | x: 0.0 321 | y: 0.0 322 | z: -1.0 323 | } 324 | rotation { 325 | x: 0.0 326 | y: 0.0 327 | z: 0.0 328 | w: 1.0 329 | } 330 | scale3 { 331 | x: 1.0 332 | y: 1.0 333 | z: 1.0 334 | } 335 | } 336 | embedded_instances { 337 | id: "instructions" 338 | data: "embedded_components {\n" 339 | " id: \"label\"\n" 340 | " type: \"label\"\n" 341 | " data: \"size {\\n" 342 | " x: 128.0\\n" 343 | " y: 32.0\\n" 344 | " z: 0.0\\n" 345 | " w: 0.0\\n" 346 | "}\\n" 347 | "color {\\n" 348 | " x: 1.0\\n" 349 | " y: 1.0\\n" 350 | " z: 1.0\\n" 351 | " w: 1.0\\n" 352 | "}\\n" 353 | "outline {\\n" 354 | " x: 0.0\\n" 355 | " y: 0.0\\n" 356 | " z: 0.0\\n" 357 | " w: 1.0\\n" 358 | "}\\n" 359 | "shadow {\\n" 360 | " x: 0.0\\n" 361 | " y: 0.0\\n" 362 | " z: 0.0\\n" 363 | " w: 1.0\\n" 364 | "}\\n" 365 | "leading: 1.0\\n" 366 | "tracking: 0.0\\n" 367 | "pivot: PIVOT_NW\\n" 368 | "blend_mode: BLEND_MODE_ALPHA\\n" 369 | "line_break: false\\n" 370 | "text: \\\"ARROWS = MOVE\\\\n" 371 | "\\\"\\n" 372 | " \\\"SPACE = JUMP + DOUBLE JUMP\\\\n" 373 | "\\\"\\n" 374 | " \\\"X = SHOOT\\\"\\n" 375 | "font: \\\"/assets/fonts/instructions.font\\\"\\n" 376 | "material: \\\"/builtins/fonts/label.material\\\"\\n" 377 | "\"\n" 378 | " position {\n" 379 | " x: 0.0\n" 380 | " y: 0.0\n" 381 | " z: 0.0\n" 382 | " }\n" 383 | " rotation {\n" 384 | " x: 0.0\n" 385 | " y: 0.0\n" 386 | " z: 0.0\n" 387 | " w: 1.0\n" 388 | " }\n" 389 | "}\n" 390 | "" 391 | position { 392 | x: 249.0 393 | y: 148.0 394 | z: 0.0 395 | } 396 | rotation { 397 | x: 0.0 398 | y: 0.0 399 | z: 0.0 400 | w: 1.0 401 | } 402 | scale3 { 403 | x: 1.0 404 | y: 1.0 405 | z: 1.0 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /game/jump.particlefx: -------------------------------------------------------------------------------- 1 | emitters { 2 | id: "emitter" 3 | mode: PLAY_MODE_ONCE 4 | duration: 0.2 5 | space: EMISSION_SPACE_WORLD 6 | position { 7 | x: 0.0 8 | y: 0.0 9 | z: 0.0 10 | } 11 | rotation { 12 | x: 0.0 13 | y: 0.0 14 | z: 0.0 15 | w: 1.0 16 | } 17 | tile_source: "/builtins/graphics/particle_blob.tilesource" 18 | animation: "anim" 19 | material: "/builtins/materials/particlefx.material" 20 | blend_mode: BLEND_MODE_ADD 21 | particle_orientation: PARTICLE_ORIENTATION_DEFAULT 22 | inherit_velocity: 0.0 23 | max_particle_count: 3 24 | type: EMITTER_TYPE_CIRCLE 25 | start_delay: 0.0 26 | properties { 27 | key: EMITTER_KEY_SPAWN_RATE 28 | points { 29 | x: 0.0 30 | y: 30.0 31 | t_x: 1.0 32 | t_y: 0.0 33 | } 34 | spread: 20.0 35 | } 36 | properties { 37 | key: EMITTER_KEY_SIZE_X 38 | points { 39 | x: 0.0 40 | y: 7.0 41 | t_x: 1.0 42 | t_y: 0.0 43 | } 44 | spread: 0.0 45 | } 46 | properties { 47 | key: EMITTER_KEY_SIZE_Y 48 | points { 49 | x: 0.0 50 | y: 7.0 51 | t_x: 1.0 52 | t_y: 0.0 53 | } 54 | spread: 0.0 55 | } 56 | properties { 57 | key: EMITTER_KEY_SIZE_Z 58 | points { 59 | x: 0.0 60 | y: 0.0 61 | t_x: 1.0 62 | t_y: 0.0 63 | } 64 | spread: 0.0 65 | } 66 | properties { 67 | key: EMITTER_KEY_PARTICLE_LIFE_TIME 68 | points { 69 | x: 0.0 70 | y: 1.0 71 | t_x: 1.0 72 | t_y: 0.0 73 | } 74 | spread: 0.5 75 | } 76 | properties { 77 | key: EMITTER_KEY_PARTICLE_SPEED 78 | points { 79 | x: 0.0 80 | y: 3.0 81 | t_x: 1.0 82 | t_y: 0.0 83 | } 84 | spread: 1.0 85 | } 86 | properties { 87 | key: EMITTER_KEY_PARTICLE_SIZE 88 | points { 89 | x: 0.0 90 | y: 2.0 91 | t_x: 1.0 92 | t_y: 0.0 93 | } 94 | spread: 1.0 95 | } 96 | properties { 97 | key: EMITTER_KEY_PARTICLE_RED 98 | points { 99 | x: 0.0 100 | y: 1.0 101 | t_x: 1.0 102 | t_y: 0.0 103 | } 104 | spread: 0.0 105 | } 106 | properties { 107 | key: EMITTER_KEY_PARTICLE_GREEN 108 | points { 109 | x: 0.0 110 | y: 1.0 111 | t_x: 1.0 112 | t_y: 0.0 113 | } 114 | spread: 0.0 115 | } 116 | properties { 117 | key: EMITTER_KEY_PARTICLE_BLUE 118 | points { 119 | x: 0.0 120 | y: 1.0 121 | t_x: 1.0 122 | t_y: 0.0 123 | } 124 | spread: 0.0 125 | } 126 | properties { 127 | key: EMITTER_KEY_PARTICLE_ALPHA 128 | points { 129 | x: 0.0 130 | y: 1.0 131 | t_x: 1.0 132 | t_y: 0.0 133 | } 134 | spread: 0.0 135 | } 136 | properties { 137 | key: EMITTER_KEY_PARTICLE_ROTATION 138 | points { 139 | x: 0.0 140 | y: 0.0 141 | t_x: 1.0 142 | t_y: 0.0 143 | } 144 | spread: 0.0 145 | } 146 | properties { 147 | key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_X 148 | points { 149 | x: 0.0 150 | y: 0.0 151 | t_x: 1.0 152 | t_y: 0.0 153 | } 154 | spread: 0.0 155 | } 156 | properties { 157 | key: EMITTER_KEY_PARTICLE_STRETCH_FACTOR_Y 158 | points { 159 | x: 0.0 160 | y: 0.0 161 | t_x: 1.0 162 | t_y: 0.0 163 | } 164 | spread: 0.0 165 | } 166 | properties { 167 | key: EMITTER_KEY_PARTICLE_ANGULAR_VELOCITY 168 | points { 169 | x: 0.0 170 | y: 0.0 171 | t_x: 1.0 172 | t_y: 0.0 173 | } 174 | spread: 0.0 175 | } 176 | particle_properties { 177 | key: PARTICLE_KEY_SCALE 178 | points { 179 | x: 0.0 180 | y: 0.47391304 181 | t_x: 0.12695746 182 | t_y: 0.99190813 183 | } 184 | points { 185 | x: 1.0 186 | y: 2.0 187 | t_x: 1.0 188 | t_y: 0.0 189 | } 190 | } 191 | particle_properties { 192 | key: PARTICLE_KEY_RED 193 | points { 194 | x: 0.0 195 | y: 1.0 196 | t_x: 1.0 197 | t_y: 0.0 198 | } 199 | } 200 | particle_properties { 201 | key: PARTICLE_KEY_GREEN 202 | points { 203 | x: 0.0 204 | y: 1.0 205 | t_x: 1.0 206 | t_y: 0.0 207 | } 208 | } 209 | particle_properties { 210 | key: PARTICLE_KEY_BLUE 211 | points { 212 | x: 0.0 213 | y: 1.0 214 | t_x: 1.0 215 | t_y: 0.0 216 | } 217 | } 218 | particle_properties { 219 | key: PARTICLE_KEY_ALPHA 220 | points { 221 | x: 0.0 222 | y: 0.0 223 | t_x: 0.07194582 224 | t_y: 0.99740857 225 | } 226 | points { 227 | x: 0.11320755 228 | y: 0.99277455 229 | t_x: 0.99418455 230 | t_y: 0.10768964 231 | } 232 | points { 233 | x: 0.7112546 234 | y: 0.555656 235 | t_x: 0.5694311 236 | t_y: -0.82203907 237 | } 238 | points { 239 | x: 1.0 240 | y: 0.0072254334 241 | t_x: 0.4737472 242 | t_y: -0.8806609 243 | } 244 | } 245 | particle_properties { 246 | key: PARTICLE_KEY_ROTATION 247 | points { 248 | x: 0.0 249 | y: 0.0 250 | t_x: 1.0 251 | t_y: 0.0 252 | } 253 | } 254 | particle_properties { 255 | key: PARTICLE_KEY_STRETCH_FACTOR_X 256 | points { 257 | x: 0.0 258 | y: 0.0 259 | t_x: 1.0 260 | t_y: 0.0 261 | } 262 | } 263 | particle_properties { 264 | key: PARTICLE_KEY_STRETCH_FACTOR_Y 265 | points { 266 | x: 0.0 267 | y: 0.0 268 | t_x: 1.0 269 | t_y: 0.0 270 | } 271 | } 272 | particle_properties { 273 | key: PARTICLE_KEY_ANGULAR_VELOCITY 274 | points { 275 | x: 0.0 276 | y: 1.0 277 | t_x: 1.0 278 | t_y: 0.0 279 | } 280 | } 281 | size_mode: SIZE_MODE_MANUAL 282 | start_delay_spread: 0.0 283 | duration_spread: 0.0 284 | stretch_with_velocity: false 285 | start_offset: 0.0 286 | } 287 | -------------------------------------------------------------------------------- /game/level.script: -------------------------------------------------------------------------------- 1 | local BACKGROUND_COLOR = vmath.vector4(252/255, 223/255, 205/255, 255/255) 2 | 3 | function init(self) 4 | msg.post("@render:", "clear_color", { color = BACKGROUND_COLOR }) 5 | end 6 | -------------------------------------------------------------------------------- /game/level.tilemap: -------------------------------------------------------------------------------- 1 | tile_set: "/assets/game.tilesource" 2 | layers { 3 | id: "layer1" 4 | z: 0.0 5 | is_visible: 1 6 | cell { 7 | x: 15 8 | y: 6 9 | tile: 16 10 | h_flip: 0 11 | v_flip: 0 12 | } 13 | cell { 14 | x: 10 15 | y: 7 16 | tile: 18 17 | h_flip: 0 18 | v_flip: 0 19 | } 20 | cell { 21 | x: 15 22 | y: 7 23 | tile: 13 24 | h_flip: 0 25 | v_flip: 0 26 | } 27 | cell { 28 | x: 10 29 | y: 8 30 | tile: 15 31 | h_flip: 0 32 | v_flip: 0 33 | } 34 | cell { 35 | x: 15 36 | y: 8 37 | tile: 13 38 | h_flip: 0 39 | v_flip: 0 40 | } 41 | cell { 42 | x: 3 43 | y: 9 44 | tile: 26 45 | h_flip: 0 46 | v_flip: 0 47 | } 48 | cell { 49 | x: 4 50 | y: 9 51 | tile: 4 52 | h_flip: 0 53 | v_flip: 0 54 | } 55 | cell { 56 | x: 5 57 | y: 9 58 | tile: 4 59 | h_flip: 0 60 | v_flip: 0 61 | } 62 | cell { 63 | x: 6 64 | y: 9 65 | tile: 4 66 | h_flip: 0 67 | v_flip: 0 68 | } 69 | cell { 70 | x: 7 71 | y: 9 72 | tile: 25 73 | h_flip: 0 74 | v_flip: 0 75 | } 76 | cell { 77 | x: 10 78 | y: 9 79 | tile: 15 80 | h_flip: 0 81 | v_flip: 0 82 | } 83 | cell { 84 | x: 15 85 | y: 9 86 | tile: 6 87 | h_flip: 0 88 | v_flip: 0 89 | } 90 | cell { 91 | x: 16 92 | y: 9 93 | tile: 4 94 | h_flip: 0 95 | v_flip: 0 96 | } 97 | cell { 98 | x: 17 99 | y: 9 100 | tile: 21 101 | h_flip: 0 102 | v_flip: 0 103 | } 104 | cell { 105 | x: 18 106 | y: 9 107 | tile: 4 108 | h_flip: 0 109 | v_flip: 0 110 | } 111 | cell { 112 | x: 19 113 | y: 9 114 | tile: 4 115 | h_flip: 0 116 | v_flip: 0 117 | } 118 | cell { 119 | x: 20 120 | y: 9 121 | tile: 25 122 | h_flip: 0 123 | v_flip: 0 124 | } 125 | cell { 126 | x: 3 127 | y: 10 128 | tile: 15 129 | h_flip: 0 130 | v_flip: 0 131 | } 132 | cell { 133 | x: 5 134 | y: 10 135 | tile: 58 136 | h_flip: 0 137 | v_flip: 0 138 | } 139 | cell { 140 | x: 7 141 | y: 10 142 | tile: 13 143 | h_flip: 0 144 | v_flip: 0 145 | } 146 | cell { 147 | x: 10 148 | y: 10 149 | tile: 15 150 | h_flip: 0 151 | v_flip: 0 152 | } 153 | cell { 154 | x: 16 155 | y: 10 156 | tile: 36 157 | h_flip: 0 158 | v_flip: 0 159 | } 160 | cell { 161 | x: 18 162 | y: 10 163 | tile: 35 164 | h_flip: 0 165 | v_flip: 0 166 | } 167 | cell { 168 | x: 19 169 | y: 10 170 | tile: 32 171 | h_flip: 0 172 | v_flip: 0 173 | } 174 | cell { 175 | x: 20 176 | y: 10 177 | tile: 13 178 | h_flip: 0 179 | v_flip: 0 180 | } 181 | cell { 182 | x: 3 183 | y: 11 184 | tile: 15 185 | h_flip: 0 186 | v_flip: 0 187 | } 188 | cell { 189 | x: 5 190 | y: 11 191 | tile: 39 192 | h_flip: 0 193 | v_flip: 0 194 | } 195 | cell { 196 | x: 7 197 | y: 11 198 | tile: 3 199 | h_flip: 0 200 | v_flip: 0 201 | } 202 | cell { 203 | x: 8 204 | y: 11 205 | tile: 4 206 | h_flip: 0 207 | v_flip: 0 208 | } 209 | cell { 210 | x: 9 211 | y: 11 212 | tile: 22 213 | h_flip: 0 214 | v_flip: 0 215 | } 216 | cell { 217 | x: 10 218 | y: 11 219 | tile: 5 220 | h_flip: 0 221 | v_flip: 0 222 | } 223 | cell { 224 | x: 13 225 | y: 11 226 | tile: 12 227 | h_flip: 0 228 | v_flip: 0 229 | } 230 | cell { 231 | x: 20 232 | y: 11 233 | tile: 13 234 | h_flip: 0 235 | v_flip: 0 236 | } 237 | cell { 238 | x: -1 239 | y: 11 240 | tile: 16 241 | h_flip: 0 242 | v_flip: 0 243 | } 244 | cell { 245 | x: 0 246 | y: 12 247 | tile: 4 248 | h_flip: 0 249 | v_flip: 0 250 | } 251 | cell { 252 | x: 1 253 | y: 12 254 | tile: 4 255 | h_flip: 0 256 | v_flip: 0 257 | } 258 | cell { 259 | x: 2 260 | y: 12 261 | tile: 4 262 | h_flip: 0 263 | v_flip: 0 264 | } 265 | cell { 266 | x: 3 267 | y: 12 268 | tile: 8 269 | h_flip: 0 270 | v_flip: 0 271 | } 272 | cell { 273 | x: 5 274 | y: 12 275 | tile: 48 276 | h_flip: 0 277 | v_flip: 0 278 | } 279 | cell { 280 | x: 8 281 | y: 12 282 | tile: 36 283 | h_flip: 0 284 | v_flip: 0 285 | } 286 | cell { 287 | x: 9 288 | y: 12 289 | tile: 58 290 | h_flip: 0 291 | v_flip: 0 292 | } 293 | cell { 294 | x: 20 295 | y: 12 296 | tile: 13 297 | h_flip: 0 298 | v_flip: 0 299 | } 300 | cell { 301 | x: 25 302 | y: 12 303 | tile: 26 304 | h_flip: 0 305 | v_flip: 0 306 | } 307 | cell { 308 | x: 26 309 | y: 12 310 | tile: 4 311 | h_flip: 0 312 | v_flip: 0 313 | } 314 | cell { 315 | x: 27 316 | y: 12 317 | tile: 4 318 | h_flip: 0 319 | v_flip: 0 320 | } 321 | cell { 322 | x: 28 323 | y: 12 324 | tile: 4 325 | h_flip: 0 326 | v_flip: 0 327 | } 328 | cell { 329 | x: 29 330 | y: 12 331 | tile: 25 332 | h_flip: 0 333 | v_flip: 0 334 | } 335 | cell { 336 | x: 32 337 | y: 12 338 | tile: 18 339 | h_flip: 0 340 | v_flip: 0 341 | } 342 | cell { 343 | x: 34 344 | y: 12 345 | tile: 16 346 | h_flip: 0 347 | v_flip: 0 348 | } 349 | cell { 350 | x: -1 351 | y: 12 352 | tile: 6 353 | h_flip: 0 354 | v_flip: 0 355 | } 356 | cell { 357 | x: 1 358 | y: 13 359 | tile: 30 360 | h_flip: 0 361 | v_flip: 0 362 | } 363 | cell { 364 | x: 2 365 | y: 13 366 | tile: 31 367 | h_flip: 0 368 | v_flip: 0 369 | } 370 | cell { 371 | x: 5 372 | y: 13 373 | tile: 38 374 | h_flip: 0 375 | v_flip: 0 376 | } 377 | cell { 378 | x: 9 379 | y: 13 380 | tile: 49 381 | h_flip: 0 382 | v_flip: 0 383 | } 384 | cell { 385 | x: 20 386 | y: 13 387 | tile: 13 388 | h_flip: 0 389 | v_flip: 0 390 | } 391 | cell { 392 | x: 25 393 | y: 13 394 | tile: 15 395 | h_flip: 0 396 | v_flip: 0 397 | } 398 | cell { 399 | x: 27 400 | y: 13 401 | tile: 34 402 | h_flip: 0 403 | v_flip: 0 404 | } 405 | cell { 406 | x: 29 407 | y: 13 408 | tile: 13 409 | h_flip: 0 410 | v_flip: 0 411 | } 412 | cell { 413 | x: 32 414 | y: 13 415 | tile: 15 416 | h_flip: 0 417 | v_flip: 0 418 | } 419 | cell { 420 | x: 34 421 | y: 13 422 | tile: 13 423 | h_flip: 0 424 | v_flip: 0 425 | } 426 | cell { 427 | x: 35 428 | y: 13 429 | tile: 26 430 | h_flip: 0 431 | v_flip: 0 432 | } 433 | cell { 434 | x: 36 435 | y: 13 436 | tile: 4 437 | h_flip: 0 438 | v_flip: 0 439 | } 440 | cell { 441 | x: 37 442 | y: 13 443 | tile: 21 444 | h_flip: 0 445 | v_flip: 0 446 | } 447 | cell { 448 | x: 38 449 | y: 13 450 | tile: 4 451 | h_flip: 0 452 | v_flip: 0 453 | } 454 | cell { 455 | x: 39 456 | y: 13 457 | tile: 4 458 | h_flip: 0 459 | v_flip: 0 460 | } 461 | cell { 462 | x: 40 463 | y: 13 464 | tile: 25 465 | h_flip: 0 466 | v_flip: 0 467 | } 468 | cell { 469 | x: 0 470 | y: 14 471 | tile: 9 472 | h_flip: 0 473 | v_flip: 0 474 | } 475 | cell { 476 | x: 9 477 | y: 14 478 | tile: 38 479 | h_flip: 0 480 | v_flip: 0 481 | } 482 | cell { 483 | x: 20 484 | y: 14 485 | tile: 13 486 | h_flip: 0 487 | v_flip: 0 488 | } 489 | cell { 490 | x: 25 491 | y: 14 492 | tile: 15 493 | h_flip: 0 494 | v_flip: 0 495 | } 496 | cell { 497 | x: 29 498 | y: 14 499 | tile: 3 500 | h_flip: 0 501 | v_flip: 0 502 | } 503 | cell { 504 | x: 30 505 | y: 14 506 | tile: 4 507 | h_flip: 0 508 | v_flip: 0 509 | } 510 | cell { 511 | x: 31 512 | y: 14 513 | tile: 4 514 | h_flip: 0 515 | v_flip: 0 516 | } 517 | cell { 518 | x: 32 519 | y: 14 520 | tile: 5 521 | h_flip: 0 522 | v_flip: 0 523 | } 524 | cell { 525 | x: 34 526 | y: 14 527 | tile: 3 528 | h_flip: 0 529 | v_flip: 0 530 | } 531 | cell { 532 | x: 35 533 | y: 14 534 | tile: 8 535 | h_flip: 0 536 | v_flip: 0 537 | } 538 | cell { 539 | x: 37 540 | y: 14 541 | tile: 34 542 | h_flip: 0 543 | v_flip: 0 544 | } 545 | cell { 546 | x: 38 547 | y: 14 548 | tile: 35 549 | h_flip: 0 550 | v_flip: 0 551 | } 552 | cell { 553 | x: 40 554 | y: 14 555 | tile: 13 556 | h_flip: 0 557 | v_flip: 0 558 | } 559 | cell { 560 | x: 52 561 | y: 14 562 | tile: 18 563 | h_flip: 0 564 | v_flip: 0 565 | } 566 | cell { 567 | x: 2 568 | y: 15 569 | tile: 1 570 | h_flip: 0 571 | v_flip: 0 572 | } 573 | cell { 574 | x: 3 575 | y: 15 576 | tile: 2 577 | h_flip: 0 578 | v_flip: 0 579 | } 580 | cell { 581 | x: 17 582 | y: 15 583 | tile: 1 584 | h_flip: 0 585 | v_flip: 0 586 | } 587 | cell { 588 | x: 18 589 | y: 15 590 | tile: 9 591 | h_flip: 0 592 | v_flip: 0 593 | } 594 | cell { 595 | x: 20 596 | y: 15 597 | tile: 6 598 | h_flip: 0 599 | v_flip: 0 600 | } 601 | cell { 602 | x: 21 603 | y: 15 604 | tile: 4 605 | h_flip: 0 606 | v_flip: 0 607 | } 608 | cell { 609 | x: 22 610 | y: 15 611 | tile: 22 612 | h_flip: 0 613 | v_flip: 0 614 | } 615 | cell { 616 | x: 23 617 | y: 15 618 | tile: 4 619 | h_flip: 0 620 | v_flip: 0 621 | } 622 | cell { 623 | x: 24 624 | y: 15 625 | tile: 4 626 | h_flip: 0 627 | v_flip: 0 628 | } 629 | cell { 630 | x: 25 631 | y: 15 632 | tile: 5 633 | h_flip: 0 634 | v_flip: 0 635 | } 636 | cell { 637 | x: 29 638 | y: 15 639 | tile: 32 640 | h_flip: 0 641 | v_flip: 0 642 | } 643 | cell { 644 | x: 31 645 | y: 15 646 | tile: 33 647 | h_flip: 0 648 | v_flip: 0 649 | } 650 | cell { 651 | x: 40 652 | y: 15 653 | tile: 13 654 | h_flip: 0 655 | v_flip: 0 656 | } 657 | cell { 658 | x: 45 659 | y: 15 660 | tile: 26 661 | h_flip: 0 662 | v_flip: 0 663 | } 664 | cell { 665 | x: 46 666 | y: 15 667 | tile: 4 668 | h_flip: 0 669 | v_flip: 0 670 | } 671 | cell { 672 | x: 47 673 | y: 15 674 | tile: 22 675 | h_flip: 0 676 | v_flip: 0 677 | } 678 | cell { 679 | x: 48 680 | y: 15 681 | tile: 4 682 | h_flip: 0 683 | v_flip: 0 684 | } 685 | cell { 686 | x: 49 687 | y: 15 688 | tile: 25 689 | h_flip: 0 690 | v_flip: 0 691 | } 692 | cell { 693 | x: 52 694 | y: 15 695 | tile: 15 696 | h_flip: 0 697 | v_flip: 0 698 | } 699 | cell { 700 | x: 13 701 | y: 16 702 | tile: 27 703 | h_flip: 0 704 | v_flip: 0 705 | } 706 | cell { 707 | x: 14 708 | y: 16 709 | tile: 22 710 | h_flip: 0 711 | v_flip: 0 712 | } 713 | cell { 714 | x: 15 715 | y: 16 716 | tile: 28 717 | h_flip: 0 718 | v_flip: 0 719 | } 720 | cell { 721 | x: 20 722 | y: 16 723 | tile: 30 724 | h_flip: 0 725 | v_flip: 0 726 | } 727 | cell { 728 | x: 21 729 | y: 16 730 | tile: 58 731 | h_flip: 0 732 | v_flip: 0 733 | } 734 | cell { 735 | x: 23 736 | y: 16 737 | tile: 34 738 | h_flip: 0 739 | v_flip: 0 740 | } 741 | cell { 742 | x: 24 743 | y: 16 744 | tile: 59 745 | h_flip: 0 746 | v_flip: 0 747 | } 748 | cell { 749 | x: 40 750 | y: 16 751 | tile: 13 752 | h_flip: 0 753 | v_flip: 0 754 | } 755 | cell { 756 | x: 45 757 | y: 16 758 | tile: 15 759 | h_flip: 0 760 | v_flip: 0 761 | } 762 | cell { 763 | x: 46 764 | y: 16 765 | tile: 30 766 | h_flip: 0 767 | v_flip: 0 768 | } 769 | cell { 770 | x: 47 771 | y: 16 772 | tile: 57 773 | h_flip: 0 774 | v_flip: 0 775 | } 776 | cell { 777 | x: 49 778 | y: 16 779 | tile: 13 780 | h_flip: 0 781 | v_flip: 0 782 | } 783 | cell { 784 | x: 52 785 | y: 16 786 | tile: 15 787 | h_flip: 0 788 | v_flip: 0 789 | } 790 | cell { 791 | x: 5 792 | y: 17 793 | tile: 11 794 | h_flip: 0 795 | v_flip: 0 796 | } 797 | cell { 798 | x: 14 799 | y: 17 800 | tile: 58 801 | h_flip: 0 802 | v_flip: 0 803 | } 804 | cell { 805 | x: 21 806 | y: 17 807 | tile: 49 808 | h_flip: 0 809 | v_flip: 0 810 | } 811 | cell { 812 | x: 24 813 | y: 17 814 | tile: 38 815 | h_flip: 0 816 | v_flip: 0 817 | } 818 | cell { 819 | x: 40 820 | y: 17 821 | tile: 13 822 | h_flip: 0 823 | v_flip: 0 824 | } 825 | cell { 826 | x: 45 827 | y: 17 828 | tile: 15 829 | h_flip: 0 830 | v_flip: 0 831 | } 832 | cell { 833 | x: 47 834 | y: 17 835 | tile: 38 836 | h_flip: 0 837 | v_flip: 0 838 | } 839 | cell { 840 | x: 49 841 | y: 17 842 | tile: 3 843 | h_flip: 0 844 | v_flip: 0 845 | } 846 | cell { 847 | x: 50 848 | y: 17 849 | tile: 4 850 | h_flip: 0 851 | v_flip: 0 852 | } 853 | cell { 854 | x: 51 855 | y: 17 856 | tile: 4 857 | h_flip: 0 858 | v_flip: 0 859 | } 860 | cell { 861 | x: 52 862 | y: 17 863 | tile: 5 864 | h_flip: 0 865 | v_flip: 0 866 | } 867 | cell { 868 | x: 14 869 | y: 18 870 | tile: 39 871 | h_flip: 0 872 | v_flip: 0 873 | } 874 | cell { 875 | x: 21 876 | y: 18 877 | tile: 38 878 | h_flip: 0 879 | v_flip: 0 880 | } 881 | cell { 882 | x: 40 883 | y: 18 884 | tile: 6 885 | h_flip: 0 886 | v_flip: 0 887 | } 888 | cell { 889 | x: 41 890 | y: 18 891 | tile: 4 892 | h_flip: 0 893 | v_flip: 0 894 | } 895 | cell { 896 | x: 42 897 | y: 18 898 | tile: 22 899 | h_flip: 0 900 | v_flip: 0 901 | } 902 | cell { 903 | x: 43 904 | y: 18 905 | tile: 4 906 | h_flip: 0 907 | v_flip: 0 908 | } 909 | cell { 910 | x: 44 911 | y: 18 912 | tile: 4 913 | h_flip: 0 914 | v_flip: 0 915 | } 916 | cell { 917 | x: 45 918 | y: 18 919 | tile: 5 920 | h_flip: 0 921 | v_flip: 0 922 | } 923 | cell { 924 | x: 49 925 | y: 18 926 | tile: 58 927 | h_flip: 0 928 | v_flip: 0 929 | } 930 | cell { 931 | x: 14 932 | y: 19 933 | tile: 48 934 | h_flip: 0 935 | v_flip: 0 936 | } 937 | cell { 938 | x: 28 939 | y: 19 940 | tile: 27 941 | h_flip: 0 942 | v_flip: 0 943 | } 944 | cell { 945 | x: 29 946 | y: 19 947 | tile: 21 948 | h_flip: 0 949 | v_flip: 0 950 | } 951 | cell { 952 | x: 30 953 | y: 19 954 | tile: 28 955 | h_flip: 0 956 | v_flip: 0 957 | } 958 | cell { 959 | x: 40 960 | y: 19 961 | tile: 33 962 | h_flip: 0 963 | v_flip: 0 964 | } 965 | cell { 966 | x: 41 967 | y: 19 968 | tile: 58 969 | h_flip: 0 970 | v_flip: 0 971 | } 972 | cell { 973 | x: 43 974 | y: 19 975 | tile: 37 976 | h_flip: 0 977 | v_flip: 0 978 | } 979 | cell { 980 | x: 44 981 | y: 19 982 | tile: 35 983 | h_flip: 0 984 | v_flip: 0 985 | } 986 | cell { 987 | x: 49 988 | y: 19 989 | tile: 48 990 | h_flip: 0 991 | v_flip: 0 992 | } 993 | cell { 994 | x: 51 995 | y: 19 996 | tile: 11 997 | h_flip: 0 998 | v_flip: 0 999 | } 1000 | cell { 1001 | x: 14 1002 | y: 20 1003 | tile: 38 1004 | h_flip: 0 1005 | v_flip: 0 1006 | } 1007 | cell { 1008 | x: 29 1009 | y: 20 1010 | tile: 58 1011 | h_flip: 0 1012 | v_flip: 0 1013 | } 1014 | cell { 1015 | x: 36 1016 | y: 20 1017 | tile: 9 1018 | h_flip: 0 1019 | v_flip: 0 1020 | } 1021 | cell { 1022 | x: 41 1023 | y: 20 1024 | tile: 49 1025 | h_flip: 0 1026 | v_flip: 0 1027 | } 1028 | cell { 1029 | x: 47 1030 | y: 20 1031 | tile: 9 1032 | h_flip: 0 1033 | v_flip: 0 1034 | } 1035 | cell { 1036 | x: 49 1037 | y: 20 1038 | tile: 39 1039 | h_flip: 0 1040 | v_flip: 0 1041 | } 1042 | cell { 1043 | x: 26 1044 | y: 21 1045 | tile: 11 1046 | h_flip: 0 1047 | v_flip: 0 1048 | } 1049 | cell { 1050 | x: 29 1051 | y: 21 1052 | tile: 39 1053 | h_flip: 0 1054 | v_flip: 0 1055 | } 1056 | cell { 1057 | x: 41 1058 | y: 21 1059 | tile: 47 1060 | h_flip: 0 1061 | v_flip: 0 1062 | } 1063 | cell { 1064 | x: 49 1065 | y: 21 1066 | tile: 38 1067 | h_flip: 0 1068 | v_flip: 0 1069 | } 1070 | cell { 1071 | x: 29 1072 | y: 22 1073 | tile: 48 1074 | h_flip: 0 1075 | v_flip: 0 1076 | } 1077 | cell { 1078 | x: 41 1079 | y: 22 1080 | tile: 38 1081 | h_flip: 0 1082 | v_flip: 0 1083 | } 1084 | cell { 1085 | x: 44 1086 | y: 22 1087 | tile: 12 1088 | h_flip: 0 1089 | v_flip: 0 1090 | } 1091 | cell { 1092 | x: 29 1093 | y: 23 1094 | tile: 38 1095 | h_flip: 0 1096 | v_flip: 0 1097 | } 1098 | } 1099 | material: "/builtins/materials/tile_map.material" 1100 | blend_mode: BLEND_MODE_ALPHA 1101 | -------------------------------------------------------------------------------- /game/player.collection: -------------------------------------------------------------------------------- 1 | name: "default" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "player" 5 | children: "visuals" 6 | data: "components {\n" 7 | " id: \"player\"\n" 8 | " component: \"/game/player.script\"\n" 9 | "}\n" 10 | "components {\n" 11 | " id: \"jump\"\n" 12 | " component: \"/game/jump.particlefx\"\n" 13 | " position {\n" 14 | " y: -5.0\n" 15 | " }\n" 16 | "}\n" 17 | "components {\n" 18 | " id: \"dust\"\n" 19 | " component: \"/game/dust.particlefx\"\n" 20 | " position {\n" 21 | " y: -5.0\n" 22 | " }\n" 23 | "}\n" 24 | "embedded_components {\n" 25 | " id: \"collisionobject\"\n" 26 | " type: \"collisionobject\"\n" 27 | " data: \"type: COLLISION_OBJECT_TYPE_KINEMATIC\\n" 28 | "mass: 0.0\\n" 29 | "friction: 0.1\\n" 30 | "restitution: 0.5\\n" 31 | "group: \\\"player\\\"\\n" 32 | "mask: \\\"ground\\\"\\n" 33 | "mask: \\\"enemy\\\"\\n" 34 | "mask: \\\"respawn\\\"\\n" 35 | "embedded_collision_shape {\\n" 36 | " shapes {\\n" 37 | " shape_type: TYPE_SPHERE\\n" 38 | " position {\\n" 39 | " y: 2.0\\n" 40 | " }\\n" 41 | " rotation {\\n" 42 | " }\\n" 43 | " index: 0\\n" 44 | " count: 1\\n" 45 | " }\\n" 46 | " shapes {\\n" 47 | " shape_type: TYPE_SPHERE\\n" 48 | " position {\\n" 49 | " x: 4.0\\n" 50 | " y: -4.0\\n" 51 | " }\\n" 52 | " rotation {\\n" 53 | " }\\n" 54 | " index: 1\\n" 55 | " count: 1\\n" 56 | " }\\n" 57 | " shapes {\\n" 58 | " shape_type: TYPE_SPHERE\\n" 59 | " position {\\n" 60 | " x: -4.0\\n" 61 | " y: -4.0\\n" 62 | " }\\n" 63 | " rotation {\\n" 64 | " }\\n" 65 | " index: 2\\n" 66 | " count: 1\\n" 67 | " }\\n" 68 | " data: 6.0\\n" 69 | " data: 1.0\\n" 70 | " data: 1.0\\n" 71 | "}\\n" 72 | "\"\n" 73 | "}\n" 74 | "embedded_components {\n" 75 | " id: \"bulletfactory\"\n" 76 | " type: \"factory\"\n" 77 | " data: \"prototype: \\\"/game/bullet.go\\\"\\n" 78 | "\"\n" 79 | "}\n" 80 | "embedded_components {\n" 81 | " id: \"camera\"\n" 82 | " type: \"camera\"\n" 83 | " data: \"aspect_ratio: 1.0\\n" 84 | "fov: 0.7854\\n" 85 | "near_z: -10.0\\n" 86 | "far_z: 10.0\\n" 87 | "orthographic_projection: 1\\n" 88 | "orthographic_zoom: 3.0\\n" 89 | "\"\n" 90 | "}\n" 91 | "" 92 | } 93 | embedded_instances { 94 | id: "visuals" 95 | data: "embedded_components {\n" 96 | " id: \"sprite\"\n" 97 | " type: \"sprite\"\n" 98 | " data: \"default_animation: \\\"player_walk\\\"\\n" 99 | "material: \\\"/builtins/materials/sprite.material\\\"\\n" 100 | "textures {\\n" 101 | " sampler: \\\"texture_sampler\\\"\\n" 102 | " texture: \\\"/assets/game.tilesource\\\"\\n" 103 | "}\\n" 104 | "\"\n" 105 | " position {\n" 106 | " y: 3.0\n" 107 | " }\n" 108 | "}\n" 109 | "" 110 | } 111 | -------------------------------------------------------------------------------- /game/player.script: -------------------------------------------------------------------------------- 1 | -- Player logic 2 | 3 | -- these are the tweaks for the mechanics, feel free to change them for a different feeling 4 | -- max speed right/left 5 | local MAX_GROUND_SPEED = 100 6 | local MAX_AIR_SPEED = 80 7 | -- max fall speed 8 | local MAX_FALL_SPEED = 500 9 | 10 | -- gravity pulling the player down in pixel units 11 | local GRAVITY = -500 12 | -- take-off speed when jumping in pixel units 13 | local JUMP_TAKEOFF_SPEED = 240 14 | local DOUBLEJUMP_TAKEOFF_SPEED = 200 15 | -- push-back when shooting 16 | local RECOIL = 500 17 | 18 | -- pre-hashing ids improves performance 19 | local CONTACT_POINT_RESPONSE = hash("contact_point_response") 20 | local GROUND = hash("ground") 21 | local RESPAWMN = hash("respawn") 22 | local ENEMY = hash("enemy") 23 | 24 | local LEFT = hash("left") 25 | local RIGHT = hash("right") 26 | local JUMP = hash("jump") 27 | local FIRE = hash("fire") 28 | 29 | local ANIM_WALK = hash("player_walk") 30 | local ANIM_IDLE = hash("player_idle") 31 | local ANIM_JUMP = hash("player_jump") 32 | local ANIM_FALL = hash("player_fall") 33 | 34 | local SPRITE = "visuals#sprite" 35 | 36 | 37 | function init(self) 38 | -- this lets us handle input in this script 39 | msg.post(".", "acquire_input_focus") 40 | 41 | -- spawn position 42 | self.spawn_position = go.get_position() 43 | -- player velocity 44 | self.velocity = vmath.vector3(0, 0, 0) 45 | -- which direction the player is facing 46 | self.direction = 1 47 | -- support variable to keep track of collisions and separation 48 | self.correction = vmath.vector3() 49 | -- if the player stands on ground or not 50 | self.ground_contact = true 51 | -- also track state of last frame 52 | -- (to detect when landing or taking off) 53 | self.previous_ground_contact = true 54 | -- the currently playing animation 55 | self.anim = nil 56 | end 57 | 58 | local function play_animation(self, anim) 59 | -- only play animations which are not already playing 60 | if self.anim ~= anim then 61 | -- tell the sprite to play the animation 62 | sprite.play_flipbook(SPRITE, anim) 63 | -- remember which animation is playing 64 | self.anim = anim 65 | end 66 | end 67 | 68 | local function squish() 69 | go.animate("visuals", "scale.x", go.PLAYBACK_ONCE_PINGPONG, 0.8, go.EASING_INOUTQUAD, 0.6) 70 | go.animate("visuals", "scale.y", go.PLAYBACK_ONCE_PINGPONG, 1.2, go.EASING_INOUTQUAD, 0.6) 71 | end 72 | 73 | local function update_animations(self) 74 | -- make sure the player character faces the right way 75 | sprite.set_hflip(SPRITE, self.direction == -1) 76 | 77 | -- make sure the right animation is playing 78 | if self.ground_contact then 79 | if self.velocity.x == 0 then 80 | play_animation(self, ANIM_IDLE) 81 | else 82 | play_animation(self, ANIM_WALK) 83 | end 84 | else 85 | if self.velocity.y > 0 then 86 | play_animation(self, ANIM_JUMP) 87 | else 88 | play_animation(self, ANIM_FALL) 89 | end 90 | end 91 | end 92 | 93 | -- clamp a number between a min and max value 94 | local function clamp(v, min, max) 95 | if v < min then return min 96 | elseif v > max then return max 97 | else return v end 98 | end 99 | 100 | -- apply an opposing force to decrease a velocity 101 | local function decelerate(v, f, dt) 102 | local opposing = math.abs(v * f) 103 | if v > 0 then 104 | return math.floor(math.max(0, v - opposing * dt)) 105 | elseif v < 0 then 106 | return math.ceil(math.min(0, v + opposing * dt)) 107 | else 108 | return 0 109 | end 110 | end 111 | 112 | function fixed_update(self, dt) 113 | -- apply gravity 114 | self.velocity.y = self.velocity.y + GRAVITY * dt 115 | self.velocity.y = clamp(self.velocity.y, -MAX_FALL_SPEED, MAX_FALL_SPEED) 116 | 117 | -- apply ground or air friction 118 | if self.ground_contact then 119 | self.velocity.x = decelerate(self.velocity.x, 20, dt) 120 | self.velocity.x = clamp(self.velocity.x, -MAX_GROUND_SPEED, MAX_GROUND_SPEED) 121 | else 122 | self.velocity.x = decelerate(self.velocity.x, 1, dt) 123 | self.velocity.x = clamp(self.velocity.x, -MAX_AIR_SPEED, MAX_AIR_SPEED) 124 | end 125 | 126 | -- move player 127 | local pos = go.get_position() 128 | pos = pos + self.velocity * dt 129 | go.set_position(pos) 130 | 131 | -- update animations based on state (ground, air, move and idle) 132 | update_animations(self) 133 | 134 | -- reset volatile state 135 | self.previous_ground_contact = self.ground_contact 136 | self.correction = vmath.vector3() 137 | self.ground_contact = false 138 | self.wall_contact = false 139 | end 140 | 141 | local NORMAL_THRESHOLD = 0.7 142 | 143 | -- https://defold.com/manuals/physics/#resolving-kinematic-collisions 144 | local function handle_obstacle_contact(self, normal, distance) 145 | -- don't care about anything but normals beyond the threshold 146 | -- we do this to eliminate false-positives such as ceiling hits when 147 | -- jumping next to a wall while moving into the wall 148 | if normal.y < NORMAL_THRESHOLD and normal.y > -NORMAL_THRESHOLD then 149 | normal.y = 0 150 | end 151 | if normal.x < NORMAL_THRESHOLD and normal.x > -NORMAL_THRESHOLD then 152 | normal.x = 0 153 | end 154 | -- update distance in case the normals have changed 155 | distance = distance * vmath.length(normal) 156 | 157 | if distance > 0 then 158 | -- First, project the accumulated correction onto 159 | -- the penetration vector 160 | local proj = vmath.project(self.correction, normal * distance) 161 | if proj < 1 then 162 | -- Only care for projections that does not overshoot. 163 | local comp = (distance - distance * proj) * normal 164 | -- Apply compensation 165 | go.set_position(go.get_position() + comp) 166 | -- Accumulate correction done 167 | self.correction = self.correction + comp 168 | end 169 | end 170 | 171 | -- collided with a wall 172 | -- stop horizontal movement 173 | if math.abs(normal.x) > NORMAL_THRESHOLD then 174 | self.wall_contact = true 175 | self.velocity.x = 0 176 | end 177 | -- collided with the ground 178 | -- stop vertical movement 179 | if normal.y > NORMAL_THRESHOLD then 180 | if not self.previous_ground_contact then 181 | -- add some particles 182 | particlefx.play("#dust") 183 | -- reset any "squish" that may have been applied 184 | go.set("visuals", "scale", 1) 185 | self.double_jump = false 186 | end 187 | self.ground_contact = true 188 | self.velocity.y = 0 189 | end 190 | -- collided with the ceiling 191 | -- stop vertical movement 192 | if normal.y < -NORMAL_THRESHOLD then 193 | self.velocity.y = 0 194 | end 195 | end 196 | 197 | function on_message(self, message_id, message, sender) 198 | -- check if we received a contact point message 199 | if message_id == CONTACT_POINT_RESPONSE then 200 | -- check that the object is something we consider an obstacle 201 | if message.group == GROUND then 202 | handle_obstacle_contact(self, message.normal, message.distance) 203 | elseif message.group == RESPAWMN or message.group == ENEMY then 204 | go.set_position(self.spawn_position) 205 | end 206 | end 207 | end 208 | 209 | local function jump(self) 210 | -- only allow jump from ground 211 | -- (extend this with a counter to do things like double-jumps) 212 | if self.ground_contact then 213 | -- set take-off speed 214 | self.velocity.y = JUMP_TAKEOFF_SPEED 215 | -- play animation 216 | play_animation(self, ANIM_JUMP) 217 | self.ground_contact = false 218 | -- compress and stretch player for visual "juice" 219 | squish() 220 | -- allow double jump if still moving up 221 | elseif not self.double_jump then 222 | self.velocity.y = DOUBLEJUMP_TAKEOFF_SPEED 223 | self.double_jump = true 224 | end 225 | -- add some particles 226 | particlefx.play("#jump") 227 | end 228 | 229 | local function abort_jump(self) 230 | -- cut the jump short if we are still going up 231 | if self.velocity.y > 0 then 232 | -- scale down the upwards speed 233 | self.velocity.y = self.velocity.y * 0.5 234 | end 235 | end 236 | 237 | local function walk(self, direction) 238 | if direction ~= 0 then 239 | self.direction = direction 240 | end 241 | if self.ground_contact then 242 | self.velocity.x = MAX_GROUND_SPEED * direction 243 | else 244 | -- move slower in the air 245 | self.velocity.x = MAX_AIR_SPEED * direction 246 | end 247 | end 248 | 249 | local function fire(self) 250 | self.velocity.x = self.velocity.x + RECOIL * -self.direction 251 | 252 | local pos = go.get_position() 253 | -- offset the bullet so that it is fired "outside" of the player sprite 254 | pos.x = pos.x + 8 * self.direction 255 | local id = factory.create("#bulletfactory", pos) 256 | 257 | -- flip the bullet sprite 258 | sprite.set_hflip(msg.url(nil, id, "sprite"), self.direction == -1) 259 | 260 | -- move the bullet 300 pixels and then delete it 261 | local distance = 300 262 | local to = pos.x + distance * self.direction 263 | local duration = distance / 250 264 | go.animate(id, "position.x", go.PLAYBACK_ONCE_FORWARD, to, go.EASING_LINEAR, duration, 0, function() 265 | go.delete(id) 266 | end) 267 | end 268 | 269 | function on_input(self, action_id, action) 270 | if action_id == LEFT then 271 | walk(self, -action.value) 272 | elseif action_id == RIGHT then 273 | walk(self, action.value) 274 | elseif action_id == JUMP then 275 | if action.pressed then 276 | jump(self) 277 | elseif action.released then 278 | abort_jump(self) 279 | end 280 | elseif action_id == FIRE then 281 | if action.released then 282 | fire(self) 283 | end 284 | end 285 | end -------------------------------------------------------------------------------- /game/slime.go: -------------------------------------------------------------------------------- 1 | components { 2 | id: "slime" 3 | component: "/game/slime.script" 4 | position { 5 | x: 0.0 6 | y: 0.0 7 | z: 0.0 8 | } 9 | rotation { 10 | x: 0.0 11 | y: 0.0 12 | z: 0.0 13 | w: 1.0 14 | } 15 | } 16 | embedded_components { 17 | id: "sprite" 18 | type: "sprite" 19 | data: "tile_set: \"/assets/game.tilesource\"\n" 20 | "default_animation: \"slime\"\n" 21 | "material: \"/builtins/materials/sprite.material\"\n" 22 | "blend_mode: BLEND_MODE_ALPHA\n" 23 | "" 24 | position { 25 | x: 0.0 26 | y: 5.0 27 | z: 0.0 28 | } 29 | rotation { 30 | x: 0.0 31 | y: 0.0 32 | z: 0.0 33 | w: 1.0 34 | } 35 | } 36 | embedded_components { 37 | id: "collisionobject" 38 | type: "collisionobject" 39 | data: "collision_shape: \"\"\n" 40 | "type: COLLISION_OBJECT_TYPE_KINEMATIC\n" 41 | "mass: 0.0\n" 42 | "friction: 0.1\n" 43 | "restitution: 0.5\n" 44 | "group: \"enemy\"\n" 45 | "mask: \"player\"\n" 46 | "mask: \"bullet\"\n" 47 | "embedded_collision_shape {\n" 48 | " shapes {\n" 49 | " shape_type: TYPE_SPHERE\n" 50 | " position {\n" 51 | " x: 0.0\n" 52 | " y: 0.5\n" 53 | " z: 0.0\n" 54 | " }\n" 55 | " rotation {\n" 56 | " x: 0.0\n" 57 | " y: 0.0\n" 58 | " z: 0.0\n" 59 | " w: 1.0\n" 60 | " }\n" 61 | " index: 0\n" 62 | " count: 1\n" 63 | " }\n" 64 | " data: 3.5\n" 65 | "}\n" 66 | "linear_damping: 0.0\n" 67 | "angular_damping: 0.0\n" 68 | "locked_rotation: false\n" 69 | "bullet: false\n" 70 | "" 71 | position { 72 | x: 0.0 73 | y: 0.0 74 | z: 0.0 75 | } 76 | rotation { 77 | x: 0.0 78 | y: 0.0 79 | z: 0.0 80 | w: 1.0 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /game/slime.script: -------------------------------------------------------------------------------- 1 | go.property("distance", 50) 2 | 3 | local SPEED = 10 4 | local DEAD_SPEED = 200 5 | 6 | local COLLISION_RESPONSE = hash("collision_response") 7 | local BULLET = hash("bullet") 8 | 9 | function init(self) 10 | -- move back and forth 11 | local pos = go.get_position() 12 | local to = pos.x + self.distance 13 | local duration = self.distance / SPEED 14 | go.animate(".", "position.x", go.PLAYBACK_LOOP_PINGPONG, to, go.EASING_LINEAR, duration) 15 | 16 | -- flip sprite 17 | local flip = false 18 | timer.delay(duration / 2, true, function() 19 | flip = not flip 20 | sprite.set_hflip("#sprite", flip) 21 | end) 22 | end 23 | 24 | function on_message(self, message_id, message, sender) 25 | if self.dead then return end 26 | if message_id == COLLISION_RESPONSE then 27 | if message.other_group == BULLET then 28 | -- remove the bullet 29 | go.delete(message.other_id) 30 | 31 | -- turn upside down and make it drop dead! 32 | -- also flag it as dead and ignore any additional messages 33 | self.dead = true 34 | sprite.set_vflip("#sprite", true) 35 | local pos = go.get_position() 36 | local duration = pos.y / DEAD_SPEED 37 | go.cancel_animations(".", "position.x") 38 | go.animate(".", "position.y", go.PLAYBACK_ONCE_FORWARD, 0, go.EASING_INQUAD, duration, 0, function() 39 | go.delete() 40 | end) 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /input/game.input_binding: -------------------------------------------------------------------------------- 1 | key_trigger { 2 | input: KEY_LEFT 3 | action: "left" 4 | } 5 | key_trigger { 6 | input: KEY_RIGHT 7 | action: "right" 8 | } 9 | key_trigger { 10 | input: KEY_SPACE 11 | action: "jump" 12 | } 13 | key_trigger { 14 | input: KEY_UP 15 | action: "jump" 16 | } 17 | key_trigger { 18 | input: KEY_X 19 | action: "fire" 20 | } 21 | gamepad_trigger { 22 | input: GAMEPAD_LSTICK_LEFT 23 | action: "left" 24 | } 25 | gamepad_trigger { 26 | input: GAMEPAD_LSTICK_RIGHT 27 | action: "right" 28 | } 29 | gamepad_trigger { 30 | input: GAMEPAD_RPAD_LEFT 31 | action: "fire" 32 | } 33 | gamepad_trigger { 34 | input: GAMEPAD_RPAD_UP 35 | action: "jump" 36 | } 37 | gamepad_trigger { 38 | input: GAMEPAD_LPAD_LEFT 39 | action: "left" 40 | } 41 | gamepad_trigger { 42 | input: GAMEPAD_LPAD_RIGHT 43 | action: "right" 44 | } 45 | --------------------------------------------------------------------------------