├── .gitignore ├── License.txt ├── art ├── CapturFiles-20170729_102112.png ├── CapturFiles-20170729_102158.png ├── CapturFiles-20170729_102215.png └── CapturFiles-20170729_102242.png ├── assets ├── images │ ├── 041.png │ ├── UI_WINDOW_1.png │ ├── UI_WINDOW_2.png │ ├── UI_WINDOW_3.png │ ├── UI_WINDOW_4.png │ ├── UI_WINDOW_5.png │ ├── UI_WINDOW_6.png │ ├── UI_WINDOW_7.png │ ├── UI_WINDOW_8.png │ ├── UI_WINDOW_9.png │ ├── arrowLeft.png │ ├── arrowRight.png │ ├── blackSmoke21.png │ ├── buttonStart.png │ ├── checkmark.png │ ├── cloud.png │ ├── crate_01.png │ ├── crate_07.png │ ├── crate_08.png │ ├── crate_09.png │ ├── crate_10.png │ ├── crate_11.png │ ├── crate_17.png │ ├── crate_18.png │ ├── crate_19.png │ ├── crate_20.png │ ├── crate_21.png │ ├── crate_42.png │ ├── crate_43.png │ ├── crate_44.png │ ├── crate_45.png │ ├── cross.png │ ├── exp2_0.png │ ├── flatDark03.png │ ├── flatDark48.png │ ├── flatDark49.png │ ├── gear.png │ ├── grass2_64.png │ ├── grass_64.png │ ├── greenRobotMoving.png │ ├── greyRobotMoving.png │ ├── information.png │ ├── jet_pack.png │ ├── longCloud.png │ ├── lucifer_cannon.png │ ├── medical_pack.png │ ├── menuList.png │ ├── meteorGrey_big1.png │ ├── meteorGrey_big2.png │ ├── meteorGrey_big3.png │ ├── meteorGrey_big4.png │ ├── meteorGrey_med1.png │ ├── meteorGrey_med2.png │ ├── meteorGrey_small1.png │ ├── meteorGrey_small2.png │ ├── meteorGrey_tiny1.png │ ├── meteorGrey_tiny2.png │ ├── mountain2_64.png │ ├── mountain_64.png │ ├── musicOff.png │ ├── musicOn.png │ ├── oil.png │ ├── pause.png │ ├── redRobotMoving.png │ ├── robot_3Dblue.png │ ├── robot_3Dgreen.png │ ├── robot_3Dred.png │ ├── robot_3Dyellow.png │ ├── robot_greenJump.png │ ├── robot_redJump.png │ ├── sand_64.png │ ├── sandstone_64.png │ ├── share1.png │ ├── shield.png │ ├── stone_64.png │ ├── tank_bullet3.png │ ├── tank_bulletFly2.png │ ├── tank_bulletFly3.png │ ├── tiled_64.png │ ├── tracksLarge.png │ ├── warning.png │ └── yellowRobotMoving.png ├── json │ ├── credits.json │ ├── level.json │ └── menu.json └── sounds │ ├── click.mp3 │ ├── explosion.mp3 │ ├── pling.mp3 │ └── shot.mp3 ├── deliver.sh ├── gulpfile.js ├── index.html ├── js ├── config.js ├── main.js ├── prefabs │ ├── animatedSprite.js │ ├── bossRobot.js │ ├── bossRobotSpawner.js │ ├── button.js │ ├── chest.js │ ├── chestSpawner.js │ ├── control.js │ ├── creditsItem.js │ ├── creditsItemSpawner.js │ ├── dpad.js │ ├── droppable.js │ ├── droppableRobot.js │ ├── dust.js │ ├── dustSpawner.js │ ├── earthQuakeSpawner.js │ ├── enemyRobot.js │ ├── enemyRobotSpawner.js │ ├── explosion.js │ ├── explosionSpawner.js │ ├── loot.js │ ├── lootSpawner.js │ ├── menuBackgroundChooser.js │ ├── menuRobot.js │ ├── menuRobotChooser.js │ ├── menuRobotSpawner.js │ ├── messagePrefab.js │ ├── messageSpawner.js │ ├── meteorit.js │ ├── meteoritSpawner.js │ ├── minimap.js │ ├── oil.js │ ├── oilSpawner.js │ ├── pauseDialog.js │ ├── pauseDialogSpawner.js │ ├── prefab.js │ ├── robot.js │ ├── robotSpawner.js │ ├── selectableSprite.js │ ├── smoke.js │ ├── smokeSpawner.js │ ├── soundPrefab.js │ ├── soundSpawner.js │ ├── spawner.js │ ├── statisticsPanel.js │ ├── textPrefab.js │ ├── textSpawner.js │ ├── tileSprite.js │ ├── track.js │ └── trackSpawner.js ├── states │ ├── boot.js │ ├── credits.js │ ├── level.js │ ├── loading.js │ └── menu.js └── utilities │ ├── arrayUtilities.js │ ├── groupUtilities.js │ ├── mathUtilities.js │ └── nameUtilities.js ├── libs └── phaser.js ├── package.json ├── readme.md └── watch.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | #gulpfile.js 4 | dist 5 | #watch.sh 6 | #deliver.sh 7 | node_modules 8 | sketch -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright 2017 Stefan Neidig 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /art/CapturFiles-20170729_102112.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/art/CapturFiles-20170729_102112.png -------------------------------------------------------------------------------- /art/CapturFiles-20170729_102158.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/art/CapturFiles-20170729_102158.png -------------------------------------------------------------------------------- /art/CapturFiles-20170729_102215.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/art/CapturFiles-20170729_102215.png -------------------------------------------------------------------------------- /art/CapturFiles-20170729_102242.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/art/CapturFiles-20170729_102242.png -------------------------------------------------------------------------------- /assets/images/041.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/041.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_1.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_2.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_3.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_4.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_5.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_6.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_7.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_8.png -------------------------------------------------------------------------------- /assets/images/UI_WINDOW_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/UI_WINDOW_9.png -------------------------------------------------------------------------------- /assets/images/arrowLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/arrowLeft.png -------------------------------------------------------------------------------- /assets/images/arrowRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/arrowRight.png -------------------------------------------------------------------------------- /assets/images/blackSmoke21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/blackSmoke21.png -------------------------------------------------------------------------------- /assets/images/buttonStart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/buttonStart.png -------------------------------------------------------------------------------- /assets/images/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/checkmark.png -------------------------------------------------------------------------------- /assets/images/cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/cloud.png -------------------------------------------------------------------------------- /assets/images/crate_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_01.png -------------------------------------------------------------------------------- /assets/images/crate_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_07.png -------------------------------------------------------------------------------- /assets/images/crate_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_08.png -------------------------------------------------------------------------------- /assets/images/crate_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_09.png -------------------------------------------------------------------------------- /assets/images/crate_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_10.png -------------------------------------------------------------------------------- /assets/images/crate_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_11.png -------------------------------------------------------------------------------- /assets/images/crate_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_17.png -------------------------------------------------------------------------------- /assets/images/crate_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_18.png -------------------------------------------------------------------------------- /assets/images/crate_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_19.png -------------------------------------------------------------------------------- /assets/images/crate_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_20.png -------------------------------------------------------------------------------- /assets/images/crate_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_21.png -------------------------------------------------------------------------------- /assets/images/crate_42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_42.png -------------------------------------------------------------------------------- /assets/images/crate_43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_43.png -------------------------------------------------------------------------------- /assets/images/crate_44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_44.png -------------------------------------------------------------------------------- /assets/images/crate_45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/crate_45.png -------------------------------------------------------------------------------- /assets/images/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/cross.png -------------------------------------------------------------------------------- /assets/images/exp2_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/exp2_0.png -------------------------------------------------------------------------------- /assets/images/flatDark03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/flatDark03.png -------------------------------------------------------------------------------- /assets/images/flatDark48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/flatDark48.png -------------------------------------------------------------------------------- /assets/images/flatDark49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/flatDark49.png -------------------------------------------------------------------------------- /assets/images/gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/gear.png -------------------------------------------------------------------------------- /assets/images/grass2_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/grass2_64.png -------------------------------------------------------------------------------- /assets/images/grass_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/grass_64.png -------------------------------------------------------------------------------- /assets/images/greenRobotMoving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/greenRobotMoving.png -------------------------------------------------------------------------------- /assets/images/greyRobotMoving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/greyRobotMoving.png -------------------------------------------------------------------------------- /assets/images/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/information.png -------------------------------------------------------------------------------- /assets/images/jet_pack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/jet_pack.png -------------------------------------------------------------------------------- /assets/images/longCloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/longCloud.png -------------------------------------------------------------------------------- /assets/images/lucifer_cannon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/lucifer_cannon.png -------------------------------------------------------------------------------- /assets/images/medical_pack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/medical_pack.png -------------------------------------------------------------------------------- /assets/images/menuList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/menuList.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_big1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_big1.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_big2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_big2.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_big3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_big3.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_big4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_big4.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_med1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_med1.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_med2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_med2.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_small1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_small1.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_small2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_small2.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_tiny1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_tiny1.png -------------------------------------------------------------------------------- /assets/images/meteorGrey_tiny2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/meteorGrey_tiny2.png -------------------------------------------------------------------------------- /assets/images/mountain2_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/mountain2_64.png -------------------------------------------------------------------------------- /assets/images/mountain_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/mountain_64.png -------------------------------------------------------------------------------- /assets/images/musicOff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/musicOff.png -------------------------------------------------------------------------------- /assets/images/musicOn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/musicOn.png -------------------------------------------------------------------------------- /assets/images/oil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/oil.png -------------------------------------------------------------------------------- /assets/images/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/pause.png -------------------------------------------------------------------------------- /assets/images/redRobotMoving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/redRobotMoving.png -------------------------------------------------------------------------------- /assets/images/robot_3Dblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/robot_3Dblue.png -------------------------------------------------------------------------------- /assets/images/robot_3Dgreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/robot_3Dgreen.png -------------------------------------------------------------------------------- /assets/images/robot_3Dred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/robot_3Dred.png -------------------------------------------------------------------------------- /assets/images/robot_3Dyellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/robot_3Dyellow.png -------------------------------------------------------------------------------- /assets/images/robot_greenJump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/robot_greenJump.png -------------------------------------------------------------------------------- /assets/images/robot_redJump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/robot_redJump.png -------------------------------------------------------------------------------- /assets/images/sand_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/sand_64.png -------------------------------------------------------------------------------- /assets/images/sandstone_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/sandstone_64.png -------------------------------------------------------------------------------- /assets/images/share1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/share1.png -------------------------------------------------------------------------------- /assets/images/shield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/shield.png -------------------------------------------------------------------------------- /assets/images/stone_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/stone_64.png -------------------------------------------------------------------------------- /assets/images/tank_bullet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/tank_bullet3.png -------------------------------------------------------------------------------- /assets/images/tank_bulletFly2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/tank_bulletFly2.png -------------------------------------------------------------------------------- /assets/images/tank_bulletFly3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/tank_bulletFly3.png -------------------------------------------------------------------------------- /assets/images/tiled_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/tiled_64.png -------------------------------------------------------------------------------- /assets/images/tracksLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/tracksLarge.png -------------------------------------------------------------------------------- /assets/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/warning.png -------------------------------------------------------------------------------- /assets/images/yellowRobotMoving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/images/yellowRobotMoving.png -------------------------------------------------------------------------------- /assets/json/credits.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets": { 3 | "uiArrowRight": { 4 | "type": "image", 5 | "source": "assets/images/arrowRight.png" 6 | }, 7 | "uiArrowLeft": { 8 | "type": "image", 9 | "source": "assets/images/arrowLeft.png" 10 | }, 11 | "clickSound": { 12 | "type": "sound", 13 | "source": "assets/sounds/click.mp3" 14 | }, 15 | "uiSettings": { 16 | "type": "image", 17 | "source": "assets/images/gear.png" 18 | }, 19 | "uiInformation": { 20 | "type": "image", 21 | "source": "assets/images/information.png" 22 | }, 23 | "uiStart": { 24 | "type": "image", 25 | "source": "assets/images/buttonStart.png" 26 | }, 27 | "cloud1": { 28 | "type": "image", 29 | "source": "assets/images/longCloud.png" 30 | }, 31 | "cloud2": { 32 | "type": "image", 33 | "source": "assets/images/cloud.png" 34 | }, 35 | "logoRobotRed": { 36 | "type": "image", 37 | "source": "assets/images/robot_redJump.png" 38 | }, 39 | "logoRobotGreen": { 40 | "type": "image", 41 | "source": "assets/images/robot_greenJump.png" 42 | }, 43 | "logoBulletLeft": { 44 | "type": "image", 45 | "source": "assets/images/tank_bulletFly2.png" 46 | }, 47 | "redRobotMoving": { 48 | "type": "spritesheet", 49 | "source": "assets/images/redRobotMoving.png", 50 | "frameWidth": 90, 51 | "frameHeight": 75, 52 | "frames": 2 53 | }, 54 | "yellowRobotMoving": { 55 | "type": "spritesheet", 56 | "source": "assets/images/yellowRobotMoving.png", 57 | "frameWidth": 92, 58 | "frameHeight": 76, 59 | "frames": 2 60 | }, 61 | "greenRobotMoving": { 62 | "type": "spritesheet", 63 | "source": "assets/images/greenRobotMoving.png", 64 | "frameWidth": 79, 65 | "frameHeight": 60, 66 | "frames": 2 67 | }, 68 | "greyRobotMoving": { 69 | "type": "spritesheet", 70 | "source": "assets/images/greyRobotMoving.png", 71 | "frameWidth": 79, 72 | "frameHeight": 75, 73 | "frames": 2 74 | }, 75 | "uiLink": { 76 | "type": "image", 77 | "source": "assets/images/share1.png" 78 | }, 79 | "groundStone": { 80 | "type": "image", 81 | "source": "assets/images/sandstone_64.png" 82 | }, 83 | "groundMountain": { 84 | "type": "image", 85 | "source": "assets/images/mountain_64.png" 86 | }, 87 | "groundMountain2": { 88 | "type": "image", 89 | "source": "assets/images/mountain2_64.png" 90 | }, 91 | "groundDirt": { 92 | "type": "image", 93 | "source": "assets/images/041.png" 94 | }, 95 | "grass2": { 96 | "type": "image", 97 | "source": "assets/images/grass2_64.png" 98 | }, 99 | "stone": { 100 | "type": "image", 101 | "source": "assets/images/stone_64.png" 102 | }, 103 | "groundSand": { 104 | "type": "image", 105 | "source": "assets/images/sand_64.png" 106 | }, 107 | "logoBulletRight": { 108 | "type": "image", 109 | "source": "assets/images/tank_bulletFly3.png" 110 | }, 111 | "groundGrass": { 112 | "type": "image", 113 | "source": "assets/images/grass_64.png" 114 | }, 115 | "groundTiled": { 116 | "type": "image", 117 | "source": "assets/images/tiled_64.png" 118 | }, 119 | "robot3Dblue": { 120 | "type": "image", 121 | "source": "assets/images/robot_3Dblue.png" 122 | }, 123 | "robot3Dgreen": { 124 | "type": "image", 125 | "source": "assets/images/robot_3Dgreen.png" 126 | }, 127 | "robot3Dred": { 128 | "type": "image", 129 | "source": "assets/images/robot_3Dred.png" 130 | }, 131 | "robot3Dyellow": { 132 | "type": "image", 133 | "source": "assets/images/robot_3Dyellow.png" 134 | }, 135 | "bullet": { 136 | "type": "image", 137 | "source": "assets/images/tank_bullet3.png" 138 | }, 139 | "jet_pack": { 140 | "type": "image", 141 | "source": "assets/images/jet_pack.png" 142 | }, 143 | "lucifer_cannon": { 144 | "type": "image", 145 | "source": "assets/images/lucifer_cannon.png" 146 | }, 147 | "medical_pack": { 148 | "type": "image", 149 | "source": "assets/images/medical_pack.png" 150 | }, 151 | "shield": { 152 | "type": "image", 153 | "source": "assets/images/shield.png" 154 | }, 155 | "blackSmoke": { 156 | "type": "image", 157 | "source": "assets/images/blackSmoke21.png" 158 | }, 159 | "tracks": { 160 | "type": "image", 161 | "source": "assets/images/tracksLarge.png" 162 | }, 163 | "explosion2": { 164 | "type": "spritesheet", 165 | "source": "assets/images/exp2_0.png", 166 | "frameWidth": 64, 167 | "frameHeight": 64, 168 | "frames": 16 169 | }, 170 | "uiMenu": { 171 | "type": "image", 172 | "source": "assets/images/menuList.png" 173 | }, 174 | "uiPause": { 175 | "type": "image", 176 | "source": "assets/images/pause.png" 177 | }, 178 | "uiDPad": { 179 | "type": "image", 180 | "source": "assets/images/flatDark03.png" 181 | }, 182 | "uiShootButton": { 183 | "type": "image", 184 | "source": "assets/images/flatDark48.png" 185 | }, 186 | "crate_01": { 187 | "type": "image", 188 | "source": "assets/images/crate_01.png" 189 | }, 190 | "crate_07": { 191 | "type": "image", 192 | "source": "assets/images/crate_07.png" 193 | }, 194 | "crate_08": { 195 | "type": "image", 196 | "source": "assets/images/crate_08.png" 197 | }, 198 | "crate_09": { 199 | "type": "image", 200 | "source": "assets/images/crate_09.png" 201 | }, 202 | "crate_10": { 203 | "type": "image", 204 | "source": "assets/images/crate_10.png" 205 | }, 206 | "crate_11": { 207 | "type": "image", 208 | "source": "assets/images/crate_11.png" 209 | }, 210 | "crate_17": { 211 | "type": "image", 212 | "source": "assets/images/crate_17.png" 213 | }, 214 | "crate_18": { 215 | "type": "image", 216 | "source": "assets/images/crate_18.png" 217 | }, 218 | "crate_19": { 219 | "type": "image", 220 | "source": "assets/images/crate_19.png" 221 | }, 222 | "crate_20": { 223 | "type": "image", 224 | "source": "assets/images/crate_20.png" 225 | }, 226 | "crate_21": { 227 | "type": "image", 228 | "source": "assets/images/crate_21.png" 229 | }, 230 | "crate_42": { 231 | "type": "image", 232 | "source": "assets/images/crate_42.png" 233 | }, 234 | "crate_43": { 235 | "type": "image", 236 | "source": "assets/images/crate_43.png" 237 | }, 238 | "crate_44": { 239 | "type": "image", 240 | "source": "assets/images/crate_44.png" 241 | }, 242 | "crate_45": { 243 | "type": "image", 244 | "source": "assets/images/crate_45.png" 245 | }, 246 | "oil": { 247 | "type": "image", 248 | "source": "assets/images/oil.png" 249 | }, 250 | "meteorGrey_big1": { 251 | "type": "image", 252 | "source": "assets/images/meteorGrey_big1.png" 253 | }, 254 | "meteorGrey_big2": { 255 | "type": "image", 256 | "source": "assets/images/meteorGrey_big2.png" 257 | }, 258 | "meteorGrey_big3": { 259 | "type": "image", 260 | "source": "assets/images/meteorGrey_big3.png" 261 | }, 262 | "meteorGrey_big4": { 263 | "type": "image", 264 | "source": "assets/images/meteorGrey_big4.png" 265 | }, 266 | "meteorGrey_med1": { 267 | "type": "image", 268 | "source": "assets/images/meteorGrey_med1.png" 269 | }, 270 | "meteorGrey_med2": { 271 | "type": "image", 272 | "source": "assets/images/meteorGrey_med2.png" 273 | }, 274 | "meteorGrey_small1": { 275 | "type": "image", 276 | "source": "assets/images/meteorGrey_small1.png" 277 | }, 278 | "meteorGrey_small2": { 279 | "type": "image", 280 | "source": "assets/images/meteorGrey_small2.png" 281 | }, 282 | "meteorGrey_tiny1": { 283 | "type": "image", 284 | "source": "assets/images/meteorGrey_tiny1.png" 285 | }, 286 | "meteorGrey_tiny2": { 287 | "type": "image", 288 | "source": "assets/images/meteorGrey_tiny2.png" 289 | }, 290 | "uiWindow": { 291 | "type": "image", 292 | "source": "assets/images/UI_WINDOW_1.png" 293 | }, 294 | "uiWindowBL": { 295 | "type": "image", 296 | "source": "assets/images/UI_WINDOW_2.png" 297 | }, 298 | "uiWindowB": { 299 | "type": "image", 300 | "source": "assets/images/UI_WINDOW_3.png" 301 | }, 302 | "uiWindowBR": { 303 | "type": "image", 304 | "source": "assets/images/UI_WINDOW_4.png" 305 | }, 306 | "uiWindowR": { 307 | "type": "image", 308 | "source": "assets/images/UI_WINDOW_5.png" 309 | }, 310 | "uiWindowL": { 311 | "type": "image", 312 | "source": "assets/images/UI_WINDOW_6.png" 313 | }, 314 | "uiWindowTR": { 315 | "type": "image", 316 | "source": "assets/images/UI_WINDOW_7.png" 317 | }, 318 | "uiWindowTL": { 319 | "type": "image", 320 | "source": "assets/images/UI_WINDOW_8.png" 321 | }, 322 | "uiWindowT": { 323 | "type": "image", 324 | "source": "assets/images/UI_WINDOW_9.png" 325 | }, 326 | "uiCross": { 327 | "type": "image", 328 | "source": "assets/images/cross.png" 329 | }, 330 | "uiCheckmark": { 331 | "type": "image", 332 | "source": "assets/images/checkmark.png" 333 | } 334 | }, 335 | "groups": [ 336 | "background", 337 | "spawners", 338 | "credits", 339 | "hud" 340 | ], 341 | "prefabs": { 342 | "background": { 343 | "type": "tileSprite", 344 | "position": { 345 | "x": 0, 346 | "y": 0 347 | }, 348 | "properties": { 349 | "group": "background", 350 | "key": "groundGrass", 351 | "size": { 352 | "width": 640, 353 | "height": 360 354 | }, 355 | "fixedToCamera": true 356 | } 357 | }, 358 | "menuButton": { 359 | "type": "button", 360 | "position": { 361 | "x": 24, 362 | "y": 24 363 | }, 364 | "properties": { 365 | "group": "hud", 366 | "key": "uiMenu", 367 | "anchor": { 368 | "x": 0.5, 369 | "y": 0.5 370 | } 371 | } 372 | }, 373 | "caption": { 374 | "type": "text", 375 | "position": { 376 | "x": 320, 377 | "y": 24 378 | }, 379 | "properties": { 380 | "text": "Credits", 381 | "group": "credits", 382 | "fixedToCamera": true, 383 | "style": { 384 | "font": "25pt Arial", 385 | "fill": "#ffffff", 386 | "align": "center" 387 | }, 388 | "anchor": { 389 | "x": 0.5, 390 | "y": 0.5 391 | }, 392 | "shadow": true 393 | } 394 | }, 395 | "text": { 396 | "type": "text", 397 | "position": { 398 | "x": 48, 399 | "y": 48 400 | }, 401 | "properties": { 402 | "text": "This is my contribution for the 2017 Phaser hackathon hosted by Zenva. The objective was to create a fun game using only the Phaserjs game engine and a predefined set of assets. Furthermore you only had 500 KB of space for the whole game.\n\nMy take was a game heavily inspired by Slither.io and is called Bots. You are a robot driving in a huge world packed with other robots with the same goal - killing each other. Dive into the vivid world of Bots and claim your place!\n\nAnyway, this challenge was real fun! I want to thank Zenva for hosting such a hackathon to begin with. Furthermore I want to thank all people I took the assets from. Those are listed below with the respective assets I used from them. And finally I want to thank my wife, who immensely supported me in my endeavour by not only actively playing and testing the game but also by understanding and maintaining her patience. I love you!", 403 | "group": "credits", 404 | "fixedToCamera": true, 405 | "lineSpacing": -5, 406 | "style": { 407 | "font": "10pt Arial", 408 | "fill": "#ffffff", 409 | "align": "left", 410 | "wordWrap": true, 411 | "wordWrapWidth": 544 412 | }, 413 | "anchor": { 414 | "x": 0, 415 | "y": 0 416 | }, 417 | "shadow": true 418 | } 419 | }, 420 | "thankYouText": { 421 | "type": "text", 422 | "position": { 423 | "x": 320, 424 | "y": 1165 425 | }, 426 | "properties": { 427 | "text": "Thanks for playing!", 428 | "group": "credits", 429 | "fixedToCamera": true, 430 | "lineSpacing": -5, 431 | "style": { 432 | "font": "24pt Arial", 433 | "fill": "#ffffff", 434 | "align": "center", 435 | "wordWrap": true, 436 | "wordWrapWidth": 544 437 | }, 438 | "anchor": { 439 | "x": 0.5, 440 | "y": 0 441 | }, 442 | "shadow": true 443 | } 444 | }, 445 | "creditsItemSpawner": { 446 | "type": "creditsItemSpawner", 447 | "position": { 448 | "x": 0, 449 | "y": 280 450 | }, 451 | "properties": { 452 | "group": "spawners", 453 | "pool": "credits", 454 | "key": "", 455 | "spacing": 16, 456 | "margin": 48, 457 | "columnCount": 3, 458 | "mode": "once", 459 | "spawnTimeInSeconds": { 460 | "min": 0, 461 | "max": 0 462 | }, 463 | "items": [ 464 | { 465 | "key": "logoRobotRed", 466 | "title": "Robot pack", 467 | "link": "http://kenney.nl/assets/robot-pack", 468 | "author": "Kenney" 469 | }, 470 | { 471 | "key": "bullet", 472 | "title": "Tanks", 473 | "link": "http://kenney.nl/assets/tanks", 474 | "author": "Kenney" 475 | }, 476 | { 477 | "key": "groundTiled", 478 | "title": "Stone blocks", 479 | "link": "https://opengameart.org/content/stoneblocks", 480 | "author": "SpriteAttack" 481 | }, 482 | { 483 | "key": "lucifer_cannon", 484 | "title": "Powers Icons", 485 | "link": "https://opengameart.org/content/powers-icons", 486 | "author": "Clint Bellanger" 487 | }, 488 | { 489 | "key": "explosion2", 490 | "title": "Explosion", 491 | "link": "https://opengameart.org/content/explosion", 492 | "author": "Cuzco" 493 | }, 494 | { 495 | "key": "blackSmoke", 496 | "title": "Smoke Particle Assets", 497 | "link": "https://opengameart.org/content/smoke-particle-assets", 498 | "author": "Kenney" 499 | }, 500 | { 501 | "key": "groundGrass", 502 | "title": "Topdown Tanks", 503 | "link": "https://kenney.nl/assets/topdown-tanks", 504 | "author": "Kenney" 505 | }, 506 | { 507 | "key": "uiStart", 508 | "title": "Game icons", 509 | "link": "https://opengameart.org/content/game-icons", 510 | "author": "Kenney" 511 | }, 512 | { 513 | "key": "cloud2", 514 | "title": "Cloud set", 515 | "link": "https://opengameart.org/content/cloud-set", 516 | "author": "Sam" 517 | }, 518 | { 519 | "key": "uiDPad", 520 | "title": "Onscreen - Controls", 521 | "link": "http://kenney.nl/assets/onscreen-controls", 522 | "author": "Kenney" 523 | }, 524 | { 525 | "key": "crate_10", 526 | "title": "Sokoban (100+ Tiles)", 527 | "link": "https://opengameart.org/content/sokoban-100-tiles", 528 | "author": "Kenney" 529 | }, 530 | { 531 | "key": "meteorGrey_big1", 532 | "title": "Space Shooter Redux", 533 | "link": "https://opengameart.org/content/space-shooter-redux", 534 | "author": "Kenney" 535 | }, 536 | { 537 | "key": "groundDirt", 538 | "title": "50 free textures 5 - with normalmaps", 539 | "link": "https://opengameart.org/content/50-free-textures-5-with-normalmaps", 540 | "author": "rubberduck" 541 | } 542 | ] 543 | } 544 | }, 545 | "clickSound": { 546 | "type": "sound", 547 | "position": { 548 | "x": 0, 549 | "y": 0 550 | }, 551 | "properties": { 552 | "key": "clickSound" 553 | } 554 | } 555 | } 556 | } -------------------------------------------------------------------------------- /assets/json/menu.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets": { 3 | "groundStone": { 4 | "type": "image", 5 | "source": "assets/images/sandstone_64.png" 6 | }, 7 | "groundMountain": { 8 | "type": "image", 9 | "source": "assets/images/mountain_64.png" 10 | }, 11 | "groundMountain2": { 12 | "type": "image", 13 | "source": "assets/images/mountain2_64.png" 14 | }, 15 | "grass2": { 16 | "type": "image", 17 | "source": "assets/images/grass2_64.png" 18 | }, 19 | "groundDirt": { 20 | "type": "image", 21 | "source": "assets/images/041.png" 22 | }, 23 | "stone": { 24 | "type": "image", 25 | "source": "assets/images/stone_64.png" 26 | }, 27 | "groundSand": { 28 | "type": "image", 29 | "source": "assets/images/sand_64.png" 30 | }, 31 | "groundGrass": { 32 | "type": "image", 33 | "source": "assets/images/grass_64.png" 34 | }, 35 | "clickSound": { 36 | "type": "sound", 37 | "source": "assets/sounds/click.mp3" 38 | }, 39 | "groundTiled": { 40 | "type": "image", 41 | "source": "assets/images/tiled_64.png" 42 | }, 43 | "uiArrowRight": { 44 | "type": "image", 45 | "source": "assets/images/arrowRight.png" 46 | }, 47 | "uiArrowLeft": { 48 | "type": "image", 49 | "source": "assets/images/arrowLeft.png" 50 | }, 51 | "uiSettings": { 52 | "type": "image", 53 | "source": "assets/images/gear.png" 54 | }, 55 | "uiInformation": { 56 | "type": "image", 57 | "source": "assets/images/information.png" 58 | }, 59 | "uiMusicOn": { 60 | "type": "image", 61 | "source": "assets/images/musicOn.png" 62 | }, 63 | "uiMusicOff": { 64 | "type": "image", 65 | "source": "assets/images/musicOff.png" 66 | }, 67 | "uiStart": { 68 | "type": "image", 69 | "source": "assets/images/buttonStart.png" 70 | }, 71 | "cloud1": { 72 | "type": "image", 73 | "source": "assets/images/longCloud.png" 74 | }, 75 | "cloud2": { 76 | "type": "image", 77 | "source": "assets/images/cloud.png" 78 | }, 79 | "logoRobotRed": { 80 | "type": "image", 81 | "source": "assets/images/robot_redJump.png" 82 | }, 83 | "logoRobotGreen": { 84 | "type": "image", 85 | "source": "assets/images/robot_greenJump.png" 86 | }, 87 | "logoBulletLeft": { 88 | "type": "image", 89 | "source": "assets/images/tank_bulletFly2.png" 90 | }, 91 | "robot3Dblue": { 92 | "type": "image", 93 | "source": "assets/images/robot_3Dblue.png" 94 | }, 95 | "robot3Dgreen": { 96 | "type": "image", 97 | "source": "assets/images/robot_3Dgreen.png" 98 | }, 99 | "robot3Dred": { 100 | "type": "image", 101 | "source": "assets/images/robot_3Dred.png" 102 | }, 103 | "robot3Dyellow": { 104 | "type": "image", 105 | "source": "assets/images/robot_3Dyellow.png" 106 | }, 107 | "logoBulletRight": { 108 | "type": "image", 109 | "source": "assets/images/tank_bulletFly3.png" 110 | }, 111 | "redRobotMoving": { 112 | "type": "spritesheet", 113 | "source": "assets/images/redRobotMoving.png", 114 | "frameWidth": 90, 115 | "frameHeight": 75, 116 | "frames": 2 117 | }, 118 | "yellowRobotMoving": { 119 | "type": "spritesheet", 120 | "source": "assets/images/yellowRobotMoving.png", 121 | "frameWidth": 92, 122 | "frameHeight": 76, 123 | "frames": 2 124 | }, 125 | "greenRobotMoving": { 126 | "type": "spritesheet", 127 | "source": "assets/images/greenRobotMoving.png", 128 | "frameWidth": 79, 129 | "frameHeight": 60, 130 | "frames": 2 131 | }, 132 | "greyRobotMoving": { 133 | "type": "spritesheet", 134 | "source": "assets/images/greyRobotMoving.png", 135 | "frameWidth": 79, 136 | "frameHeight": 75, 137 | "frames": 2 138 | }, 139 | "uiWindow": { 140 | "type": "image", 141 | "source": "assets/images/UI_WINDOW_1.png" 142 | }, 143 | "uiWindowBL": { 144 | "type": "image", 145 | "source": "assets/images/UI_WINDOW_2.png" 146 | }, 147 | "uiWindowB": { 148 | "type": "image", 149 | "source": "assets/images/UI_WINDOW_3.png" 150 | }, 151 | "uiWindowBR": { 152 | "type": "image", 153 | "source": "assets/images/UI_WINDOW_4.png" 154 | }, 155 | "uiWindowR": { 156 | "type": "image", 157 | "source": "assets/images/UI_WINDOW_5.png" 158 | }, 159 | "uiWindowL": { 160 | "type": "image", 161 | "source": "assets/images/UI_WINDOW_6.png" 162 | }, 163 | "uiWindowTR": { 164 | "type": "image", 165 | "source": "assets/images/UI_WINDOW_7.png" 166 | }, 167 | "uiWindowTL": { 168 | "type": "image", 169 | "source": "assets/images/UI_WINDOW_8.png" 170 | }, 171 | "uiWindowT": { 172 | "type": "image", 173 | "source": "assets/images/UI_WINDOW_9.png" 174 | }, 175 | "uiCross": { 176 | "type": "image", 177 | "source": "assets/images/cross.png" 178 | } 179 | }, 180 | "groups": [ 181 | "background", 182 | "spawners", 183 | "shadows", 184 | "robots", 185 | "robotTexts", 186 | "logo", 187 | "chooser", 188 | "selectables", 189 | "hud" 190 | ], 191 | "prefabs": { 192 | "background": { 193 | "type": "tileSprite", 194 | "position": { 195 | "x": 0, 196 | "y": 0 197 | }, 198 | "properties": { 199 | "group": "background", 200 | "key": "groundGrass", 201 | "size": { 202 | "width": 640, 203 | "height": 360 204 | }, 205 | "fixedToCamera": true 206 | } 207 | }, 208 | "redRobotMovingText": { 209 | "type": "text", 210 | "position": { 211 | "x": 0, 212 | "y": -92 213 | }, 214 | "properties": { 215 | "text": "Easy", 216 | "group": "robotTexts", 217 | "fixedToCamera": true, 218 | "style": { 219 | "font": "18pt Arial", 220 | "fill": "#ffffff", 221 | "align": "center" 222 | }, 223 | "anchor": { 224 | "x": 0.5, 225 | "y": 0.5 226 | }, 227 | "shadow": true 228 | } 229 | }, 230 | "greenRobotMovingText": { 231 | "type": "text", 232 | "position": { 233 | "x": 0, 234 | "y": -92 235 | }, 236 | "properties": { 237 | "text": "Medium", 238 | "group": "robotTexts", 239 | "fixedToCamera": true, 240 | "style": { 241 | "font": "18pt Arial", 242 | "fill": "#ffffff", 243 | "align": "center" 244 | }, 245 | "anchor": { 246 | "x": 0.5, 247 | "y": 0.5 248 | }, 249 | "shadow": true 250 | } 251 | }, 252 | "yellowRobotMovingText": { 253 | "type": "text", 254 | "position": { 255 | "x": 0, 256 | "y": -92 257 | }, 258 | "properties": { 259 | "text": "Hard", 260 | "group": "robotTexts", 261 | "fixedToCamera": true, 262 | "style": { 263 | "font": "18pt Arial", 264 | "fill": "#ffffff", 265 | "align": "center" 266 | }, 267 | "anchor": { 268 | "x": 0.5, 269 | "y": 0.5 270 | }, 271 | "shadow": true 272 | } 273 | }, 274 | "greyRobotMovingText": { 275 | "type": "text", 276 | "position": { 277 | "x": 0, 278 | "y": -92 279 | }, 280 | "properties": { 281 | "text": "Very hard", 282 | "group": "robotTexts", 283 | "fixedToCamera": true, 284 | "style": { 285 | "font": "18pt Arial", 286 | "fill": "#ffffff", 287 | "align": "center" 288 | }, 289 | "anchor": { 290 | "x": 0.5, 291 | "y": 0.5 292 | }, 293 | "shadow": true 294 | } 295 | }, 296 | "logoBulletLeft": { 297 | "type": "sprite", 298 | "position": { 299 | "x": 374, 300 | "y": 62 301 | }, 302 | "properties": { 303 | "group": "logo", 304 | "key": "logoBulletLeft", 305 | "anchor": { 306 | "x": 0.5, 307 | "y": 0.5 308 | }, 309 | "angle": 8, 310 | "mirror": { 311 | "x": true 312 | }, 313 | "alpha": 0 314 | } 315 | }, 316 | "logoBulletRight": { 317 | "type": "sprite", 318 | "position": { 319 | "x": 342, 320 | "y": 80 321 | }, 322 | "properties": { 323 | "group": "logo", 324 | "key": "logoBulletRight", 325 | "anchor": { 326 | "x": 0.5, 327 | "y": 0.5 328 | }, 329 | "angle": 343, 330 | "scale": { 331 | "x": 0.7, 332 | "y": 0.7 333 | }, 334 | "alpha": 0 335 | } 336 | }, 337 | "logoRobotRed": { 338 | "type": "sprite", 339 | "position": { 340 | "x": 374, 341 | "y": 62 342 | }, 343 | "properties": { 344 | "group": "logo", 345 | "key": "logoRobotRed", 346 | "anchor": { 347 | "x": 0.5, 348 | "y": 0.5 349 | }, 350 | "angle": 8, 351 | "mirror": { 352 | "x": true 353 | }, 354 | "alpha": 0 355 | } 356 | }, 357 | "logoRobotGreen": { 358 | "type": "sprite", 359 | "position": { 360 | "x": 342, 361 | "y": 80 362 | }, 363 | "properties": { 364 | "group": "logo", 365 | "key": "logoRobotGreen", 366 | "anchor": { 367 | "x": 0.5, 368 | "y": 0.5 369 | }, 370 | "angle": 343, 371 | "scale": { 372 | "x": 0.9, 373 | "y": 0.9 374 | }, 375 | "alpha": 0 376 | } 377 | }, 378 | "middleCloud": { 379 | "type": "sprite", 380 | "position": { 381 | "x": 320, 382 | "y": 100 383 | }, 384 | "properties": { 385 | "group": "logo", 386 | "key": "cloud1", 387 | "anchor": { 388 | "x": 0.5, 389 | "y": 0.5 390 | }, 391 | "alpha": 0 392 | } 393 | }, 394 | "leftCloud": { 395 | "type": "sprite", 396 | "position": { 397 | "x": -211, 398 | "y": 122 399 | }, 400 | "properties": { 401 | "group": "logo", 402 | "key": "cloud2", 403 | "anchor": { 404 | "x": 0, 405 | "y": 0.5 406 | } 407 | } 408 | }, 409 | "rightCloud": { 410 | "type": "sprite", 411 | "position": { 412 | "x": 706, 413 | "y": 122 414 | }, 415 | "properties": { 416 | "group": "logo", 417 | "key": "cloud2", 418 | "anchor": { 419 | "x": 0.5, 420 | "y": 0.5 421 | }, 422 | "scale": { 423 | "x": 0.63, 424 | "y": 0.63 425 | }, 426 | "angle": 180 427 | } 428 | }, 429 | "redRobotMoving": { 430 | "type": "animatedSprite", 431 | "position": { 432 | "x": 320, 433 | "y": 180 434 | }, 435 | "properties": { 436 | "group": "chooser", 437 | "key": "redRobotMoving", 438 | "secondKey": "robot3Dred", 439 | "anchor": { 440 | "x": 0.5, 441 | "y": 1 442 | }, 443 | "animations": [ 444 | { 445 | "name": "driving", 446 | "frameRate": 10, 447 | "frames": [ 448 | 0, 449 | 1 450 | ], 451 | "loop": true, 452 | "killOnComplete": false 453 | } 454 | ] 455 | } 456 | }, 457 | "yellowRobotMoving": { 458 | "type": "animatedSprite", 459 | "position": { 460 | "x": 180, 461 | "y": 180 462 | }, 463 | "properties": { 464 | "group": "chooser", 465 | "key": "yellowRobotMoving", 466 | "secondKey": "robot3Dyellow", 467 | "anchor": { 468 | "x": 0.5, 469 | "y": 1 470 | }, 471 | "animations": [ 472 | { 473 | "name": "driving", 474 | "frameRate": 10, 475 | "frames": [ 476 | 0, 477 | 1 478 | ], 479 | "loop": true, 480 | "killOnComplete": false 481 | } 482 | ] 483 | } 484 | }, 485 | "greenRobotMoving": { 486 | "type": "animatedSprite", 487 | "position": { 488 | "x": 420, 489 | "y": 180 490 | }, 491 | "properties": { 492 | "group": "chooser", 493 | "key": "greenRobotMoving", 494 | "secondKey": "robot3Dgreen", 495 | "anchor": { 496 | "x": 0.5, 497 | "y": 1 498 | }, 499 | "animations": [ 500 | { 501 | "name": "driving", 502 | "frameRate": 10, 503 | "frames": [ 504 | 0, 505 | 1 506 | ], 507 | "loop": true, 508 | "killOnComplete": false 509 | } 510 | ] 511 | } 512 | }, 513 | "greyRobotMoving": { 514 | "type": "animatedSprite", 515 | "position": { 516 | "x": 550, 517 | "y": 180 518 | }, 519 | "properties": { 520 | "group": "chooser", 521 | "key": "greyRobotMoving", 522 | "secondKey": "robot3Dblue", 523 | "anchor": { 524 | "x": 0.5, 525 | "y": 1 526 | }, 527 | "animations": [ 528 | { 529 | "name": "driving", 530 | "frameRate": 10, 531 | "frames": [ 532 | 0, 533 | 1 534 | ], 535 | "loop": true, 536 | "killOnComplete": false 537 | } 538 | ] 539 | } 540 | }, 541 | "menuChooser": { 542 | "type": "menuRobotChooser", 543 | "position": { 544 | "x": 320, 545 | "y": 290 546 | }, 547 | "properties": { 548 | "group": "spawners", 549 | "pool": "chooser", 550 | "robots": [ 551 | "redRobotMoving", 552 | "greenRobotMoving", 553 | "yellowRobotMoving", 554 | "greyRobotMoving" 555 | ] 556 | } 557 | }, 558 | "menuRobotSpawner": { 559 | "type": "menuRobotSpawner", 560 | "position": { 561 | "x": 0, 562 | "y": 0 563 | }, 564 | "properties": { 565 | "key": "", 566 | "group": "spawners", 567 | "pool": "robots", 568 | "mode": "limited", 569 | "limit": 3, 570 | "spawnTimeInSeconds": { 571 | "min": 0, 572 | "max": 1 573 | } 574 | } 575 | }, 576 | "informationButton": { 577 | "type": "button", 578 | "position": { 579 | "x": 616, 580 | "y": 24 581 | }, 582 | "properties": { 583 | "group": "hud", 584 | "key": "uiInformation", 585 | "anchor": { 586 | "x": 0.5, 587 | "y": 0.5 588 | } 589 | } 590 | }, 591 | "soundButton": { 592 | "type": "button", 593 | "position": { 594 | "x": 616, 595 | "y": 72 596 | }, 597 | "properties": { 598 | "group": "hud", 599 | "key": "uiMusicOn", 600 | "anchor": { 601 | "x": 0.5, 602 | "y": 0.5 603 | } 604 | } 605 | }, 606 | "leftButton": { 607 | "type": "button", 608 | "position": { 609 | "x": 240, 610 | "y": 250 611 | }, 612 | "properties": { 613 | "group": "hud", 614 | "key": "uiArrowLeft", 615 | "anchor": { 616 | "x": 0.5, 617 | "y": 0.5 618 | } 619 | } 620 | }, 621 | "rightButton": { 622 | "type": "button", 623 | "position": { 624 | "x": 400, 625 | "y": 250 626 | }, 627 | "properties": { 628 | "group": "hud", 629 | "key": "uiArrowRight", 630 | "anchor": { 631 | "x": 0.5, 632 | "y": 0.5 633 | } 634 | } 635 | }, 636 | "startButton": { 637 | "type": "button", 638 | "position": { 639 | "x": 320, 640 | "y": 328 641 | }, 642 | "properties": { 643 | "group": "hud", 644 | "key": "uiStart", 645 | "anchor": { 646 | "x": 0.5, 647 | "y": 0.5 648 | } 649 | } 650 | }, 651 | "menuBackgroundChooser": { 652 | "type": "menuBackgroundChooser", 653 | "position": { 654 | "x": 32, 655 | "y": 328 656 | }, 657 | "properties": { 658 | "group": "spawners", 659 | "pool": "selectables", 660 | "columns": 4, 661 | "anchor": { 662 | "x": 0.5, 663 | "y": 0.5 664 | }, 665 | "scale": { 666 | "x": 0.5, 667 | "y": 0.5 668 | }, 669 | "shadow": true, 670 | "spacing": 16, 671 | "backgrounds": [ 672 | "stone", 673 | "grass2", 674 | "groundDirt", 675 | "groundStone", 676 | "groundMountain", 677 | "groundSand", 678 | "groundGrass", 679 | "groundTiled", 680 | "groundMountain2" 681 | ] 682 | } 683 | }, 684 | "pauseDialogSpawner": { 685 | "type": "pauseDialogSpawner", 686 | "position": { 687 | "x": 0, 688 | "y": 0 689 | }, 690 | "properties": { 691 | "key": "", 692 | "group": "spawners", 693 | "pool": "hud", 694 | "mode": "never", 695 | "size": { 696 | "x": 200, 697 | "y": 80 698 | } 699 | } 700 | }, 701 | "clickSound": { 702 | "type": "sound", 703 | "position": { 704 | "x": 0, 705 | "y": 0 706 | }, 707 | "properties": { 708 | "key": "clickSound" 709 | } 710 | }, 711 | "hintText": { 712 | "type": "text", 713 | "position": { 714 | "x": 632, 715 | "y": 360 716 | }, 717 | "properties": { 718 | "group": "hud", 719 | "text": "Tip: Press shift in game to open the HUD!", 720 | "style": { 721 | "font": "10pt Arial", 722 | "fill": "#ffffff", 723 | "align": "right" 724 | }, 725 | "anchor": { 726 | "x": 1, 727 | "y": 1 728 | }, 729 | "shadow": true 730 | } 731 | } 732 | } 733 | } -------------------------------------------------------------------------------- /assets/sounds/click.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/sounds/click.mp3 -------------------------------------------------------------------------------- /assets/sounds/explosion.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/sounds/explosion.mp3 -------------------------------------------------------------------------------- /assets/sounds/pling.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/sounds/pling.mp3 -------------------------------------------------------------------------------- /assets/sounds/shot.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasheck0/robots/4767138d127cb6209d685a99fd7acb8e68483366/assets/sounds/shot.mp3 -------------------------------------------------------------------------------- /deliver.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | gulp transpile minify linkPhaser calculateSize copy 4 | #gulp transpile minifyAssets minify linkPhaser calculateSize copy -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | const gulp = require('gulp'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | const opn = require('opn'); 9 | const minify = require('gulp-minify'); 10 | const babel = require('gulp-babel'); 11 | const getFolderSize = require('get-folder-size'); 12 | const imagemin = require('gulp-imagemin'); 13 | 14 | gulp.task('minifyAssets', () => 15 | gulp.src('assets/images/*') 16 | .pipe(imagemin()) 17 | .pipe(gulp.dest('assets2')) 18 | ); 19 | 20 | gulp.task('copy', ['minify', 'transpile', 'linkPhaser', 'calculateSize'], () => { 21 | const destination = '/Applications/MAMP/htdocs/dasheck-hackathon-phaser'; 22 | const sources = ['dist', 'assets'].reverse(); 23 | 24 | sources.forEach(source => copyFolderRecursiveSync(path.join(process.cwd(), source), destination)); 25 | copyFileSync(path.join(process.cwd(), 'index.html'), destination); 26 | }); 27 | 28 | gulp.task('open', () => { 29 | opn('http://localhost:8888/dasheck-hackathon-phaser'); 30 | }); 31 | 32 | gulp.task('minify', ['transpile'], (done) => { 33 | gulp.src('dist/**/*.js') 34 | .pipe(minify({ 35 | ext: { 36 | min: '.js' 37 | }, 38 | noSource: true, 39 | preserveComments: () => false, 40 | ignoreFiles: ['phaser.js'] 41 | })) 42 | .pipe(gulp.dest('dist')) 43 | .on('end', done); 44 | }); 45 | 46 | gulp.task('calculateSize', ['minify', 'transpile'], (done) => { 47 | getFolderSize(path.join(process.cwd(), 'dist'), /phaser.js/g, (error, distSize) => { 48 | getFolderSize(path.join(process.cwd(), 'assets'), (error, assetsSize) => { 49 | console.log('Size:', ((distSize + assetsSize) / 1024.0).toFixed(2), 'KB'); 50 | done(); 51 | }); 52 | }); 53 | }); 54 | 55 | gulp.task('transpile', () => { 56 | deleteFolderRecursive(path.join(process.cwd(), 'dist')); 57 | return gulp.src('js/**/*.js') 58 | .pipe(babel({ 59 | presets: ['es2015'] 60 | })) 61 | .pipe(gulp.dest('dist')); 62 | }); 63 | 64 | gulp.task('linkPhaser', ['minify'], () => { 65 | fs.mkdirSync(path.join(process.cwd(), 'dist/libs')); 66 | copyFileSync(path.join(process.cwd(), 'libs/phaser.js'), path.join(process.cwd(), 'dist/libs/phaser.js')); 67 | }); 68 | 69 | function copyFileSync(source, target) { 70 | 71 | var targetFile = target; 72 | 73 | //if target is a directory a new file with the same name will be created 74 | if (fs.existsSync(target)) { 75 | if (fs.lstatSync(target).isDirectory()) { 76 | targetFile = path.join(target, path.basename(source)); 77 | } 78 | } 79 | 80 | fs.writeFileSync(targetFile, fs.readFileSync(source)); 81 | } 82 | 83 | function copyFolderRecursiveSync(source, target) { 84 | var files = []; 85 | 86 | //check if folder needs to be created or integrated 87 | var targetFolder = path.join(target, path.basename(source)); 88 | if (!fs.existsSync(targetFolder)) { 89 | fs.mkdirSync(targetFolder); 90 | } 91 | 92 | //copy 93 | if (fs.lstatSync(source).isDirectory()) { 94 | files = fs.readdirSync(source); 95 | files.forEach(function (file) { 96 | var curSource = path.join(source, file); 97 | if (fs.lstatSync(curSource).isDirectory()) { 98 | copyFolderRecursiveSync(curSource, targetFolder); 99 | } else { 100 | copyFileSync(curSource, targetFolder); 101 | } 102 | }); 103 | } 104 | } 105 | 106 | function deleteFolderRecursive(path) { 107 | if (fs.existsSync(path)) { 108 | fs.readdirSync(path).forEach(function (file, index) { 109 | var curPath = path + "/" + file; 110 | if (fs.lstatSync(curPath).isDirectory()) { // recurse 111 | deleteFolderRecursive(curPath); 112 | } else { // delete file 113 | fs.unlinkSync(curPath); 114 | } 115 | }); 116 | fs.rmdirSync(path); 117 | } 118 | }; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | Bots 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /js/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 16/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.debug = true; 8 | Bots.scale = 0.3; 9 | Bots.worldSize = new Phaser.Point(3000, 3000); 10 | Bots.screenSize = new Phaser.Point(640, 360); 11 | Bots.cameraPadding = 100; 12 | Bots.minimapWidth = Bots.screenSize.x * 0.25; 13 | Bots.minimapHeight = (Bots.minimapWidth * Bots.worldSize.y) / Bots.worldSize.x; 14 | Bots.minimapPadding = new Phaser.Point(16, 16); 15 | Bots.killCount = 0; 16 | Bots.deathCount = 0; 17 | Bots.soundsEnabled = true; 18 | Bots.background = ''; -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | window.onload = function () { 9 | var game = new Phaser.Game(640, 360, Phaser.CANVAS); 10 | 11 | game.state.add('boot', new Bots.Boot()); 12 | game.state.add('loading', new Bots.Loading()); 13 | game.state.add('level', new Bots.Level()); 14 | game.state.add('menu', new Bots.Menu()); 15 | game.state.add('credits', new Bots.Credits()); 16 | 17 | game.state.start('boot', true, false, { 18 | menu: 'assets/json/menu.json', 19 | level: 'assets/json/level.json', 20 | credits: 'assets/json/credits.json' 21 | }); 22 | }; -------------------------------------------------------------------------------- /js/prefabs/animatedSprite.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 22/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.AnimatedSprite = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | (properties.animations || []).forEach((animation) => { 11 | this.animations.add(animation.name, properties.frames, properties.frameRate, properties.loop, properties.killOnComplete); 12 | }) 13 | }; 14 | 15 | Bots.AnimatedSprite.prototype = Object.create(Bots.Prefab.prototype); 16 | Bots.AnimatedSprite.prototype.constructor = Bots.AnimatedSprite; 17 | 18 | Bots.AnimatedSprite.prototype.play = function (name) { 19 | const animation = this.properties.animations.filter(animation => animation.name === name)[0]; 20 | if (animation) { 21 | this.animations.play(animation.name, animation.frameRate, animation.loop, animation.killOnComplete); 22 | } 23 | } -------------------------------------------------------------------------------- /js/prefabs/bossRobot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 16/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.BossRobot = function (state, name, position, properties) { 8 | Bots.DroppableRobot.call(this, state, name, position, properties); 9 | 10 | this.boss = true; 11 | this.currentDestination = null; 12 | this.body.mass = 100; 13 | }; 14 | 15 | Bots.BossRobot.prototype = Object.create(Bots.DroppableRobot.prototype); 16 | Bots.BossRobot.prototype.constructor = Bots.BossRobot; 17 | 18 | Bots.BossRobot.prototype.initializeObject = function () { 19 | Bots.DroppableRobot.prototype.initializeObject(this); 20 | 21 | this.properties.rotationSpeed = this.properties.speed / 17; 22 | this.properties.maxSpeed = this.properties.speed * 2; 23 | this.body.maxVelocity.setTo(this.properties.maxSpeed); 24 | 25 | this.smokeTimer = this.game.time.events.loop(500, ()=> getMemberByName(this.state.groups.spawners, 'smokeSpawner').spawn(this), this); 26 | this.checkSurroundingsTimer = this.game.time.events.loop(1000, this.attackSurrounding, this); 27 | this.jumpTimer = this.game.time.events.add(11284, this.jump, this); 28 | this.meteoritTimer = this.game.time.events.add(17420, this.initiateMeteoritHail, this); 29 | } 30 | 31 | Bots.BossRobot.prototype.getClosestMemberOfGroup = function (group) { 32 | let closestMember = null; 33 | let closestDistance = Number.MAX_VALUE; 34 | 35 | group.forEachAlive((member) => { 36 | if (member.name !== this.name) { 37 | const distance = this.game.physics.arcade.distanceBetween(this, member); 38 | if (distance < closestDistance) { 39 | closestDistance = distance; 40 | closestMember = member; 41 | } 42 | } 43 | }); 44 | 45 | return { 46 | member: closestMember, 47 | distance: closestDistance, 48 | present: closestMember !== null 49 | }; 50 | } 51 | 52 | Bots.BossRobot.prototype.update = function () { 53 | Bots.DroppableRobot.prototype.update(this); 54 | 55 | if (!this.isDead) { 56 | if (!this.currentDestination || this.game.physics.arcade.distanceToXY(this, this.currentDestination.x, this.currentDestination.y) <= 50) { 57 | this.currentDestination = new Phaser.Point(randomInteger(Bots.worldSize.x) - Bots.worldSize.x / 2, randomInteger(Bots.worldSize.y) - Bots.worldSize.y / 2); 58 | const offset = -60 * this.game.rnd.realInRange(this.properties.accuracy, 1) + 60; 59 | } 60 | 61 | if (this.currentDestination) { 62 | this.rotation = this.game.physics.arcade.angleToXY(this, this.currentDestination.x, this.currentDestination.y, true); 63 | this.game.physics.arcade.moveToObject(this, this.currentDestination, this.properties.maxSpeed); 64 | } 65 | // 66 | // if (!this.checkSurroundingsTimer) { 67 | // this.checkSurroundingsTimer = this.game.time.events.loop(1000, this.attackSurrounding, this); 68 | // } 69 | } 70 | } 71 | 72 | Bots.BossRobot.prototype.attackNearbyObjects = function (group) { 73 | if (!this.attackedNearbyObjectInTurn) { 74 | group.forEachAlive((object) => { 75 | if (this.game.physics.arcade.distanceBetween(this, object) < this.properties.shootRange && this.game.rnd.frac() < this.properties.sloppiness) { 76 | this.rotation = this.game.physics.arcade.angleBetween(this, object); 77 | Bots.DroppableRobot.prototype.fire.call(this); 78 | this.attackedNearbyObjectInTurn = true; 79 | return; 80 | } 81 | }, this); 82 | } 83 | } 84 | 85 | Bots.BossRobot.prototype.attackSurrounding = function () { 86 | this.attackedNearbyObjectInTurn = false; 87 | this.attackNearbyObjects(this.state.groups.robots); 88 | this.attackNearbyObjects(this.state.groups.chests); 89 | } 90 | 91 | Bots.BossRobot.prototype.jump = function () { 92 | this.game.add.tween(this.scale).to({ 93 | x: Bots.scale * this.properties.scaleMultiplier * 2, 94 | y: Bots.scale * this.properties.scaleMultiplier * 2 95 | }, 300, Phaser.Easing.Linear.None, true) 96 | .onComplete.add(() => { 97 | this.scale.x = Bots.scale * this.properties.scaleMultiplier * 2; 98 | this.scale.y = Bots.scale * this.properties.scaleMultiplier * 2; 99 | 100 | this.isJumping = false; 101 | this.game.add.tween(this.scale).to({ 102 | x: Bots.scale * this.properties.scaleMultiplier, 103 | y: Bots.scale * this.properties.scaleMultiplier 104 | }, 300, Phaser.Easing.Linear.None, true) 105 | .onComplete.add(() => { 106 | this.scale.x = Bots.scale * this.properties.scaleMultiplier; 107 | this.scale.y = Bots.scale * this.properties.scaleMultiplier; 108 | 109 | getMemberByName(this.state.groups.spawners, 'earthQuakeSpawner').spawn(this, 10); 110 | }, this); 111 | }, this); 112 | } 113 | 114 | Bots.BossRobot.prototype.initiateMeteoritHail = function () { 115 | this.state.groups.robots.forEachAlive((robot) => { 116 | if (!robot.isDead && !robot.boss && this.game.physics.arcade.distanceBetween(this, robot) < this.properties.shootRange) { 117 | const position = new Phaser.Point(robot.x, robot.y); 118 | getMemberByName(this.state.groups.spawners, 'meteoritSpawner').forceSpawn(position); 119 | } 120 | }) 121 | 122 | const count = this.game.rnd.integerInRange(5, 10); 123 | for (let i = 0; i < count; i++) { 124 | this.game.time.events.add(this.game.rnd.integerInRange(50, 500), () => { 125 | const position = new Phaser.Point(this.x + this.game.rnd.integerInRange(0, 200) * (randomBoolean() ? 1 : -1), this.y + this.game.rnd.integerInRange(0, 200) * (randomBoolean() ? 1 : -1)); 126 | getMemberByName(this.state.groups.spawners, 'meteoritSpawner').forceSpawn(position); 127 | }, this); 128 | } 129 | } -------------------------------------------------------------------------------- /js/prefabs/bossRobotSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.BossRobotSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.BossRobotSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.BossRobotSpawner.prototype.constructor = Bots.BossRobotSpawner; 13 | 14 | Bots.BossRobotSpawner.prototype.spawn = function (withDelay) { 15 | const time = this.game.rnd.integerInRange(this.properties.spawnTimeInSeconds.min, this.properties.spawnTimeInSeconds.max); 16 | this.game.time.events.add(withDelay ? time * 1000 : 0, () => { 17 | if (this.isAllowedToSpawn()) { 18 | const position = new Phaser.Point(this.game.rnd.between(-Bots.worldSize.x / 2, Bots.worldSize.x / 2), this.game.rnd.between(-Bots.worldSize.y / 2, Bots.worldSize.y / 2)); 19 | const name = `object_${this.pool.countLiving()}`; 20 | const object = this.createObject(name, position); 21 | } 22 | }, this); 23 | } 24 | 25 | Bots.BossRobotSpawner.prototype.createObject = function (name, position) { 26 | const maxHealth = this.state.game.rnd.integerInRange(1000, 1500); 27 | const randomName = getRandomName(); 28 | 29 | getMemberByName(this.state.groups.spawners, 'messageSpawner').spawn(`A new boss '${randomName}' has entered the stage`, 'warning'); 30 | 31 | return new Bots.BossRobot(this.state, name, position, { 32 | group: "robots", 33 | key: sample(['robot3Dred', 'robot3Dblue', 'robot3Dgreen', 'robot3Dyellow']), 34 | friction: 10, 35 | rotationSpeed: 5, 36 | attack: this.state.game.rnd.integerInRange(60, 80), 37 | defense: this.state.game.rnd.integerInRange(130, 180), 38 | speed: this.state.game.rnd.integerInRange(20, 35), 39 | health: maxHealth, 40 | maxHealth: maxHealth, 41 | displayName: randomName, 42 | shootRange: this.state.game.rnd.integerInRange(300, 500), 43 | stopRange: this.state.game.rnd.integerInRange(150, 200), 44 | accuracy: this.state.game.rnd.realInRange(0.9, 1), 45 | scaleMultiplier: 3, 46 | sloppiness: this.state.game.rnd.realInRange(0.25, 0.6) 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /js/prefabs/button.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 22/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.Button = function (state, name, position, properties) { 10 | Bots.Prefab.call(this, state, name, position, properties); 11 | 12 | this.fixedToCamera = true; 13 | 14 | this.inputEnabled = true; 15 | this.input.priorityId = 999; // ui 16 | this.input.useHandCursor = true; 17 | 18 | this.events.onInputDown.add(this.onButtonPressed, this); 19 | this.events.onInputUp.add(this.onButtonReleased, this); 20 | 21 | this.shadow = this.game.add.sprite(this.x, this.y + 2, this.properties.key); 22 | this.shadow.tint = 0x000000; 23 | this.shadow.anchor.setTo(0.5); 24 | this.shadow.fixedToCamera = true; 25 | 26 | this.state.groups.hud.addAt(this.shadow, 0); 27 | }; 28 | 29 | Bots.Button.prototype = Object.create(Bots.Prefab.prototype); 30 | Bots.Button.prototype.constructor = Bots.Button; 31 | 32 | Bots.Button.prototype.onButtonPressed = function () { 33 | if (!this.game.paused || this.properties.force) { 34 | this.scale.setTo(1.1); 35 | this.shadow.scale.setTo(1.1); 36 | } 37 | } 38 | 39 | Bots.Button.prototype.onButtonReleased = function () { 40 | if (!this.game.paused || this.properties.force) { 41 | this.scale.setTo(1); 42 | this.shadow.scale.setTo(1); 43 | 44 | if (Bots.soundsEnabled) { 45 | this.state.prefabs.clickSound.safelyPlay(); 46 | } 47 | 48 | this.state.onButtonPressed(this); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /js/prefabs/chest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.Chest = function (state, name, position, properties) { 10 | Bots.Droppable.call(this, state, name, position, properties); 11 | 12 | this.scale.setTo(Bots.scale); 13 | this.anchor.setTo(0.5); 14 | this.angle = this.game.rnd.integerInRange(0, 360); 15 | 16 | this.shadow = this.game.add.sprite(this.x, this.y, properties.key); 17 | this.shadow.scale.x = this.scale.x * 1.3; 18 | this.shadow.scale.y = this.scale.y * 1.3; 19 | this.shadow.alpha = 0.25; 20 | this.shadow.anchor.setTo(0.5); 21 | this.shadow.tint = 0x000000; 22 | this.shadow.name = `${name}_shadow`; 23 | this.shadow.angle = this.angle; 24 | this.state.groups.shadows.add(this.shadow); 25 | }; 26 | 27 | Bots.Chest.prototype = Object.create(Bots.Droppable.prototype); 28 | Bots.Chest.prototype.constructor = Bots.Chest; 29 | 30 | Bots.Chest.prototype.initializeObject = function () { 31 | this.game.physics.enable(this, Phaser.Physics.ARCADE); 32 | this.body.immovable = true; 33 | } 34 | 35 | Bots.Chest.prototype.hit = function () { 36 | this.properties.lifePoints -= 1; 37 | return this.properties.lifePoints <= 0; 38 | } -------------------------------------------------------------------------------- /js/prefabs/chestSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.ChestSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.ChestSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.ChestSpawner.prototype.constructor = Bots.ChestSpawner; 13 | 14 | Bots.ChestSpawner.prototype.createObject = function (name, position) { 15 | const key = sample(this.properties.keys); 16 | 17 | return new Bots.Chest(this.state, name, position, { 18 | key, 19 | group: 'chests', 20 | scale: { 21 | x: 0.75, 22 | y: 0.75 23 | }, 24 | lifePoints: this.game.rnd.integerInRange(1, 5) 25 | }); 26 | } -------------------------------------------------------------------------------- /js/prefabs/control.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 21/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.Control = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | this.isPressed = false; 11 | 12 | this.inputEnabled = true; 13 | this.events.onInputDown.add(() => (this.isPressed = true), this); 14 | this.events.onInputUp.add(() => { 15 | this.isPressed = false; 16 | }, this); 17 | }; 18 | 19 | Bots.Control.prototype = Object.create(Bots.Prefab.prototype); 20 | Bots.Control.prototype.constructor = Bots.Control; -------------------------------------------------------------------------------- /js/prefabs/creditsItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.CreditsItem = function (state, name, position, properties) { 10 | Bots.Prefab.call(this, state, name, position, properties); 11 | 12 | const factor = 0.4; 13 | 14 | this.graphics = this.game.add.graphics(0, 0); 15 | this.addChild(this.graphics); 16 | 17 | this.sprite = this.game.add.sprite(0, 0, properties.dummyKey); 18 | this.sprite.anchor.setTo(0.5); 19 | 20 | const scaleX = (factor * this.properties.size.width) / this.sprite.width; 21 | const scaleY = (factor * this.properties.size.height) / this.sprite.height; 22 | 23 | this.sprite.scale.setTo((scaleX < scaleY) ? scaleX : scaleY); 24 | this.sprite.x = -this.properties.size.width / 2 + this.sprite.width / 2 + 8; 25 | this.addChild(this.sprite); 26 | 27 | this.caption = this.game.add.text(this.sprite.x + this.sprite.width / 2 + 8, this.sprite.y - this.sprite.height / 2, shortenName(properties.title, 15), this.captionTextStyle()); 28 | this.addChild(this.caption); 29 | 30 | this.author = this.game.add.text(this.sprite.x + this.sprite.width / 2 + 8, this.sprite.y - this.sprite.height / 2 + 16, `by ${shortenName(properties.author, 12)}`, this.regularTextStyle()); 31 | this.addChild(this.author); 32 | 33 | this.linkIcon = this.game.add.sprite(this.properties.size.width / 2 - 8, this.properties.size.height / 2 - 8, 'uiLink'); 34 | this.linkIcon.anchor.setTo(1); 35 | this.addChild(this.linkIcon); 36 | 37 | this.linkIcon.inputEnabled = true; 38 | this.linkIcon.events.onInputUp.add(() => { 39 | if (this.game.device.iPad) { 40 | location.href = properties.link; 41 | } else { 42 | var newWindow = window.open(properties.link, '_blank'); 43 | if (newWindow) { 44 | newWindow.focus(); 45 | } else { 46 | location.href = properties.link; 47 | } 48 | } 49 | }, this); 50 | }; 51 | 52 | Bots.CreditsItem.prototype = Object.create(Bots.Prefab.prototype); 53 | Bots.CreditsItem.prototype.constructor = Bots.CreditsItem; 54 | 55 | Bots.CreditsItem.prototype.update = function () { 56 | this.graphics.clear(); 57 | this.graphics.beginFill(0x000000, 0.5); 58 | this.graphics.drawRect(-this.properties.size.width / 2, -this.properties.size.height / 2, this.properties.size.width, this.properties.size.height); 59 | this.graphics.endFill(); 60 | } 61 | 62 | Bots.CreditsItem.prototype.captionTextStyle = function () { 63 | return { 64 | font: '10pt bold Helvetica, sans-serif', 65 | fill: '#ffffff', 66 | align: 'left' 67 | } 68 | } 69 | 70 | Bots.CreditsItem.prototype.regularTextStyle = function (fontSize = 8) { 71 | return { 72 | font: `${fontSize}pt Helvetica, sans-serif`, 73 | fill: '#ffffff', 74 | align: 'left' 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /js/prefabs/creditsItemSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.CreditsItemSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | 10 | this.currentRow = 0; 11 | }; 12 | 13 | Bots.CreditsItemSpawner.prototype = Object.create(Bots.Spawner.prototype); 14 | Bots.CreditsItemSpawner.prototype.constructor = Bots.CreditsItemSpawner; 15 | 16 | Bots.CreditsItemSpawner.prototype.spawn = function () { 17 | this.properties.items.forEach((item, index) => { 18 | const name = `object_${this.pool.countLiving()}`; 19 | const object = this.createObject(name, item, index); 20 | }); 21 | } 22 | 23 | Bots.CreditsItemSpawner.prototype.createObject = function (name, properties, index) { 24 | const modIndex = mod(index, this.properties.columnCount); 25 | if (modIndex === 0 && index !== 0) { 26 | this.currentRow += 1; 27 | } 28 | 29 | const width = (Bots.screenSize.x - (this.properties.columnCount - 1 ) * this.properties.spacing - 2 * this.properties.margin) / this.properties.columnCount 30 | const height = width / 1.61803398875; 31 | 32 | const position = new Phaser.Point(this.properties.margin + modIndex * (width + this.properties.spacing) + width / 2, this.y + this.currentRow * (height + this.properties.spacing) + height / 2); 33 | return new Bots.CreditsItem(this.state, name, position, { 34 | dummyKey: properties.key, 35 | title: properties.title, 36 | author: properties.author, 37 | link: properties.link, 38 | group: this.properties.pool, 39 | size: { width, height }, 40 | anchor: { 41 | x: 0.5, 42 | y: 0.5 43 | }, 44 | fixedToCamera: true 45 | }); 46 | } -------------------------------------------------------------------------------- /js/prefabs/dpad.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.DPad = function (state, name, position, properties) { 9 | Bots.Prefab.call(this, state, name, position, properties); 10 | 11 | this.isPressed = false; 12 | this.pointer = null; 13 | 14 | this.inputEnabled = true; 15 | this.events.onInputDown.add(function (dpad, pointer) { 16 | this.isPressed = true; 17 | this.pointer = pointer; 18 | }, this); 19 | this.events.onInputUp.add(function () { 20 | this.isPressed = false; 21 | this.pointer = null; 22 | }, this); 23 | }; 24 | 25 | Bots.DPad.prototype = Object.create(Bots.Prefab.prototype); 26 | Bots.DPad.prototype.constructor = Bots.DPad; 27 | 28 | Bots.DPad.prototype.dpadAngle = function () { 29 | if (this.pointer) { 30 | return this.game.physics.arcade.angleToPointer(this, this.pointer) * 180 / 3.141592654; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /js/prefabs/droppable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.Droppable = function (state, name, position, properties) { 10 | Bots.Prefab.call(this, state, name, position, properties); 11 | 12 | this.dropped = false; 13 | this.dropObject(); 14 | }; 15 | 16 | Bots.Droppable.prototype = Object.create(Phaser.Sprite.prototype); 17 | Bots.Droppable.prototype.constructor = Bots.Droppable; 18 | 19 | Bots.Droppable.prototype.dropObject = function () { 20 | const easing = this.properties.avoidBounce ? Phaser.Easing.Quintic.In : Phaser.Easing.Bounce.Out; 21 | 22 | this.scale.setTo(Bots.scale * 8); 23 | const tween = this.game.add.tween(this.scale).to({ 24 | x: Bots.scale * (this.properties.scaleMultiplier || 1), 25 | y: Bots.scale * (this.properties.scaleMultiplier || 1) 26 | }, 750, easing, true); 27 | tween.onComplete.add(function () { 28 | this.dropped = true; 29 | this.initializeObject(); 30 | }, this); 31 | } 32 | 33 | Bots.Droppable.prototype.reset = function (x, y) { 34 | Phaser.Sprite.prototype.reset.call(this, x, y); 35 | 36 | this.dropped = false; 37 | this.dropObject(); 38 | } -------------------------------------------------------------------------------- /js/prefabs/droppableRobot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 16/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.DroppableRobot = function (state, name, position, properties) { 10 | Bots.Droppable.call(this, state, name, position, properties); 11 | this.anchor.setTo(0.5); 12 | this.human = false; 13 | this.isDead = false; 14 | this.isJumping = false; 15 | this.kills = 0; 16 | this.deaths = 0; 17 | 18 | this.scale.setTo(Bots.scale); 19 | this.game.physics.enable(this, Phaser.Physics.ARCADE); 20 | this.currentSpeed = 0; 21 | this.body.maxVelocity.setTo(this.properties.speed); 22 | this.body.mass = 1; 23 | this.body.collideWorldBounds = true; 24 | this.speedMultiplier = 1; 25 | 26 | this.weapon = this.game.add.weapon(10 + this.game.rnd.integerInRange(-2, 2), 'bullet', 0, this.state.groups.bullets); 27 | this.weapon.bullets.forEach((bullet) => { 28 | bullet.scale.setTo(Bots.scale); 29 | }, this); 30 | this.weapon.bulletKillType = Phaser.Weapon.KILL_DISTANCE; 31 | this.weapon.bulletKillDistance = 1000; 32 | this.weapon.bulletSpeed = 600 + this.game.rnd.integerInRange(-50, 50); 33 | this.weapon.fireRate = 300 + this.game.rnd.integerInRange(-30, 30); // 1 per 60 ms 34 | this.weapon.bulletAngleVariance = 5 + this.game.rnd.integerInRange(-5, 5); 35 | this.weapon.trackSprite(this, 0, 0, true); 36 | this.weapon.onFire.add(() => { 37 | getMemberByName(this.state.groups.spawners, 'soundSpawner').spawn(this, 'shotSound'); 38 | }, this); 39 | 40 | this.killCounter = this.game.add.text(0, 0, '1', { font: '10pt Arial', fill: '#ffffff', align: 'right' }) 41 | this.killCounter.anchor.setTo(1, 0); 42 | this.state.groups.hud.add(this.killCounter); 43 | 44 | this.nameText = this.game.add.text(0, 0, properties.displayName || 'Player', { 45 | font: '10pt Arial', 46 | fill: '#ffffff', 47 | align: 'center' 48 | }); 49 | this.nameText.anchor.setTo(0.5); 50 | this.state.groups.hud.add(this.nameText); 51 | 52 | this.healthBar = this.game.add.graphics(0, 0, state.groups.hud); 53 | 54 | this.shadow = this.game.add.sprite(this.x, this.y, properties.key); 55 | this.shadow.scale.x = this.scale.x * 1.2; 56 | this.shadow.scale.y = this.scale.y * 1.2; 57 | this.shadow.alpha = 0.25; 58 | this.shadow.anchor.setTo(0.5); 59 | this.shadow.tint = 0x000000; 60 | this.shadow.name = `${name}_shadow`; 61 | this.state.groups.shadows.add(this.shadow); 62 | 63 | this.spawnProtect = true; 64 | }; 65 | 66 | Bots.DroppableRobot.prototype = Object.create(Bots.Droppable.prototype); 67 | Bots.DroppableRobot.prototype.constructor = Bots.DroppableRobot; 68 | 69 | Bots.DroppableRobot.prototype.initializeObject = function (instance) { 70 | instance.alpha = 0.5; 71 | instance.spawnProtect = true; 72 | instance.game.time.events.add(2000, () => { 73 | instance.alpha = 1; 74 | instance.spawnProtect = false; 75 | }, instance); 76 | } 77 | 78 | Bots.DroppableRobot.prototype.reset = function (x, y) { 79 | Bots.Droppable.prototype.reset.call(this, x, y); 80 | } 81 | 82 | Bots.DroppableRobot.prototype.dealDamage = function (damage) { 83 | if (this.spawnProtect) { 84 | return false; 85 | } 86 | 87 | if (this.boss && damage < 0) { 88 | damage = 0; 89 | } 90 | 91 | this.properties.health = Math.ceil(this.properties.health - damage); 92 | 93 | if (this.properties.health > this.properties.maxHealth) { 94 | this.properties.health = this.properties.maxHealth; 95 | } 96 | 97 | if (this.human) { 98 | getMemberByName(this.state.groups.hud, 'healthText').text = this.properties.health < 0 ? 0 : this.properties.health; 99 | } 100 | 101 | if (this.properties.health < 0) { 102 | this.animateDeath(); 103 | return true; 104 | } 105 | 106 | return false; 107 | } 108 | 109 | Bots.DroppableRobot.prototype.killedOtherRobot = function (deadRobot) { 110 | this.dealDamage(-this.properties.maxHealth); 111 | 112 | if (this.human) { 113 | Bots.killCount += 1; 114 | } 115 | 116 | if (deadRobot.human) { 117 | Bots.deathCount += 1; 118 | } 119 | 120 | this.killCounter.text = parseInt(this.killCounter.text) + parseInt(deadRobot.killCounter.text); 121 | this.game.time.events.repeat(50, parseInt(deadRobot.killCounter.text), function () { 122 | getMemberByName(this.state.groups.spawners, 'lootSpawner').spawn(deadRobot, this); 123 | }, this); 124 | } 125 | 126 | Bots.DroppableRobot.prototype.animateDeath = function () { 127 | this.isDead = true; 128 | 129 | const deathTween = this.game.add.tween(this).to({ x: this.x - 10 }, 25, Phaser.Easing.Quadratic.InOut, true, 0, 5, true); 130 | deathTween.onComplete.add(function () { 131 | getMemberByName(this.state.groups.spawners, 'dustSpawner').spawn(this); 132 | getMemberByName(this.state.groups.spawners, 'explosionSpawner').spawn(this); 133 | getMemberByName(this.state.groups.spawners, 'earthQuakeSpawner').spawn(this, 4); 134 | 135 | killFromGroup(this.shadow, this.state.groups.shadows); 136 | 137 | this.game.add.tween(this.scale).to({ x: 4, y: 4 }, 500, Phaser.Easing.Quadratic.Out, true); 138 | this.game.add.tween(this).to({ alpha: 0 }, 500, Phaser.Easing.Quadratic.Out, true).onComplete.add(function () { 139 | if (this.trackTimer) { 140 | this.game.time.events.remove(this.trackTimer); 141 | this.trackTimer = null; 142 | } 143 | 144 | if (this.checkSurroundingsTimer) { 145 | this.game.time.events.remove(this.checkSurroundingsTimer); 146 | this.checkSurroundingsTimer = null; 147 | } 148 | 149 | if (this.jumpTimer) { 150 | this.game.time.events.remove(this.jumpTimer); 151 | this.jumpTimer = null; 152 | } 153 | 154 | if (this.meteoritTimer) { 155 | this.game.time.events.remove(this.meteoritTimer); 156 | this.meteoritTimer = null; 157 | } 158 | 159 | if (this.smokeTimer) { 160 | this.game.time.events.remove(this.smokeTimer); 161 | this.smokeTimer = null; 162 | } 163 | 164 | killFromGroup(this.killCounter, this.state.groups.hud); 165 | killFromGroup(this.healthBar, this.state.groups.hud); 166 | killFromGroup(this.nameText, this.state.groups.hud); 167 | killFromGroup(this, this.state.groups.hud); 168 | 169 | if (this.human) { 170 | getMemberByName(this.state.groups.spawners, 'robotSpawner').spawn('robot'); 171 | } else if (this.boss) { 172 | getMemberByName(this.state.groups.spawners, 'bossRobotSpawner').spawn(true); 173 | } 174 | }, this); 175 | }, this); 176 | } 177 | 178 | Bots.DroppableRobot.prototype.update = function (instance) { 179 | instance.speedMultiplier = 1; 180 | 181 | if (instance.body) { 182 | instance.game.physics.arcade.overlap(instance.weapon.bullets, instance.state.groups.chests, this.onBulletChestCollide, null, instance); 183 | instance.game.physics.arcade.overlap(instance.weapon.bullets, instance.state.groups.robots, this.onBulletRobotCollide, this.onBulletRobotCollideProcess, instance); 184 | instance.game.physics.arcade.overlap(instance.state.groups.oil, instance.state.groups.robots, this.onOilRobotOverlap, null, instance); 185 | } 186 | 187 | if (instance.healthBar) { 188 | instance.healthBar.clear(); 189 | 190 | if (instance.properties.health > 0) { 191 | let color = 0x00ff00; 192 | if (instance.properties.health < 0.5 * instance.properties.maxHealth) { 193 | color = 0xffae00; 194 | } 195 | 196 | if (instance.properties.health < 0.25 * instance.properties.maxHealth) { 197 | color = 0xff0000; 198 | } 199 | 200 | instance.healthBar.beginFill(color); 201 | instance.healthBar.lineStyle(0); 202 | instance.healthBar.drawRect(instance.x - instance.width / 2 + 16, instance.y + instance.height / 2 + 4, (instance.width - 16) * (instance.properties.health / instance.properties.maxHealth), 4); 203 | instance.healthBar.endFill(); 204 | 205 | instance.healthBar.lineStyle(1, 0x000000, 0.8) 206 | instance.healthBar.drawRect(instance.x - instance.width / 2 + 16, instance.y + instance.height / 2 + 4, instance.width - 16, 4); 207 | } 208 | } 209 | 210 | if (instance.killCounter) { 211 | instance.killCounter.x = instance.x - instance.width / 2 + 12; 212 | instance.killCounter.y = instance.y + instance.height / 2 - 2; 213 | } 214 | 215 | if (instance.nameText) { 216 | instance.nameText.x = instance.x; 217 | instance.nameText.y = instance.y - instance.height / 2 - 4; 218 | } 219 | 220 | instance.shadow.x = instance.x; 221 | instance.shadow.y = instance.y; 222 | instance.shadow.angle = instance.angle; 223 | } 224 | 225 | Bots.DroppableRobot.prototype.onBulletChestCollide = function (bullet, chest) { 226 | bullet.kill(); 227 | getMemberByName(this.state.groups.spawners, 'soundSpawner').spawn(chest, 'plingSound'); 228 | 229 | if (chest.hit()) { 230 | killFromGroup(chest.shadow, this.state.groups.shadows); 231 | killFromGroup(chest, this.state.groups.chests); 232 | 233 | getMemberByName(this.state.groups.spawners, 'explosionSpawner').spawn(chest); 234 | getMemberByName(this.state.groups.spawners, 'dustSpawner').spawn(chest); 235 | getMemberByName(this.state.groups.spawners, 'earthQuakeSpawner').spawn(this, 2); 236 | getMemberByName(this.state.groups.spawners, 'lootSpawner').spawn(chest, this); 237 | } 238 | } 239 | 240 | Bots.DroppableRobot.prototype.onBulletRobotCollide = function (bullet, robot) { 241 | if (robot !== this && !robot.isDead) { 242 | bullet.kill(); 243 | 244 | if (robot.dealDamage(calculateDamage2(this.properties.attack, robot.properties.defense))) { 245 | getMemberByName(this.state.groups.spawners, 'textSpawner').spawn(`${this.properties.displayName} (${this.killCounter.text}) killed ${robot.properties.displayName} (${robot.killCounter.text})`); 246 | 247 | this.killedOtherRobot(robot); 248 | } 249 | } 250 | } 251 | 252 | Bots.DroppableRobot.prototype.onOilRobotOverlap = function (oil, robot) { 253 | robot.speedMultiplier = 0.5; 254 | } 255 | 256 | Bots.DroppableRobot.prototype.onBulletRobotCollideProcess = function (bullet, robot) { 257 | return robot !== this; 258 | } 259 | 260 | Bots.DroppableRobot.prototype.fire = function () { 261 | if (!this.isDead && !this.spawnProtect) { 262 | this.weapon.fire(); 263 | } 264 | } 265 | 266 | Bots.DroppableRobot.prototype.applySpeedIncrease = function () { 267 | this.properties.rotationSpeed = this.properties.speed / 17; 268 | this.properties.maxSpeed = this.properties.speed * 2.5; 269 | 270 | if (this.body) { 271 | this.body.maxVelocity.setTo(this.boss ? 100 : this.properties.maxSpeed); 272 | } 273 | } -------------------------------------------------------------------------------- /js/prefabs/dust.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 21/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.Dust = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | this.game.add.tween(this).to({ alpha: 0 }, 5000, Phaser.Easing.Quartic.In, true).onComplete.add(function () { 11 | this.kill(); 12 | this.destroy(); 13 | this.state.groups[this.properties.group].remove(this); 14 | }, this); 15 | // 16 | // const explosion = this.animations.add('explosion'); 17 | // this.animations.play('explosion', 25, false); 18 | // this.animations.currentAnim.onComplete.add(function () { 19 | // console.log("Rxploded"); 20 | // 21 | // this.loadTexture('blackSmoke', 0); 22 | // this.alpha = 0.8; 23 | // 24 | // this.game.add.tween(this).to({ alpha: 0 }, 1000, Phaser.Easing.Quartic.In, true).onComplete.add(function () { 25 | // this.kill(); 26 | // this.destroy(); 27 | // this.state.groups[this.properties.group].remove(this); 28 | // }, this); 29 | // }, this) 30 | }; 31 | 32 | Bots.Dust.prototype = Object.create(Bots.Prefab.prototype); 33 | Bots.Dust.prototype.constructor = Bots.Dust; -------------------------------------------------------------------------------- /js/prefabs/dustSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.DustSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.DustSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.DustSpawner.prototype.constructor = Bots.DustSpawner; 13 | 14 | Bots.DustSpawner.prototype.spawn = function (object) { 15 | const position = new Phaser.Point(object.x, object.y); 16 | 17 | let dust = this.pool.getFirstDead(); 18 | if (dust) { 19 | dust.reset(position.x, position.y); 20 | } else { 21 | const name = `dust_${this.pool.countLiving()}`; 22 | const dustOrNull = this.createObject(name, position, object); 23 | 24 | if (dustOrNull) { 25 | dust = dustOrNull; 26 | } 27 | } 28 | } 29 | 30 | Bots.DustSpawner.prototype.createObject = function (name, position, object) { 31 | if (object) { 32 | const properties = { 33 | key: 'blackSmoke', 34 | group: 'ground', 35 | alpha: this.game.rnd.realInRange(0.4, 0.6), 36 | scale: { 37 | x: this.game.rnd.realInRange(0.9, 1.1), 38 | y: this.game.rnd.realInRange(0.9, 1.1) 39 | }, 40 | angle: this.game.rnd.integerInRange(0, 360), 41 | anchor: { 42 | x: 0.5, 43 | y: 0.5 44 | } 45 | } 46 | 47 | return new Bots.Dust(this.state, name, position, properties); 48 | } 49 | 50 | return null; 51 | } -------------------------------------------------------------------------------- /js/prefabs/earthQuakeSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.EarthQuakeSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.EarthQuakeSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.EarthQuakeSpawner.prototype.constructor = Bots.EarthQuakeSpawner; 13 | 14 | Bots.EarthQuakeSpawner.prototype.spawn = function (object, magnitude = 1) { 15 | if (this.game.physics.arcade.distanceBetween(object, getHumanRobot(this.state.groups.robots)) < 400) { 16 | const position = new Phaser.Point(object.x, object.y); 17 | this.game.camera.shake(0.001 * magnitude, 150 * magnitude); 18 | } 19 | 20 | if (magnitude >= 5) { 21 | this.state.groups.robots.forEach((robot) => { 22 | if (this.game.physics.arcade.distanceBetween(object, robot) < 400 && !robot.boss) { 23 | robot.stunned = true; 24 | this.game.time.events.add(150 * magnitude / 2, () => { 25 | robot.stunned = false; 26 | }, this); 27 | } 28 | }); 29 | } 30 | } -------------------------------------------------------------------------------- /js/prefabs/enemyRobot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 16/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.EnemyRobot = function (state, name, position, properties) { 8 | Bots.DroppableRobot.call(this, state, name, position, properties); 9 | }; 10 | 11 | 12 | Bots.EnemyRobot.prototype = Object.create(Bots.DroppableRobot.prototype); 13 | Bots.EnemyRobot.prototype.constructor = Bots.EnemyRobot; 14 | 15 | Bots.EnemyRobot.prototype.initializeObject = function () { 16 | Bots.DroppableRobot.prototype.initializeObject(this); 17 | 18 | this.properties.rotationSpeed = this.properties.speed / 17; 19 | this.properties.maxSpeed = this.properties.speed * 2.5; 20 | this.body.maxVelocity.setTo(this.properties.maxSpeed); 21 | 22 | this.trackTimer = this.game.time.events.loop(100, function () { 23 | if (!this.isDead) { 24 | getMemberByName(this.state.groups.spawners, 'trackSpawner').spawn(this); 25 | } 26 | }, this); 27 | } 28 | 29 | Bots.EnemyRobot.prototype.getClosestMemberOfGroup = function (group, isRobot) { 30 | let closestMember = null; 31 | let closestDistance = Number.MAX_VALUE; 32 | 33 | group.forEachAlive((member) => { 34 | if (member.name !== this.name) { 35 | const distance = this.game.physics.arcade.distanceBetween(this, member); 36 | if (distance < closestDistance) { 37 | if (isRobot && !member.isDead && !member.spawnProtect) { 38 | closestDistance = distance; 39 | closestMember = member; 40 | } 41 | } 42 | } 43 | }); 44 | 45 | return { 46 | member: closestMember, 47 | distance: closestDistance, 48 | present: closestMember !== null 49 | }; 50 | } 51 | 52 | Bots.EnemyRobot.prototype.update = function () { 53 | Bots.DroppableRobot.prototype.update(this); 54 | 55 | if (!this.stunned) { 56 | if (this.dropped && !this.isDead) { 57 | const closestRobot = this.getClosestMemberOfGroup(this.state.groups.robots, true); 58 | const closestChest = this.getClosestMemberOfGroup(this.state.groups.chests); 59 | 60 | const member = (closestRobot.present && closestRobot.distance < closestChest.distance) ? closestRobot : closestChest; 61 | 62 | if (member.member) { 63 | if (member.distance < this.properties.shootRange) { 64 | if (member.distance < this.properties.stopRange) { 65 | this.body.velocity.x = 0; 66 | this.body.velocity.y = 0; 67 | } else { 68 | } 69 | 70 | Bots.DroppableRobot.prototype.fire.call(this); 71 | } 72 | 73 | const offset = -60 * this.game.rnd.realInRange(this.properties.accuracy, 1) + 60; 74 | const destinationPosition = new Phaser.Point(member.member.x + offset * (randomBoolean() ? 1 : -1), member.member.y + offset * (randomBoolean() ? 1 : -1)); 75 | 76 | this.rotation = this.game.physics.arcade.angleBetween(this, member.member);// + (offset * (randomBoolean() ? 1 : -1)) * 3.141592563 / 180; 77 | this.game.physics.arcade.moveToObject(this, destinationPosition, this.properties.maxSpeed); 78 | } 79 | } 80 | } else { 81 | this.body.velocity.x = 0; 82 | this.body.velocity.y = 0; 83 | } 84 | } -------------------------------------------------------------------------------- /js/prefabs/enemyRobotSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.EnemyRobotSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.EnemyRobotSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.EnemyRobotSpawner.prototype.constructor = Bots.EnemyRobotSpawner; 13 | 14 | Bots.EnemyRobotSpawner.prototype.createObject = function (name, position) { 15 | const maxHealth = this.state.game.rnd.integerInRange(90, 120); 16 | 17 | return new Bots.EnemyRobot(this.state, name, position, { 18 | "group": "robots", 19 | "key": sample(['robot3Dred', 'robot3Dblue', 'robot3Dgreen', 'robot3Dyellow']), 20 | "friction": 10, 21 | "rotationSpeed": 10, 22 | "attack": this.state.game.rnd.integerInRange(30, 38), 23 | "defense": this.state.game.rnd.integerInRange(40, 48), 24 | "speed": this.state.game.rnd.integerInRange(40, 60), 25 | "health": maxHealth, 26 | "maxHealth": maxHealth, 27 | "displayName": getRandomName(), 28 | shootRange: this.state.game.rnd.integerInRange(200, 300), 29 | stopRange: this.state.game.rnd.integerInRange(150, 200), 30 | accuracy: this.state.game.rnd.realInRange(0.75, 0.98), 31 | scaleMultiplier: 1 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /js/prefabs/explosion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 21/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.Explosion = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | const explosion = this.animations.add('explosion'); 11 | this.animations.play('explosion', 25, false, true); 12 | 13 | getMemberByName(this.state.groups.spawners, 'soundSpawner').spawn(this, 'explosionSound'); 14 | }; 15 | 16 | Bots.Explosion.prototype = Object.create(Bots.Prefab.prototype); 17 | Bots.Explosion.prototype.constructor = Bots.Explosion; -------------------------------------------------------------------------------- /js/prefabs/explosionSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.ExplosionSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.ExplosionSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.ExplosionSpawner.prototype.constructor = Bots.ExplosionSpawner; 13 | 14 | Bots.ExplosionSpawner.prototype.spawn = function (object) { 15 | const position = new Phaser.Point(object.x, object.y); 16 | 17 | let explosion = this.pool.getFirstDead(); 18 | if (explosion) { 19 | explosion.reset(position.x, position.y); 20 | } else { 21 | const name = `explosion_${this.pool.countLiving()}`; 22 | const explosionOrNull = this.createObject(name, position, object); 23 | 24 | if (explosionOrNull) { 25 | explosion = explosionOrNull; 26 | } 27 | } 28 | } 29 | 30 | Bots.ExplosionSpawner.prototype.createObject = function (name, position, object) { 31 | if (object) { 32 | const properties = { 33 | key: 'explosion2', 34 | group: 'explosions', 35 | anchor: { 36 | x: 0.5, 37 | y: 0.5 38 | } 39 | } 40 | 41 | return new Bots.Explosion(this.state, name, position, properties); 42 | } 43 | 44 | return null; 45 | } -------------------------------------------------------------------------------- /js/prefabs/loot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.Loot = function (state, name, position, properties) { 9 | Bots.Prefab.call(this, state, name, position, properties); 10 | 11 | this.properties.robot.properties[this.properties.type] += this.properties.amount; 12 | if (this.properties.robot.properties[this.properties.type] > this.properties.maxValue) { 13 | this.properties.robot.properties[this.properties.type] = this.properties.maxValue; 14 | } 15 | 16 | if (this.properties.type === 'speed') { 17 | this.properties.robot.applySpeedIncrease(); 18 | } 19 | 20 | if (this.properties.robot.human) { 21 | // update hud 22 | const tweenColor = this.properties.amount >= 0 ? '#00ff00' : '#ff0000'; 23 | this.game.time.events.add(0, function () { 24 | const text = getMemberByName(this.state.groups.hud, this.properties.hudTextName); 25 | text.addColor(tweenColor, 0); 26 | 27 | this.game.time.events.add(250, function () { 28 | const text = getMemberByName(this.state.groups.hud, this.properties.hudTextName); 29 | text.addColor('#ffffff', 0); 30 | }, this) 31 | }, this); 32 | 33 | getMemberByName(this.state.groups.hud, this.properties.hudTextName).text = this.properties.robot.properties[this.properties.type] 34 | } 35 | 36 | this.game.add.tween(this).to({ y: position.y - 150, alpha: 0 }, 1000, Phaser.Easing.Quadratic.Out, true); 37 | this.game.add.tween(this.scale).to({ 38 | x: 4, 39 | y: 4 40 | }, 1000, Phaser.Easing.Quadratic.Out, true).onComplete.add(function () { 41 | this.kill(); 42 | this.destroy(); 43 | this.state.groups.loot.remove(this); 44 | }, this); 45 | }; 46 | 47 | Bots.Loot.prototype = Object.create(Bots.Prefab.prototype); 48 | Bots.Loot.prototype.constructor = Bots.Loot; 49 | -------------------------------------------------------------------------------- /js/prefabs/lootSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.LootSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.LootSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.LootSpawner.prototype.constructor = Bots.LootSpawner; 13 | 14 | Bots.LootSpawner.prototype.spawn = function (chest, robot) { 15 | const position = new Phaser.Point(chest.x, chest.y); 16 | 17 | let loot = this.pool.getFirstDead(); 18 | if (loot) { 19 | loot.reset(position.x, position.y); 20 | } else { 21 | const name = `loot_${this.pool.countLiving()}`; 22 | const lootOrNull = this.createObject(name, position, robot); 23 | 24 | if (lootOrNull) { 25 | loot = lootOrNull; 26 | } 27 | } 28 | } 29 | 30 | Bots.LootSpawner.prototype.createObject = function (name, position, robot) { 31 | const properties = this.generateLootProperties(robot); 32 | if (properties) { 33 | properties.robot = robot; 34 | properties.alpha = 0.5; 35 | properties.group = 'loot'; 36 | properties.anchor = { x: 0.5, y: 0.5 }; 37 | 38 | return new Bots.Loot(this.state, name, position, properties); 39 | } 40 | 41 | return null; 42 | } 43 | 44 | Bots.LootSpawner.prototype.generateLootProperties = function (robot) { 45 | if (robot) { 46 | const properties = [{ 47 | type: 'attack', 48 | amount: this.game.rnd.integerInRange(3, 6), 49 | key: 'lucifer_cannon', 50 | hudTextName: 'atkText', 51 | maxValue: 255 52 | }, { 53 | type: 'defense', 54 | amount: this.game.rnd.integerInRange(5, 10), 55 | key: 'shield', 56 | hudTextName: 'defText', 57 | maxValue: 255 58 | }, { 59 | type: 'maxHealth', 60 | amount: this.game.rnd.integerInRange(20, 35), 61 | key: 'medical_pack', 62 | hudTextName: 'healthText', 63 | maxValue: 999 64 | }, { 65 | type: 'speed', 66 | amount: this.game.rnd.integerInRange(2, 4), 67 | key: 'jet_pack', 68 | hudTextName: 'speedText', 69 | maxValue: 255 70 | }]; 71 | 72 | return sample(properties); 73 | } 74 | 75 | return null; 76 | } -------------------------------------------------------------------------------- /js/prefabs/menuBackgroundChooser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 22/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.MenuBackgroundChooser = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | this.selectedTile = null; 11 | this.backgrounds = []; 12 | let selectedTile = null; 13 | 14 | properties.backgrounds.forEach((key, index) => { 15 | const spriteProperties = { 16 | key, 17 | group: properties.pool, 18 | anchor: properties.anchor, 19 | scale: properties.scale, 20 | parent: this, 21 | shadow: properties.shadow, 22 | index: index 23 | }; 24 | 25 | 26 | const selectableSprite = new Bots.SelectableSprite(state, key, position, spriteProperties); 27 | this.backgrounds.push(selectableSprite); 28 | 29 | if (Bots.background === key) { 30 | selectedTile = selectableSprite; 31 | } 32 | }); 33 | 34 | this.backgrounds.forEach((background, index) => { 35 | const length = this.backgrounds.length; 36 | background.x += (background.width + properties.spacing) * mod(index, properties.columns);// - (length * background.width + (length - 1) * properties.spacing) / 2 + background.width / 2; 37 | background.y -= Math.trunc(index / properties.columns) * (background.width + properties.spacing); 38 | }); 39 | 40 | this.onTileSelected(selectedTile === null ? this.backgrounds[0] : selectedTile); 41 | } 42 | 43 | Bots.MenuBackgroundChooser.prototype = Object.create(Bots.Prefab.prototype); 44 | Bots.MenuBackgroundChooser.prototype.constructor = Bots.MenuBackgroundChooser; 45 | 46 | Bots.MenuBackgroundChooser.prototype.onTileSelected = function (selectedTile) { 47 | this.selectedTile = selectedTile; 48 | this.backgrounds.forEach((tile) => (tile.isSelected = false)); 49 | selectedTile.isSelected = true; 50 | getMemberByName(this.state.groups.background, 'background').loadTexture(selectedTile.properties.key); 51 | } -------------------------------------------------------------------------------- /js/prefabs/menuRobot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 16/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.MenuRobot = function (state, name, position, properties) { 10 | Bots.Prefab.call(this, state, name, position, properties); 11 | this.anchor.setTo(0.5); 12 | this.scale.setTo(Bots.scale); 13 | this.currentDestination = null; 14 | 15 | this.game.physics.enable(this, Phaser.Physics.ARCADE); 16 | this.body.maxVelocity.setTo(100); 17 | this.currentSpeed = this.game.rnd.integerInRange(50, 100); 18 | this.body.mass = 1; 19 | this.speedMultiplier = 1; 20 | 21 | this.shadow = this.game.add.sprite(this.x, this.y, properties.key); 22 | this.shadow.scale.x = this.scale.x * 1.2; 23 | this.shadow.scale.y = this.scale.y * 1.2; 24 | this.shadow.alpha = 0.25; 25 | this.shadow.anchor.setTo(0.5); 26 | this.shadow.tint = 0x000000; 27 | this.shadow.name = `${name}_shadow`; 28 | this.state.groups.shadows.add(this.shadow); 29 | }; 30 | 31 | Bots.MenuRobot.prototype = Object.create(Bots.Prefab.prototype); 32 | Bots.MenuRobot.prototype.constructor = Bots.MenuRobot; 33 | 34 | Bots.MenuRobot.prototype.reset = function (x, y) { 35 | Bots.Prefab.prototype.reset.call(this, x, y); 36 | } 37 | 38 | Bots.MenuRobot.prototype.update = function () { 39 | this.speedMultiplier = 1; 40 | 41 | this.shadow.x = this.x; 42 | this.shadow.y = this.y; 43 | this.shadow.angle = this.angle; 44 | 45 | if (!this.currentDestination || this.game.physics.arcade.distanceToXY(this, this.currentDestination.x, this.currentDestination.y) <= 50) { 46 | this.currentDestination = new Phaser.Point(randomInteger(2 * Bots.screenSize.x) - Bots.screenSize.x / 2, randomInteger(2 * Bots.screenSize.y) - Bots.screenSize.y / 2); 47 | } 48 | 49 | if (this.currentDestination) { 50 | this.rotation = this.game.physics.arcade.angleToXY(this, this.currentDestination.x, this.currentDestination.y, true); 51 | this.game.physics.arcade.moveToObject(this, this.currentDestination, this.currentSpeed); 52 | } 53 | } -------------------------------------------------------------------------------- /js/prefabs/menuRobotChooser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 22/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.MenuRobotChooser = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | this.index = 0; 11 | this.robots = []; 12 | properties.robots.forEach((name, index) => { 13 | const robot = getMemberByName(this.state.groups[properties.pool], name) 14 | if (robot) { 15 | this.robots.push(robot); 16 | 17 | robot.alpha = 0; 18 | robot.x = position.x; 19 | robot.y = position.y; 20 | 21 | const text = getMemberByName(this.state.groups.robotTexts, `${name}Text`); 22 | if (text) { 23 | robot.addChild(text); 24 | } 25 | } 26 | }); 27 | } 28 | 29 | Bots.MenuRobotChooser.prototype = Object.create(Bots.Prefab.prototype); 30 | Bots.MenuRobotChooser.prototype.constructor = Bots.MenuRobotChooser; 31 | 32 | Bots.MenuRobotChooser.prototype.showNext = function () { 33 | this.index = mod(this.index + 1, this.robots.length) 34 | this.showRobot(this.index, true); 35 | } 36 | 37 | Bots.MenuRobotChooser.prototype.showPrevious = function () { 38 | this.index = mod(this.index - 1, this.robots.length) 39 | this.showRobot(this.index, false); 40 | } 41 | 42 | Bots.MenuRobotChooser.prototype.showRobot = function (index, forward) { 43 | const currentIndex = mod(index, this.robots.length); 44 | const lastIndex = mod(index + (forward ? -1 : 1), this.robots.length); 45 | 46 | this.robots[lastIndex].x = Bots.screenSize.x / 2; 47 | this.robots[lastIndex].alpha = 1; 48 | this.game.add.tween(this.robots[lastIndex]) 49 | .to({ alpha: 0, x: this.robots[lastIndex].x + (forward ? 100 : -100 ) }, 500, Phaser.Easing.Quintic.Out, true); 50 | 51 | this.robots[currentIndex].x = Bots.screenSize.x / 2 + (forward ? -100 : 100); 52 | this.robots[currentIndex].alpha = 0; 53 | this.game.add.tween(this.robots[currentIndex]) 54 | .to({ 55 | alpha: 1, 56 | x: this.robots[currentIndex].x + (forward ? 100 : -100 ) 57 | }, 500, Phaser.Easing.Quintic.Out, true); 58 | } 59 | 60 | Bots.MenuRobotChooser.prototype.chooseRobot = function (animationDuration) { 61 | this.game.add.tween(this.robots[this.index]) 62 | .to({ alpha: 0.5, x: Bots.screenSize.x * 1.5 }, animationDuration, Phaser.Easing.Quintic.Out, true); 63 | } 64 | 65 | Bots.MenuRobotChooser.prototype.getChosenRobot = function () { 66 | return this.robots[this.index]; 67 | } -------------------------------------------------------------------------------- /js/prefabs/menuRobotSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.MenuRobotSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.MenuRobotSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.MenuRobotSpawner.prototype.constructor = Bots.MenuRobotSpawner; 13 | 14 | Bots.MenuRobotSpawner.prototype.createObject = function (name, position) { 15 | position = new Phaser.Point(randomInteger(2 * Bots.screenSize.x) - Bots.screenSize.x / 2, randomInteger(2 * Bots.screenSize.y) - Bots.screenSize.y / 2); 16 | 17 | return new Bots.MenuRobot(this.state, name, position, { 18 | "group": "robots", 19 | "key": sample(['robot3Dred', 'robot3Dblue', 'robot3Dgreen', 'robot3Dyellow']), 20 | "friction": 10, 21 | "rotationSpeed": 10 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /js/prefabs/messagePrefab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.MessagePrefab = function (state, name, position, properties) { 9 | this.messageHeight = 36; 10 | Phaser.Graphics.call(this, state.game, Bots.screenSize.x / 2, 100, properties.text, properties.style); 11 | 12 | this.state = state; 13 | this.name = name; 14 | this.properties = properties; 15 | this.state.prefabs[name] = this; 16 | this.game = state.game; 17 | this.anchor.setTo(0.5); 18 | this.fixedToCamera = true; 19 | 20 | if (properties.group) { 21 | this.state.groups[properties.group].add(this); 22 | } 23 | 24 | this.beginFill(0x000000, 0.75); 25 | this.drawRect(-Bots.screenSize.x / 2, -this.messageHeight / 2, Bots.screenSize.x, this.messageHeight); 26 | this.endFill(); 27 | 28 | this.text = this.game.add.text(0, 2, properties.text, properties.style); 29 | this.text.anchor.setTo(0.5); 30 | this.addChild(this.text); 31 | 32 | this.sprite = this.game.add.sprite(0, 0, properties.key); 33 | this.sprite.anchor.setTo(0.5) 34 | this.sprite.scale.setTo(properties.imageScale.x, properties.imageScale.y); 35 | this.addChild(this.sprite); 36 | 37 | this.sprite.x = -this.text.width / 2 - this.sprite.width / 2 - 8; 38 | 39 | 40 | this.game.time.events.add(2000, () => { 41 | this.game.add.tween(this).to({ alpha: 0 }, 3000, Phaser.Easing.Quadratic.Out, true) 42 | .onComplete.add(() => { 43 | killFromGroup(this, this.state.groups[properties.group]); 44 | }, this); 45 | }, this); 46 | }; 47 | 48 | Bots.MessagePrefab.prototype = Object.create(Phaser.Graphics.prototype); 49 | Bots.MessagePrefab.prototype.constructor = Bots.MessagePrefab; 50 | 51 | Bots.MessagePrefab.prototype.autoSize = function (width, height) { 52 | if (!this.defaultFontSize) { 53 | this.defaultFontSize = this.fontSize; 54 | } 55 | 56 | if (width > 0 && height > 0) { 57 | this.fontSize = 64; 58 | let size = this.fontSize; 59 | while (this.fontSize > 4) { 60 | if (this.width < width && this.height < height) { 61 | return size; 62 | } 63 | 64 | this.fontSize = --size; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /js/prefabs/messageSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.MessageSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.MessageSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.MessageSpawner.prototype.constructor = Bots.MessageSpawner; 13 | 14 | Bots.MessageSpawner.prototype.spawn = function (text, key) { 15 | const name = `textPrefab_${this.pool.countLiving()}`; 16 | const textPrefabOrNull = this.createObject(name, text, key); 17 | } 18 | 19 | Bots.MessageSpawner.prototype.createObject = function (name, text, key) { 20 | const result = new Bots.MessagePrefab(this.state, name, new Phaser.Point(0, 0), { 21 | group: this.properties.pool, 22 | text: text, 23 | key: key, 24 | style: { 25 | font: `12pt Arial`, 26 | fill: '#ffffff', 27 | align: 'left' 28 | }, 29 | imageScale: { 30 | x: 0.75, 31 | y: 0.75 32 | } 33 | }); 34 | 35 | return result; 36 | } -------------------------------------------------------------------------------- /js/prefabs/meteorit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.Meteorit = function (state, name, position, properties) { 10 | Bots.Droppable.call(this, state, name, position, properties); 11 | 12 | this.scale.setTo(Bots.scale); 13 | this.anchor.setTo(0.5); 14 | this.angle = this.game.rnd.integerInRange(0, 360); 15 | }; 16 | 17 | Bots.Meteorit.prototype = Object.create(Bots.Droppable.prototype); 18 | Bots.Meteorit.prototype.constructor = Bots.Meteorit; 19 | 20 | Bots.Meteorit.prototype.initializeObject = function () { 21 | this.game.physics.enable(this, Phaser.Physics.ARCADE); 22 | this.body.immovable = true; 23 | 24 | getMemberByName(this.state.groups.spawners, 'explosionSpawner').spawn(this); 25 | getMemberByName(this.state.groups.spawners, 'dustSpawner').spawn(this); 26 | getMemberByName(this.state.groups.spawners, 'earthQuakeSpawner').spawn(this, this.game.rnd.integerInRange(0, 10)); 27 | 28 | const bounds = this.getBounds(); 29 | this.state.groups.robots.forEachAlive((robot) => { 30 | if (!robot.isDead && !robot.boss && Phaser.Rectangle.intersects(bounds, robot.getBounds())) { 31 | if (robot.dealDamage(calculateDamage2(this.properties.attack, robot.properties.defense))) { 32 | getMemberByName(this.state.groups.spawners, 'textSpawner').spawn(`${robot.properties.displayName} (${robot.killCounter.text}) was killed by a comet`); 33 | } 34 | } 35 | }); 36 | 37 | killFromGroup(this, this.state.groups[this.properties.group]); 38 | } -------------------------------------------------------------------------------- /js/prefabs/meteoritSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.MeteoritSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.MeteoritSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.MeteoritSpawner.prototype.constructor = Bots.MeteoritSpawner; 13 | 14 | Bots.MeteoritSpawner.prototype.forceSpawn = function (position) { 15 | let object = this.pool.getFirstDead(); 16 | if (object) { 17 | object.reset(position.x, position.y); 18 | } else { 19 | const name = `object_${this.pool.countLiving()}`; 20 | object = this.createObject(name, position); 21 | } 22 | } 23 | 24 | Bots.MeteoritSpawner.prototype.createObject = function (name, position) { 25 | const key = sample(this.properties.keys); 26 | 27 | return new Bots.Meteorit(this.state, name, position, { 28 | key, 29 | group: this.properties.pool, 30 | scale: { 31 | x: 0.75, 32 | y: 0.75 33 | }, 34 | avoidBounce: this.properties.avoidBounce, 35 | attack: this.game.rnd.integerInRange(100, 200) 36 | }); 37 | } -------------------------------------------------------------------------------- /js/prefabs/minimap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 16/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.Minimap = function (state, name, position, properties) { 10 | const x = state.game.width - Bots.minimapPadding.x - Bots.minimapWidth; 11 | const y = Bots.minimapPadding.y; 12 | 13 | Phaser.Graphics.call(this, state.game, x, y); 14 | 15 | this.state = state; 16 | this.name = name; 17 | this.alpha = properties.alpha; 18 | this.fixedToCamera = true; 19 | this.properties = properties; 20 | this.state.prefabs[name] = this; 21 | 22 | if (properties.group) { 23 | this.state.groups[properties.group].add(this); 24 | } 25 | }; 26 | 27 | Bots.Minimap.prototype = Object.create(Phaser.Graphics.prototype); 28 | Bots.Minimap.prototype.constructor = Bots.Minimap; 29 | 30 | Bots.Minimap.prototype.update = function () { 31 | this.clear(); 32 | 33 | this.drawRectangle(0, 0, Bots.minimapWidth, Bots.minimapHeight); 34 | 35 | this.state.groups.robots.forEachAlive((robot) => this.drawMinimapObject(robot, this.getRobotMinimapColor(robot), robot.boss ? 5 : 3)); 36 | this.state.groups.chests.forEachAlive((chest) => this.drawMinimapObject(chest, 0x00ff00)); 37 | this.state.groups.oil.forEachAlive((oil) => this.drawMinimapObject(oil, 0xff00ff)); 38 | } 39 | 40 | Bots.Minimap.prototype.drawRectangle = function (x, y, w, h, color = 0x000000) { 41 | this.beginFill(color); 42 | this.drawRect(x, y, w, h); 43 | this.endFill(); 44 | } 45 | 46 | Bots.Minimap.prototype.drawMinimapObject = function (object, color = 0xffffff, size = 3) { 47 | const x = object.world.x + Bots.worldSize.x / 2; 48 | const y = object.world.y + Bots.worldSize.y / 2; 49 | 50 | const mapX = (x / (1.0 * Bots.worldSize.x)) * Bots.minimapWidth; 51 | const mapY = (y / (1.0 * Bots.worldSize.y)) * Bots.minimapHeight; 52 | 53 | this.drawRectangle(mapX - (size - 1) / 2, mapY - (size - 1) / 2, size, size, color); 54 | } 55 | 56 | Bots.Minimap.prototype.getRobotMinimapColor = function (robot) { 57 | if (robot) { 58 | if (robot.human) { 59 | return 0x0000ff; 60 | } 61 | 62 | if (robot.boss) { 63 | return 0xff0000; 64 | } 65 | 66 | return 0xffffff; 67 | } 68 | } -------------------------------------------------------------------------------- /js/prefabs/oil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 21/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.Oil = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | this.game.physics.enable(this, Phaser.Physics.ARCADE); 11 | this.game.add.tween(this).to({ alpha: 0 }, 20000, Phaser.Easing.Quartic.In, true) 12 | .onComplete.add(() => killFromGroup(this, this.state.groups[this.properties.group]), this); 13 | }; 14 | 15 | Bots.Oil.prototype = Object.create(Bots.Prefab.prototype); 16 | Bots.Oil.prototype.constructor = Bots.Oil; -------------------------------------------------------------------------------- /js/prefabs/oilSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.OilSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.OilSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.OilSpawner.prototype.constructor = Bots.OilSpawner; 13 | 14 | Bots.OilSpawner.prototype.createObject = function (name, position) { 15 | const scale = this.game.rnd.realInRange(0.5, 1.3); 16 | 17 | const properties = { 18 | key: 'oil', 19 | group: 'oil', 20 | alpha: this.game.rnd.realInRange(0.6, 0.75), 21 | scale: { 22 | x: scale, 23 | y: scale 24 | }, 25 | angle: this.game.rnd.integerInRange(0, 360), 26 | anchor: { 27 | x: 0.5, 28 | y: 0.5 29 | } 30 | } 31 | 32 | return new Bots.Oil(this.state, name, position, properties); 33 | } -------------------------------------------------------------------------------- /js/prefabs/pauseDialog.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 21/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.PauseDialog = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | // this.fixedToCamera = true; 11 | 12 | this.tl = this.game.add.sprite(-this.properties.size.x / 2, -this.properties.size.y / 2, 'uiWindowTL'); 13 | this.tl.anchor.setTo(0, 0); 14 | this.tr = this.game.add.sprite(this.properties.size.x / 2, -this.properties.size.y / 2, 'uiWindowTR'); 15 | this.tr.anchor.setTo(1, 0); 16 | this.t = this.game.add.sprite(0, -this.properties.size.y / 2, 'uiWindowT'); 17 | this.t.anchor.setTo(0.5, 0); 18 | this.t.scale.x = (this.properties.size.x - this.tl.width - this.tr.width) / (this.t.width - 5); 19 | 20 | this.bl = this.game.add.sprite(-this.properties.size.x / 2, this.properties.size.y / 2, 'uiWindowBL'); 21 | this.bl.anchor.setTo(0, 1); 22 | this.br = this.game.add.sprite(this.properties.size.x / 2, this.properties.size.y / 2, 'uiWindowBR'); 23 | this.br.anchor.setTo(1, 1); 24 | this.b = this.game.add.sprite(0, this.properties.size.y / 2, 'uiWindowB'); 25 | this.b.anchor.setTo(0.5, 1); 26 | this.b.scale.x = (this.properties.size.x - this.bl.width - this.br.width) / (this.b.width - 5); 27 | 28 | this.ml = this.game.add.sprite(-this.properties.size.x / 2, 0, 'uiWindowL'); 29 | this.ml.anchor.setTo(0, 0.5); 30 | this.ml.scale.y = (this.properties.size.y - this.bl.height - this.bl.height) / (this.ml.height - 5); 31 | 32 | this.mr = this.game.add.sprite(this.properties.size.x / 2, 0, 'uiWindowR'); 33 | this.mr.anchor.setTo(1, 0.5); 34 | this.mr.scale.y = (this.properties.size.y - this.br.height - this.br.height) / (this.mr.height - 5); 35 | 36 | this.m = this.game.add.sprite(0, 0, 'uiWindow'); 37 | this.m.anchor.setTo(0.5, 0.5); 38 | this.m.scale.x = (this.properties.size.x - this.ml.width - this.mr.width) / (this.m.width - 5); 39 | this.m.scale.y = (this.properties.size.y - this.br.height - this.br.height) / (this.m.height - 5); 40 | 41 | this.graphics = this.game.add.graphics(0, 0); 42 | this.graphics.beginFill(0x000000, 0.5); 43 | this.graphics.drawRect(-Bots.screenSize.x / 2, -Bots.screenSize.y / 2, Bots.screenSize.x, Bots.screenSize.y); 44 | this.graphics.endFill(); 45 | 46 | this.cross = new Bots.Button(this.state, 'crossButton', new Phaser.Point(properties.size.x / 2 - 24, -properties.size.y / 2 + 24), { 47 | anchor: { 48 | x: 0.5, 49 | y: 0.5 50 | }, 51 | scale: { 52 | x: 0.5, 53 | y: 0.5 54 | }, 55 | key: 'uiCross', 56 | group: properties.group, 57 | force: true 58 | }); 59 | 60 | this.caption = new Bots.TextPrefab(this.state, 'pauseDialogCaption', new Phaser.Point(0, -properties.size.y / 2 + 24), { 61 | text: 'Pause', 62 | group: properties.group, 63 | style: { 64 | font: "20pt Arial", 65 | fill: "#ffffff", 66 | align: "center" 67 | }, 68 | anchor: { 69 | x: 0.5, 70 | y: 0.5 71 | } 72 | }); 73 | 74 | this.addChild(this.graphics); 75 | this.addChild(this.ml); 76 | this.addChild(this.mr); 77 | this.addChild(this.tr); 78 | this.addChild(this.br); 79 | this.addChild(this.tl); 80 | this.addChild(this.bl); 81 | this.addChild(this.b); 82 | this.addChild(this.t); 83 | this.addChild(this.m); 84 | this.addChild(this.caption); 85 | this.addChild(this.cross); 86 | 87 | this.game.paused = true; 88 | }; 89 | 90 | Bots.PauseDialog.prototype = Object.create(Bots.Prefab.prototype); 91 | Bots.PauseDialog.prototype.constructor = Bots.PauseDialog; -------------------------------------------------------------------------------- /js/prefabs/pauseDialogSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.PauseDialogSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.PauseDialogSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.PauseDialogSpawner.prototype.constructor = Bots.PauseDialogSpawner; 13 | 14 | Bots.PauseDialogSpawner.prototype.spawn = function (offset = new Phaser.Point(0, 0)) { 15 | if (!getMemberByName(this.state.groups[this.properties.pool], 'pauseDialog')) { 16 | return new Bots.PauseDialog(this.state, 'pauseDialog', new Phaser.Point(Bots.screenSize.x / 2 + offset.x, Bots.screenSize.y / 2 + offset.y), { 17 | group: this.properties.pool, 18 | size: this.properties.size, 19 | anchor: { 20 | x: 0.5, 21 | y: 0.5 22 | } 23 | }); 24 | } 25 | } -------------------------------------------------------------------------------- /js/prefabs/prefab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.Prefab = function (state, name, position, properties) { 9 | Phaser.Sprite.call(this, state.game, position.x, position.y, properties.key); 10 | 11 | this.state = state; 12 | this.name = name; 13 | this.properties = properties; 14 | this.state.prefabs[name] = this; 15 | this.game = state.game; 16 | 17 | if (properties.group) { 18 | this.state.groups[properties.group].add(this); 19 | } 20 | 21 | if (properties.frame) { 22 | this.frame = properties.frame; 23 | } 24 | 25 | if (properties.anchor) { 26 | this.anchor.setTo(properties.anchor.x, properties.anchor.y); 27 | } 28 | 29 | if (properties.scale) { 30 | this.scale.setTo(properties.scale.x, properties.scale.y); 31 | } 32 | 33 | if (properties.alpha !== undefined) { 34 | this.alpha = properties.alpha; 35 | } 36 | 37 | if (properties.angle) { 38 | this.angle = properties.angle; 39 | } 40 | 41 | if (properties.mirror) { 42 | if (properties.mirror.x) { 43 | this.scale.x *= -1; 44 | } 45 | 46 | if (properties.mirror.y) { 47 | this.scale.y *= -1; 48 | } 49 | } 50 | 51 | this.fixedToCamera = properties.fixedToCamera; 52 | }; 53 | 54 | Bots.Prefab.prototype = Object.create(Phaser.Sprite.prototype); 55 | Bots.Prefab.prototype.constructor = Bots.Prefab; 56 | 57 | Bots.Prefab.prototype.render = function () { 58 | this.game.debug.spriteInfo(this, 32, 32); 59 | } -------------------------------------------------------------------------------- /js/prefabs/robot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.Robot = function (state, name, position, properties) { 8 | Bots.DroppableRobot.call(this, state, name, position, properties); 9 | 10 | this.human = true; 11 | this.deaths = 0; 12 | this.kills = 0; 13 | 14 | this.game.camera.follow(this); 15 | this.game.camera.deadzone = new Phaser.Rectangle(Bots.cameraPadding, Bots.cameraPadding, Bots.screenSize.x - 4 * Bots.minimapPadding.x - Bots.minimapWidth - Bots.cameraPadding, Bots.screenSize.y - 2 * Bots.cameraPadding); 16 | this.game.camera.focusOnXY(position.x, position.y); 17 | 18 | this.trackTimer = null; 19 | 20 | this.dpad = getMemberByName(this.state.groups.hud, 'uiDPad'); 21 | this.shootButton = getMemberByName(this.state.groups.hud, 'uiShootButton'); 22 | this.menuButton = getMemberByName(this.state.groups.hud, 'uiMenuButton'); 23 | 24 | if (this.game.device.desktop) { 25 | killFromGroup(this.dpad, this.state.groups.hud); 26 | killFromGroup(this.shootButton, this.state.groups.hud); 27 | killFromGroup(this.menuButton, this.state.groups.hud); 28 | 29 | this.dpad = null; 30 | this.shootButton = null; 31 | this.menuButton = null; 32 | } 33 | }; 34 | 35 | Bots.Robot.prototype = Object.create(Bots.DroppableRobot.prototype); 36 | Bots.Robot.prototype.constructor = Bots.Robot; 37 | 38 | Bots.Robot.prototype.initializeObject = function () { 39 | Bots.DroppableRobot.prototype.initializeObject(this); 40 | 41 | getMemberByName(this.state.groups.hud, 'atkText').text = this.properties.attack; 42 | getMemberByName(this.state.groups.hud, 'defText').text = this.properties.defense; 43 | getMemberByName(this.state.groups.hud, 'healthText').text = this.properties.health; 44 | getMemberByName(this.state.groups.hud, 'speedText').text = this.properties.speed; 45 | 46 | this.properties.rotationSpeed = this.properties.speed / 17; 47 | this.properties.maxSpeed = this.properties.speed * 2.5; 48 | this.body.maxVelocity.setTo(this.properties.maxSpeed); 49 | } 50 | 51 | Bots.Robot.prototype.update = function () { 52 | Bots.DroppableRobot.prototype.update(this); 53 | 54 | if (this.body) { 55 | this.body.angularAcceleration = 0; 56 | this.body.velocity.x = 0; 57 | this.body.velocity.y = 0; 58 | this.body.angularVelocity = 0; 59 | 60 | if (!this.stunned) { 61 | if (this.dropped && !this.isDead) { 62 | if (this.game.device.desktop) { 63 | if (this.game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) { 64 | this.angle -= this.properties.rotationSpeed; 65 | } else if (this.game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) { 66 | this.angle += this.properties.rotationSpeed; 67 | } 68 | 69 | if (this.game.input.keyboard.isDown(Phaser.Keyboard.UP)) { 70 | this.currentSpeed = this.properties.maxSpeed * this.speedMultiplier; 71 | } else if (this.game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { 72 | this.currentSpeed = -this.properties.maxSpeed * this.speedMultiplier; 73 | } 74 | 75 | if (this.game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR)) { 76 | Bots.DroppableRobot.prototype.fire.call(this); 77 | } 78 | } else { 79 | if (this.dpad && this.dpad.isPressed) { 80 | const angle = this.dpad.dpadAngle(); 81 | if (angle) { 82 | this.angle = angle; 83 | this.currentSpeed = this.properties.maxSpeed * this.speedMultiplier; 84 | } 85 | } 86 | 87 | if (this.shootButton && this.shootButton.isPressed) { 88 | Bots.DroppableRobot.prototype.fire.call(this); 89 | } 90 | 91 | if (this.menuButton) { 92 | const panel = getMemberByName(this.state.groups.panel, 'statisticsPanel'); 93 | panel.show(this.menuButton.isPressed); 94 | panel.update(); 95 | } 96 | } 97 | 98 | if (this.currentSpeed > 0) { 99 | this.currentSpeed -= this.properties.friction; 100 | } else { 101 | this.currentSpeed += this.properties.friction; 102 | } 103 | 104 | if (Math.abs(this.currentSpeed) <= this.properties.friction) { 105 | this.currentSpeed = 0; 106 | } 107 | 108 | if (this.currentSpeed !== 0) { 109 | this.game.physics.arcade.velocityFromRotation(this.rotation, this.currentSpeed, this.body.velocity); 110 | 111 | if (!this.trackTimer) { 112 | this.trackTimer = this.game.time.events.loop(100, function () { 113 | getMemberByName(this.state.groups.spawners, 'trackSpawner').spawn(this); 114 | }, this); 115 | } 116 | } else { 117 | this.game.time.events.remove(this.trackTimer); 118 | this.trackTimer = 0; 119 | } 120 | } 121 | } 122 | } 123 | } 124 | 125 | Bots.Robot.prototype.onBulletChestCollide = function (bullet, chest) { 126 | bullet.kill(); 127 | chest.kill(); 128 | } 129 | 130 | Bots.Robot.prototype.onBulletRobotCollide = function (bullet, robot) { 131 | if (robot !== this) { 132 | bullet.kill(); 133 | robot.animateDeath(); 134 | } 135 | } 136 | 137 | Bots.Robot.prototype.onBulletRobotCollideProcess = function (bullet, robot) { 138 | return robot !== this; 139 | } -------------------------------------------------------------------------------- /js/prefabs/robotSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.RobotSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.RobotSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.RobotSpawner.prototype.constructor = Bots.RobotSpawner; 13 | 14 | Bots.RobotSpawner.prototype.createObject = function (name, position) { 15 | const properties = this.robotStats(); 16 | 17 | return new Bots.Robot(this.state, name, position, { 18 | group: "robots", 19 | key: this.properties.spawnKey, 20 | friction: 10, 21 | attack: properties.attack, 22 | defense: properties.defense, 23 | speed: properties.speed, 24 | health: properties.health, 25 | maxHealth: properties.maxHealth, 26 | displayName: "Player", 27 | scaleMultiplier: 1 28 | }); 29 | } 30 | 31 | Bots.RobotSpawner.prototype.robotStats = function () { 32 | switch (this.properties.spawnKey) { 33 | case 'robot3Dred': 34 | return { 35 | attack: 70, 36 | defense: 70, 37 | speed: 90, 38 | health: 200, 39 | maxHealth: 200 40 | }; 41 | 42 | case 'robot3Dgreen': 43 | return { 44 | attack: 50, 45 | defense: 50, 46 | speed: 80, 47 | health: 150, 48 | maxHealth: 150 49 | }; 50 | 51 | case 'robot3Dyellow': 52 | return { 53 | attack: 40, 54 | defense: 45, 55 | speed: 70, 56 | health: 120, 57 | maxHealth: 120 58 | }; 59 | 60 | case 'robot3Dblue': 61 | return { 62 | attack: 40, 63 | defense: 40, 64 | speed: 65, 65 | health: 110, 66 | maxHealth: 110 67 | }; 68 | 69 | default: 70 | return { 71 | attack: 34, 72 | defense: 48, 73 | speed: 70, 74 | health: 100, 75 | maxHealth: 100 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /js/prefabs/selectableSprite.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.SelectableSprite = function (state, name, position, properties) { 9 | Bots.Prefab.call(this, state, name, position, properties); 10 | 11 | this.isSelected = false; 12 | this.frameGraphic = this.game.add.graphics(0, 0); 13 | this.addChild(this.frameGraphic); 14 | 15 | this.inputEnabled = true; 16 | this.events.onInputUp.add(() => { 17 | if (!this.game.paused || this.properties.force) { 18 | if (Bots.soundsEnabled) { 19 | this.state.prefabs.clickSound.safelyPlay(); 20 | } 21 | 22 | this.isSelected = true; 23 | properties.parent.onTileSelected(this); 24 | } 25 | }, this); 26 | 27 | this.game.physics.enable(this, Phaser.Physics.ARCADE); 28 | 29 | if (this.properties.shadow) { 30 | this.shadowGraphic = this.game.add.graphics(0, 0); 31 | this.state.groups[properties.group].addAt(this.shadowGraphic, 0); 32 | } 33 | }; 34 | 35 | Bots.SelectableSprite.prototype = Object.create(Bots.Prefab.prototype); 36 | Bots.SelectableSprite.prototype.constructor = Bots.SelectableSprite; 37 | 38 | Bots.SelectableSprite.prototype.update = function () { 39 | this.frameGraphic.clear(); 40 | 41 | if (this.properties.shadow) { 42 | this.shadowGraphic.clear(); 43 | this.shadowGraphic.beginFill(0x000000); 44 | this.shadowGraphic.drawRect(this.x - this.width * this.scale.x + 2, this.y - this.height * this.scale.y + 2, this.width, this.height); 45 | this.shadowGraphic.endFill(); 46 | } 47 | 48 | this.frameGraphic.lineStyle(1, 0x000000, 1); 49 | this.frameGraphic.beginFill(0x000000, this.isSelected ? 0 : 0.25); 50 | this.frameGraphic.drawRect(-this.width / 2 / this.scale.x, -this.height / 2 / this.scale.y, this.width / this.scale.x, this.height / this.scale.y); 51 | this.frameGraphic.endFill(); 52 | } -------------------------------------------------------------------------------- /js/prefabs/smoke.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 21/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.Smoke = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | const initialScale = this.scale; 11 | 12 | this.game.physics.enable(this, Phaser.Physics.ARCADE); 13 | this.game.add.tween(this.scale).to({ 14 | x: initialScale.x * 3, 15 | y: initialScale.y * 3 16 | }, 5000, Phaser.Easing.Quartic.In, true) 17 | this.game.add.tween(this).to({ alpha: 0 }, 3000, Phaser.Easing.Quartic.In, true) 18 | .onComplete.add(() => killFromGroup(this, this.state.groups[this.properties.group]), this); 19 | }; 20 | 21 | Bots.Smoke.prototype = Object.create(Bots.Prefab.prototype); 22 | Bots.Smoke.prototype.constructor = Bots.Smoke; -------------------------------------------------------------------------------- /js/prefabs/smokeSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.SmokeSpwaner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.SmokeSpwaner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.SmokeSpwaner.prototype.constructor = Bots.SmokeSpwaner; 13 | 14 | Bots.SmokeSpwaner.prototype.spawn = function (object) { 15 | let probability = 0; 16 | 17 | if (object.properties.health <= object.properties.maxHealth * 0.5) { 18 | probability = 0.4; 19 | } 20 | 21 | if (object.properties.health <= object.properties.maxHealth * 0.25) { 22 | probability = 1; 23 | } 24 | 25 | if (this.game.rnd.frac() <= probability) { 26 | return this.createObject('randomName', object) 27 | } 28 | } 29 | 30 | Bots.SmokeSpwaner.prototype.createObject = function (name, position) { 31 | const scale = this.game.rnd.realInRange(0.5, 2); 32 | const maxOffset = 30; 33 | const offset = new Phaser.Point(this.game.rnd.integerInRange(-maxOffset, maxOffset), this.game.rnd.integerInRange(-maxOffset, maxOffset)); 34 | 35 | const properties = { 36 | key: 'blackSmoke', 37 | group: this.properties.pool, 38 | alpha: this.game.rnd.realInRange(0.7, 1), 39 | scale: { 40 | x: scale, 41 | y: scale 42 | }, 43 | angle: this.game.rnd.integerInRange(0, 360), 44 | anchor: { 45 | x: 0.5, 46 | y: 0.5 47 | } 48 | } 49 | 50 | return new Bots.Smoke(this.state, name, new Phaser.Point(position.x + offset.x, position.y + offset.y), properties); 51 | } -------------------------------------------------------------------------------- /js/prefabs/soundPrefab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.SoundPrefab = function (state, name, position, properties) { 9 | Phaser.Sound.call(this, state.game, properties.key); 10 | 11 | this.name = name; 12 | this.properties = properties; 13 | this.game = state.game; 14 | this.isPrepared = false; 15 | this.isKilled = false; 16 | 17 | this.game.sound.setDecodedCallback([this], () => { 18 | this.isPrepared = true; 19 | if (properties.playAfterDecode) { 20 | this.safelyPlay(); 21 | } 22 | }, this); 23 | }; 24 | 25 | Bots.SoundPrefab.prototype = Object.create(Phaser.Sound.prototype); 26 | Bots.SoundPrefab.prototype.constructor = Bots.SoundPrefab; 27 | 28 | Bots.SoundPrefab.prototype.safelyPlay = function () { 29 | if (!this.isKilled && this.isPrepared) { 30 | this.play('', 0, 1, false, false); 31 | } 32 | } -------------------------------------------------------------------------------- /js/prefabs/soundSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.SoundSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.SoundSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.SoundSpawner.prototype.constructor = Bots.SoundSpawner; 13 | 14 | Bots.SoundSpawner.prototype.spawn = function (source, key) { 15 | if (Bots.soundsEnabled) { 16 | const humanRobot = getHumanRobot(this.state.groups.robots); 17 | 18 | if (humanRobot) { 19 | const distance = this.game.physics.arcade.distanceBetween(source, humanRobot); 20 | if (distance < 300) { 21 | const sound = this.createObject(`sound_${key}`, key); 22 | } 23 | } 24 | } 25 | } 26 | 27 | Bots.SoundSpawner.prototype.createObject = function (name, key) { 28 | const properties = { 29 | key, 30 | playAfterDecode: true, 31 | killAfterPlay: true 32 | }; 33 | 34 | return new Bots.SoundPrefab(this.state, name, new Phaser.Point(0, 0), properties); 35 | }; -------------------------------------------------------------------------------- /js/prefabs/spawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.Spawner = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | this.pool = this.state.groups[properties.pool]; 11 | 12 | this.spawnTime = properties.spawnTimeInSeconds; 13 | this.spawnTimer = this.game.time.create(); 14 | 15 | this.scheduleSpawn(); 16 | } 17 | 18 | Bots.Spawner.prototype = Object.create(Bots.Prefab.prototype); 19 | Bots.Spawner.prototype.constructor = Bots.Spawner; 20 | 21 | Bots.Spawner.prototype.scheduleSpawn = function () { 22 | if (this.properties.mode !== 'never') { 23 | const time = this.game.rnd.between(this.spawnTime.min, this.spawnTime.max); 24 | 25 | this.spawnTimer.add(Phaser.Timer.SECOND * time, this.spawn, this); 26 | this.spawnTimer.start(); 27 | } 28 | } 29 | 30 | Bots.Spawner.prototype.spawn = function () { 31 | if (this.isAllowedToSpawn()) { 32 | const position = new Phaser.Point(this.game.rnd.between(-Bots.worldSize.x / 2, Bots.worldSize.x / 2), this.game.rnd.between(-Bots.worldSize.y / 2, Bots.worldSize.y / 2)); 33 | 34 | let object = this.pool.getFirstDead(); 35 | if (object) { 36 | object.reset(position.x, position.y); 37 | } else { 38 | const name = `object_${this.pool.countLiving()}`; 39 | object = this.createObject(name, position); 40 | } 41 | } 42 | 43 | if (this.properties.mode === 'infinite' || this.properties.mode === 'limited') { 44 | this.scheduleSpawn(); 45 | } 46 | } 47 | 48 | Bots.Spawner.prototype.isAllowedToSpawn = function () { 49 | return this.properties.mode === 'once' || 50 | this.properties.mode === 'infinite' || 51 | (this.properties.mode === 'limited' && this.pool.countLiving() < this.properties.limit); 52 | } -------------------------------------------------------------------------------- /js/prefabs/statisticsPanel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 24/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.StatisticsPanel = function (state, name, position, properties) { 10 | Bots.Prefab.call(this, state, name, position, properties); 11 | 12 | this.fixedToCamera = true; 13 | this.alpha = 0; 14 | 15 | this.topLeft = new Phaser.Point(50, 50); 16 | this.bottomRight = new Phaser.Point(Bots.screenSize.x - 50, Bots.screenSize.y - 50); 17 | this.panelSize = new Phaser.Point(this.bottomRight.x - this.topLeft.x, this.bottomRight.y - this.topLeft.y); 18 | 19 | this.graphics = this.game.add.graphics(0, 0); 20 | this.graphics.beginFill(0x000000, 0.75); 21 | this.graphics.drawRect(this.topLeft.x, this.topLeft.y, this.panelSize.x, this.panelSize.y); 22 | this.graphics.endFill(); 23 | this.addChild(this.graphics); 24 | 25 | this.rankText = this.game.add.text(this.topLeft.x + 16, this.topLeft.y + 16, 'Rank', this.captionTextStyle()); 26 | this.addChild(this.rankText); 27 | 28 | this.rankTexts = []; 29 | for (let i = 0; i < 12; i++) { 30 | const rankText = this.game.add.text(this.topLeft.x + 16, this.topLeft.y + 48 + i * 16, '', this.regularTextStyle()); 31 | this.addChild(rankText); 32 | 33 | this.rankTexts.push(rankText); 34 | } 35 | 36 | this.playerText = this.game.add.text(this.topLeft.x + 16 + 100, this.topLeft.y + 16, 'Player', this.captionTextStyle()); 37 | this.addChild(this.playerText); 38 | 39 | this.player = this.game.add.sprite(this.topLeft.x + 100 + 40, this.topLeft.y + 48 + 40, Bots.humanRobotKey); 40 | this.player.anchor.setTo(0.5); 41 | this.player.scale.x = Bots.scale * 0.9; 42 | this.player.scale.y = Bots.scale * 0.9; 43 | this.game.add.tween(this.player).to({ angle: 360 }, 30000, Phaser.Easing.Linear.None, true, 0, -1); 44 | this.addChild(this.player); 45 | 46 | this.attackText = this.game.add.text(this.topLeft.x + 16 + 100, this.topLeft.y + 48 + 64 + 32, 'Atl\t120', this.regularTextStyleWithTabs(48)); 47 | this.addChild(this.attackText); 48 | 49 | this.defenseText = this.game.add.text(this.topLeft.x + 16 + 100, this.topLeft.y + 48 + 64 + 48, 'Def\t120', this.regularTextStyleWithTabs(48)); 50 | this.addChild(this.defenseText); 51 | 52 | this.healthText = this.game.add.text(this.topLeft.x + 16 + 100, this.topLeft.y + 48 + 64 + 64, 'HP\t4800', this.regularTextStyleWithTabs(48)); 53 | this.addChild(this.healthText); 54 | 55 | this.speedText = this.game.add.text(this.topLeft.x + 16 + 100, this.topLeft.y + 48 + 64 + 80, 'Spd\t120', this.regularTextStyleWithTabs(48)); 56 | this.addChild(this.speedText); 57 | 58 | this.killsText = this.game.add.text(this.topLeft.x + 16 + 100, this.topLeft.y + 48 + 64 + 96, 'Kills\t120', this.regularTextStyleWithTabs(48)); 59 | this.addChild(this.killsText); 60 | 61 | this.deathsText = this.game.add.text(this.topLeft.x + 16 + 100, this.topLeft.y + 48 + 64 + 112, 'Deaths\t120', this.regularTextStyleWithTabs(48)); 62 | this.addChild(this.deathsText); 63 | 64 | this.helpText = this.game.add.text(this.topLeft.x + 200, this.topLeft.y + 16, 'Help', this.captionTextStyle()); 65 | this.addChild(this.helpText); 66 | 67 | [ 68 | 'Up\tMove forwards', 69 | 'Down\tMove backwards', 70 | 'Left\tTurn left', 71 | 'Right\tTurn right', 72 | 'Space\tShoot', 73 | 'Shift\tShow info dialog', 74 | '', 75 | 'Minimap:', 76 | 'Blue\tYou', 77 | 'White\tEnemies', 78 | 'Red\tBoss', 79 | 'Green\tChests' 80 | ].forEach((item, index) => { 81 | const text = this.game.add.text(this.topLeft.x + 200, this.topLeft.y + 48 + index * 16, item, this.regularTextStyleWithTabs(52)); 82 | this.addChild(text); 83 | }); 84 | 85 | this.objectiveText = this.game.add.text(this.topLeft.x + 360, this.topLeft.y + 16, 'Objective', this.captionTextStyle()); 86 | this.addChild(this.objectiveText); 87 | 88 | this.player1 = this.game.add.sprite(this.topLeft.x + 16 + 400, this.topLeft.y + 64, Bots.humanRobotKey); 89 | this.player1.anchor.setTo(0.5); 90 | this.player1.scale.setTo(Bots.scale * 0.7); 91 | this.player1.angle = 355; 92 | this.addChild(this.player1); 93 | 94 | this.player2 = this.game.add.sprite(this.topLeft.x + 16 + 484, this.topLeft.y + 64, sample(['robot3Dgreen', 'robot3Dred', 'robot3Dyellow', 'robot3Dblue'], Bots.humanRobotKey)); 95 | this.player2.anchor.setTo(0.5); 96 | this.player2.scale.setTo(Bots.scale * 0.7); 97 | this.player2.angle = 95; 98 | this.addChild(this.player2); 99 | 100 | this.rocket1 = this.game.add.sprite(this.topLeft.x + 16 + 442, this.topLeft.y + 64, 'logoBulletRight'); 101 | this.rocket1.anchor.setTo(0.5); 102 | this.rocket1.scale.setTo(Bots.scale); 103 | this.rocket1.angle = 355; 104 | this.addChild(this.rocket1); 105 | 106 | this.player3 = this.game.add.sprite(this.topLeft.x + 16 + 400, this.topLeft.y + 128, Bots.humanRobotKey); 107 | this.player3.anchor.setTo(0.5); 108 | this.player3.scale.setTo(Bots.scale * 0.7); 109 | this.player3.angle = 350; 110 | this.addChild(this.player3); 111 | 112 | this.chest = this.game.add.sprite(this.topLeft.x + 16 + 484, this.topLeft.y + 118, 'crate_45'); 113 | this.chest.anchor.setTo(0.5); 114 | this.chest.scale.setTo(Bots.scale * 0.7); 115 | this.chest.angle = 95; 116 | this.addChild(this.chest); 117 | 118 | this.rocket2 = this.game.add.sprite(this.topLeft.x + 16 + 442, this.topLeft.y + 128, 'logoBulletRight'); 119 | this.rocket2.anchor.setTo(0.5); 120 | this.rocket2.scale.setTo(Bots.scale); 121 | this.rocket2.angle = 350; 122 | this.addChild(this.rocket2); 123 | 124 | this.player4 = this.game.add.sprite(this.topLeft.x + 16 + 400, this.topLeft.y + 192, Bots.humanRobotKey); 125 | this.player4.anchor.setTo(0.5); 126 | this.player4.scale.setTo(Bots.scale * 0.7); 127 | this.player4.angle = 190; 128 | this.addChild(this.player4); 129 | 130 | this.player5 = this.game.add.sprite(this.topLeft.x + 16 + 484, this.topLeft.y + 192, sample(['robot3Dgreen', 'robot3Dred', 'robot3Dyellow', 'robot3Dblue'], Bots.humanRobotKey)); 131 | this.player5.anchor.setTo(0.5); 132 | this.player5.scale.setTo(Bots.scale * 0.7); 133 | this.player5.angle = 170; 134 | this.addChild(this.player5); 135 | 136 | this.rocket3 = this.game.add.sprite(this.topLeft.x + 16 + 442, this.topLeft.y + 192, 'logoBulletRight'); 137 | this.rocket3.anchor.setTo(0.5); 138 | this.rocket3.scale.setTo(Bots.scale); 139 | this.rocket3.angle = 170; 140 | this.addChild(this.rocket3); 141 | 142 | this.checkmark1 = this.game.add.sprite(this.topLeft.x + 16 + 360, this.topLeft.y + 64, 'uiCheckmark'); 143 | this.checkmark1.anchor.setTo(0.5); 144 | this.checkmark1.scale.setTo(0.5); 145 | this.checkmark1.tint = 0x00ff00; 146 | this.addChild(this.checkmark1); 147 | 148 | this.checkmark2 = this.game.add.sprite(this.topLeft.x + 16 + 360, this.topLeft.y + 128, 'uiCheckmark'); 149 | this.checkmark2.anchor.setTo(0.5); 150 | this.checkmark2.scale.setTo(0.5); 151 | this.checkmark2.tint = 0x00ff00; 152 | this.addChild(this.checkmark2); 153 | 154 | this.cross1 = this.game.add.sprite(this.topLeft.x + 16 + 360, this.topLeft.y + 192, 'uiCross'); 155 | this.cross1.anchor.setTo(0.5); 156 | this.cross1.scale.setTo(0.5); 157 | this.cross1.tint = 0xff0000; 158 | this.addChild(this.cross1); 159 | }; 160 | 161 | Bots.StatisticsPanel.prototype = Object.create(Bots.Prefab.prototype); 162 | Bots.StatisticsPanel.prototype.constructor = Bots.StatisticsPanel; 163 | 164 | Bots.StatisticsPanel.prototype.captionTextStyle = function () { 165 | return { 166 | font: '12pt bold Helvetica, sans-serif', 167 | fill: '#ffffff', 168 | align: 'left' 169 | } 170 | } 171 | 172 | Bots.StatisticsPanel.prototype.regularTextStyle = function (fontSize = 10) { 173 | return { 174 | font: `${fontSize}pt Helvetica, sans-serif`, 175 | fill: '#ffffff', 176 | align: 'left' 177 | } 178 | } 179 | 180 | Bots.StatisticsPanel.prototype.regularTextStyleWithTabs = function (tabWidth, fontsize) { 181 | const style = Object.assign({}, this.regularTextStyle()); 182 | style.tabs = tabWidth; 183 | 184 | return style; 185 | } 186 | 187 | Bots.StatisticsPanel.prototype.show = function (show) { 188 | this.alpha = show ? 1 : 0; 189 | } 190 | 191 | Bots.StatisticsPanel.prototype.update = function () { 192 | if (this.alpha === 1) { 193 | const robotNamesWithLevel = []; 194 | this.state.groups.robots.forEachAlive((robot) => { 195 | robotNamesWithLevel.push({ 196 | name: robot.properties.displayName, 197 | level: parseInt(robot.killCounter.text) 198 | }); 199 | }); 200 | 201 | robotNamesWithLevel 202 | .sort((l, r) => r.level - l.level) 203 | .slice(0, this.rankTexts.length) 204 | .forEach((robot, index) => { 205 | this.rankTexts[index].text = `${robot.level} ${shortenName(robot.name, 8)}`; 206 | }); 207 | 208 | this.attackText.text = `Atk\t${getMemberByName(this.state.groups.hud, 'atkText').text}`; 209 | this.defenseText.text = `Def\t${getMemberByName(this.state.groups.hud, 'defText').text}`; 210 | this.healthText.text = `HP\t${getMemberByName(this.state.groups.hud, 'healthText').text}`; 211 | this.speedText.text = `Spd\t${getMemberByName(this.state.groups.hud, 'speedText').text}`; 212 | this.killsText.text = `Kills\t${Bots.killCount}`; 213 | this.deathsText.text = `Deaths\t${Bots.deathCount}`; 214 | } 215 | } -------------------------------------------------------------------------------- /js/prefabs/textPrefab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.TextPrefab = function (state, name, position, properties) { 9 | Phaser.Text.call(this, state.game, position.x, position.y, properties.text, properties.style); 10 | 11 | this.state = state; 12 | this.name = name; 13 | this.properties = properties; 14 | this.state.prefabs[name] = this; 15 | this.game = state.game; 16 | 17 | if (properties.group) { 18 | this.state.groups[properties.group].add(this); 19 | } 20 | 21 | if (properties.anchor) { 22 | this.anchor.setTo(properties.anchor.x, properties.anchor.y); 23 | } 24 | 25 | if (properties.scale) { 26 | this.scale.setTo(properties.scale.x, properties.scale.y); 27 | } 28 | 29 | if (properties.alpha) { 30 | this.alpha = properties.alpha; 31 | } 32 | 33 | this.fixedToCamera = properties.fixedToCamera; 34 | 35 | if (properties.size) { 36 | this.autoSize(properties.size.width, properties.size.height); 37 | } 38 | 39 | if (properties.lineSpacing) { 40 | this.lineSpacing = properties.lineSpacing; 41 | } 42 | 43 | if (properties.shadow) { 44 | this.setShadow(2, 2, 'rgba(0,0,0,0.5)', 0); 45 | } 46 | }; 47 | 48 | Bots.TextPrefab.prototype = Object.create(Phaser.Text.prototype); 49 | Bots.TextPrefab.prototype.constructor = Bots.TextPrefab; 50 | 51 | Bots.TextPrefab.prototype.autoSize = function (width, height) { 52 | if (!this.defaultFontSize) { 53 | this.defaultFontSize = this.fontSize; 54 | } 55 | 56 | if (width > 0 && height > 0) { 57 | this.fontSize = 64; 58 | let size = this.fontSize; 59 | while (this.fontSize > 4) { 60 | if (this.width < width && this.height < height) { 61 | return size; 62 | } 63 | 64 | this.fontSize = --size; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /js/prefabs/textSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.TextSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | 10 | this.texts = []; 11 | this.maximumRows = this.properties.maximumRows || 5; 12 | this.fontSize = this.properties.fontSize || 8; 13 | }; 14 | 15 | Bots.TextSpawner.prototype = Object.create(Bots.Spawner.prototype); 16 | Bots.TextSpawner.prototype.constructor = Bots.TextSpawner; 17 | 18 | Bots.TextSpawner.prototype.spawn = function (text) { 19 | const position = new Phaser.Point(Bots.screenSize.x / 2, 100); 20 | 21 | let textPrefab = this.pool.getFirstDead(); 22 | if (textPrefab) { 23 | textPrefab.reset(position.x, position.y); 24 | } else { 25 | const name = `textPrefab_${this.pool.countLiving()}`; 26 | const textPrefabOrNull = this.createObject(name, position, text); 27 | 28 | if (textPrefabOrNull) { 29 | textPrefab = textPrefabOrNull; 30 | } 31 | } 32 | } 33 | 34 | Bots.TextSpawner.prototype.createObject = function (name, position, text) { 35 | position = this.nextPosition(); 36 | 37 | const result = new Bots.TextPrefab(this.state, name, position, { 38 | group: 'hud', 39 | text: text, 40 | fixedToCamera: true, 41 | style: { 42 | font: `${this.fontSize}pt Arial`, 43 | fill: '#ffffff', 44 | align: 'left' 45 | }, 46 | anchor: { 47 | x: 0, 48 | y: 0.5 49 | } 50 | }); 51 | 52 | const indexOfPlayer = text.indexOf('Player'); 53 | 54 | if (indexOfPlayer >= 0) { 55 | result.addColor('#0000ff', indexOfPlayer); 56 | result.addColor('#ffffff', indexOfPlayer + 6); 57 | } 58 | 59 | this.texts.push(result); 60 | return result; 61 | } 62 | 63 | Bots.TextSpawner.prototype.nextPosition = function () { 64 | if (this.texts.length >= this.maximumRows) { 65 | this.texts.forEach(text => { 66 | text.cameraOffset.y -= this.fontSize * 1.6; 67 | 68 | }); 69 | killFromGroup(this.texts[0], this.state.groups.hud); 70 | this.texts.shift(); 71 | } 72 | 73 | return new Phaser.Point(48, 18 + this.texts.length * this.fontSize * 1.6); 74 | } -------------------------------------------------------------------------------- /js/prefabs/tileSprite.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 16/07/17. 3 | */ 4 | 5 | "use strict"; 6 | 7 | var Bots = Bots || {}; 8 | 9 | Bots.TileSprite = function (state, name, position, properties) { 10 | Phaser.TileSprite.call(this, state.game, position.x, position.y, properties.size.width, properties.size.height, properties.key); 11 | 12 | this.state = state; 13 | this.name = name; 14 | this.properties = properties; 15 | this.state.prefabs[name] = this; 16 | this.fixedToCamera = !!properties.fixedToCamera; 17 | 18 | if (properties.group) { 19 | this.state.groups[properties.group].add(this); 20 | } 21 | 22 | if (properties.frame) { 23 | this.frame = properties.frame; 24 | } 25 | 26 | if (properties.anchor) { 27 | this.anchor.setTo(properties.anchor.x, properties.anchor.y); 28 | } 29 | }; 30 | 31 | Bots.TileSprite.prototype = Object.create(Phaser.TileSprite.prototype); 32 | Bots.TileSprite.prototype.constructor = Bots.TileSprite; 33 | 34 | Bots.TileSprite.prototype.update = function () { 35 | if (this.properties.fixedToCamera) { 36 | this.tilePosition.x = -this.game.camera.x; 37 | this.tilePosition.y = -this.game.camera.y; 38 | } 39 | } -------------------------------------------------------------------------------- /js/prefabs/track.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 21/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | 7 | Bots.Track = function (state, name, position, properties) { 8 | Bots.Prefab.call(this, state, name, position, properties); 9 | 10 | this.game.add.tween(this).to({ alpha: 0 }, 1000, Phaser.Easing.Quartic.In, true).onComplete.add(function () { 11 | this.kill(); 12 | this.destroy(); 13 | this.state.groups[this.properties.group].remove(this); 14 | }, this); 15 | }; 16 | 17 | Bots.Track.prototype = Object.create(Bots.Prefab.prototype); 18 | Bots.Track.prototype.constructor = Bots.Track; -------------------------------------------------------------------------------- /js/prefabs/trackSpawner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 15/07/17. 3 | */ 4 | 5 | var Bots = Bots || {}; 6 | 7 | Bots.TrackSpawner = function (state, name, position, properties) { 8 | Bots.Spawner.call(this, state, name, position, properties); 9 | }; 10 | 11 | Bots.TrackSpawner.prototype = Object.create(Bots.Spawner.prototype); 12 | Bots.TrackSpawner.prototype.constructor = Bots.TrackSpawner; 13 | 14 | Bots.TrackSpawner.prototype.spawn = function (robot) { 15 | const position = new Phaser.Point(robot.x, robot.y); 16 | 17 | let track = this.pool.getFirstDead(); 18 | if (track) { 19 | track.reset(position.x, position.y); 20 | } else { 21 | const name = `track_${this.pool.countLiving()}`; 22 | const trackOrNull = this.createObject(name, position, robot); 23 | 24 | if (trackOrNull) { 25 | track = trackOrNull; 26 | } 27 | } 28 | } 29 | 30 | Bots.TrackSpawner.prototype.createObject = function (name, position, robot) { 31 | if (robot) { 32 | const properties = { 33 | key: 'tracks', 34 | group: 'ground', 35 | angle: robot.angle, 36 | alpha: 0.5, 37 | anchor: { 38 | x: 0.5, 39 | y: 0.5 40 | } 41 | } 42 | 43 | return new Bots.Track(this.state, name, position, properties); 44 | } 45 | 46 | return null; 47 | } -------------------------------------------------------------------------------- /js/states/boot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.Boot = function () { 9 | Phaser.State.call(this); 10 | }; 11 | 12 | Bots.Boot.prototype = Object.create(Phaser.State.prototype); 13 | Bots.Boot.prototype.constructor = Bots.Boot; 14 | 15 | Bots.Boot.prototype.init = function (data) { 16 | this.data = data; 17 | }; 18 | 19 | Bots.Boot.prototype.preload = function () { 20 | for (const name in this.data) { 21 | if (this.data.hasOwnProperty(name)) { 22 | this.load.text(name, this.data[name]); 23 | } 24 | } 25 | 26 | }; 27 | 28 | Bots.Boot.prototype.create = function () { 29 | var content = this.game.cache.getText('menu'); 30 | var payload = JSON.parse(content); 31 | 32 | this.prepareScreenForScaling(); 33 | this.game.state.start('loading', true, false, payload, 'menu'); 34 | }; 35 | 36 | Bots.Boot.prototype.prepareScreenForScaling = function () { 37 | this.game.stage.disableVisibilityChange = true; 38 | 39 | this.game.scale.maxWidth = window.innerWidth * window.devicePixelRatio; 40 | this.game.scale.maxHeight = window.innerHeight * window.devicePixelRatio; 41 | this.game.scale.pageAlignVertically = true; 42 | this.game.scale.pageAlignHorizontally = true; 43 | this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; 44 | this.game.scale.windowConstraints.bottom = 'visual'; 45 | } -------------------------------------------------------------------------------- /js/states/credits.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 22/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | Bots.Credits = function () { 7 | Phaser.State.call(this); 8 | 9 | this.prefabClasses = { 10 | 'sprite': Bots.Prefab.prototype.constructor, 11 | 'tileSprite': Bots.TileSprite.prototype.constructor, 12 | 'button': Bots.Button.prototype.constructor, 13 | 'creditsItem': Bots.CreditsItem.prototype.constructor, 14 | 'creditsItemSpawner': Bots.CreditsItemSpawner.prototype.constructor, 15 | 'text': Bots.TextPrefab.prototype.constructor, 16 | 'sound': Bots.SoundPrefab.prototype.constructor 17 | } 18 | }; 19 | 20 | Bots.Credits.prototype = Object.create(Phaser.State.prototype); 21 | Bots.Credits.prototype.constructor = Bots.Credits; 22 | 23 | Bots.Credits.prototype.create = function () { 24 | this.game.time.advancedTiming = true; 25 | } 26 | 27 | Bots.Credits.prototype.init = function (data) { 28 | this.data = data; 29 | this.game.physics.startSystem(Phaser.Physics.ARCADE); 30 | } 31 | 32 | Bots.Credits.prototype.create = function () { 33 | this.game.time.advancedTiming = true 34 | 35 | this.game.stage.backgroundColor = '#212A31'; 36 | this.groups = {}; 37 | this.prefabs = {}; 38 | 39 | this.data.groups.forEach(groupName => (this.groups[groupName] = this.game.add.group()), this); 40 | for (var prefabName in this.data.prefabs) { 41 | if (this.data.prefabs.hasOwnProperty(prefabName)) { 42 | this.createPrefab(prefabName, this.data.prefabs[prefabName]); 43 | } 44 | } 45 | 46 | this.game.add.tween(this.groups.credits).to({ y: -1000 }, 120000, Phaser.Easing.Linear.None, true, 5000); 47 | }; 48 | 49 | Bots.Credits.prototype.createPrefab = function (prefabName, properties) { 50 | if (this.prefabClasses.hasOwnProperty(properties.type)) { 51 | const position = new Phaser.Point(properties.position.x, properties.position.y); 52 | const prefab = new this.prefabClasses[properties.type](this, prefabName, position, properties.properties); 53 | 54 | this.prefabs[prefabName] = prefab; 55 | } 56 | }; 57 | 58 | Bots.Credits.prototype.onButtonPressed = function (button) { 59 | if (button.name === 'menuButton') { 60 | const content = this.game.cache.getText('menu'); 61 | const payload = JSON.parse(content); 62 | payload.prefabs.background.properties.key = Bots.background; 63 | this.game.state.start('loading', true, false, payload, 'menu'); 64 | } 65 | } -------------------------------------------------------------------------------- /js/states/level.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | Bots.Level = function () { 8 | Phaser.State.call(this); 9 | 10 | this.prefabClasses = { 11 | 'sprite': Bots.Prefab.prototype.constructor, 12 | 'tileSprite': Bots.TileSprite.prototype.constructor, 13 | 'robot': Bots.Robot.prototype.constructor, 14 | 'enemyRobot': Bots.EnemyRobot.prototype.constructor, 15 | 'spawner': Bots.Spawner.prototype.constructor, 16 | 'robotSpawner': Bots.RobotSpawner.prototype.constructor, 17 | 'enemyRobotSpawner': Bots.EnemyRobotSpawner.prototype.constructor, 18 | 'bossRobotSpawner': Bots.BossRobotSpawner.prototype.constructor, 19 | 'chestSpawner': Bots.ChestSpawner.prototype.constructor, 20 | 'chest': Bots.Chest.prototype.constructor, 21 | 'meteoritSpawner': Bots.MeteoritSpawner.prototype.constructor, 22 | 'meteorit': Bots.Meteorit.prototype.constructor, 23 | 'minimap': Bots.Minimap.prototype.constructor, 24 | 'text': Bots.TextPrefab.prototype.constructor, 25 | 'lootSpawner': Bots.LootSpawner.prototype.constructor, 26 | 'loot': Bots.Loot.prototype.constructor, 27 | 'explosionSpawner': Bots.ExplosionSpawner.prototype.constructor, 28 | 'smokeSpawner': Bots.SmokeSpwaner.prototype.constructor, 29 | 'earthQuakeSpawner': Bots.EarthQuakeSpawner.prototype.constructor, 30 | 'textSpawner': Bots.TextSpawner.prototype.constructor, 31 | 'soundSpawner': Bots.SoundSpawner.prototype.constructor, 32 | 'explosion': Bots.Explosion.prototype.constructor, 33 | 'dust': Bots.Dust.prototype.constructor, 34 | 'dustSpawner': Bots.DustSpawner.prototype.constructor, 35 | 'statisticsPanel': Bots.StatisticsPanel.prototype.constructor, 36 | 'oilSpawner': Bots.OilSpawner.prototype.constructor, 37 | 'track': Bots.Track.prototype.constructor, 38 | 'trackSpawner': Bots.TrackSpawner.prototype.constructor, 39 | 'button': Bots.Button.prototype.constructor, 40 | 'dpad': Bots.DPad.prototype.constructor, 41 | 'control': Bots.Control.prototype.constructor, 42 | 'pauseDialogSpawner': Bots.PauseDialogSpawner.prototype.constructor, 43 | 'messageSpawner': Bots.MessageSpawner.prototype.constructor, 44 | 'sound': Bots.SoundPrefab.prototype.constructor 45 | } 46 | }; 47 | 48 | Bots.Level.prototype = Object.create(Phaser.State.prototype); 49 | Bots.Level.prototype.constructor = Bots.Level; 50 | 51 | Bots.Level.prototype.init = function (data) { 52 | this.data = data; 53 | this.game.physics.startSystem(Phaser.Physics.ARCADE); 54 | }; 55 | 56 | Bots.Level.prototype.create = function () { 57 | this.game.time.advancedTiming = true 58 | 59 | this.game.stage.backgroundColor = '#212A31'; 60 | this.groups = {}; 61 | this.prefabs = {}; 62 | 63 | this.data.groups.forEach(groupName => (this.groups[groupName] = this.game.add.group()), this); 64 | for (var prefabName in this.data.prefabs) { 65 | if (this.data.prefabs.hasOwnProperty(prefabName)) { 66 | this.createPrefab(prefabName, this.data.prefabs[prefabName]); 67 | } 68 | } 69 | 70 | this.game.world.setBounds(-Bots.worldSize.x / 2, -Bots.worldSize.y / 2, Bots.worldSize.x, Bots.worldSize.y); 71 | Bots.killCount = 0; 72 | Bots.deathCount = 0; 73 | }; 74 | 75 | Bots.Level.prototype.createPrefab = function (prefabName, properties) { 76 | if (this.prefabClasses.hasOwnProperty(properties.type)) { 77 | const position = new Phaser.Point(properties.position.x, properties.position.y); 78 | const prefab = new this.prefabClasses[properties.type](this, prefabName, position, properties.properties); 79 | 80 | this.prefabs[prefabName] = prefab; 81 | } 82 | }; 83 | 84 | Bots.Level.prototype.update = function () { 85 | this.game.physics.arcade.collide(this.groups.chests, this.groups.robots); 86 | this.game.physics.arcade.collide(this.groups.robots, this.groups.robots, function (robot1, robot2) { 87 | if (robot1.boss && !robot2.isDead && !robot1.isDead) { 88 | robot1.killedOtherRobot(robot2); 89 | robot2.animateDeath(); 90 | } 91 | 92 | if (robot2.boss && !robot1.isDead && !robot2.isDead) { 93 | robot2.killedOtherRobot(robot1); 94 | robot1.animateDeath(); 95 | } 96 | }, null, this); 97 | 98 | const panel = getMemberByName(this.groups.panel, 'statisticsPanel'); 99 | if (panel) { 100 | panel.show(this.game.input.keyboard.isDown(Phaser.Keyboard.SHIFT)); 101 | } 102 | } 103 | 104 | Bots.Level.prototype.onButtonPressed = function (button) { 105 | if (button.name === 'menuButton') { 106 | const content = this.game.cache.getText('menu'); 107 | const payload = JSON.parse(content); 108 | payload.prefabs.background.properties.key = Bots.background; 109 | this.game.state.start('loading', true, false, payload, 'menu'); 110 | } 111 | } -------------------------------------------------------------------------------- /js/states/loading.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 11/07/17. 3 | */ 4 | 5 | 6 | let Bots = Bots || {}; 7 | 8 | Bots.Loading = function () { 9 | Phaser.State.call(this); 10 | }; 11 | 12 | Bots.prototype = Object.create(Phaser.State.prototype); 13 | Bots.prototype.constructor = Bots.Loading; 14 | 15 | Bots.Loading.prototype.init = function (data, nextState) { 16 | this.data = data; 17 | this.nextState = nextState; 18 | }; 19 | 20 | Bots.Loading.prototype.preload = function () { 21 | var assets = this.data.assets; 22 | 23 | for (var assetKey in assets) { 24 | if (assets.hasOwnProperty(assetKey)) { 25 | var asset = assets[assetKey]; 26 | 27 | switch (asset.type) { 28 | case "image": 29 | this.load.image(assetKey, asset.source); 30 | break; 31 | case "spritesheet": 32 | this.load.spritesheet(assetKey, asset.source, asset.frameWidth, asset.frameHeight, asset.frames, asset.margin || 0, asset.spacing || 0); 33 | break; 34 | case "sound": 35 | this.load.audio(assetKey, asset.source); 36 | break; 37 | } 38 | } 39 | } 40 | }; 41 | 42 | Bots.Loading.prototype.create = function () { 43 | this.game.state.start(this.nextState, true, false, this.data); 44 | }; -------------------------------------------------------------------------------- /js/states/menu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 22/07/17. 3 | */ 4 | 5 | let Bots = Bots || {}; 6 | Bots.Menu = function () { 7 | Phaser.State.call(this); 8 | 9 | this.prefabClasses = { 10 | 'sprite': Bots.Prefab.prototype.constructor, 11 | 'text': Bots.TextPrefab.prototype.constructor, 12 | 'animatedSprite': Bots.AnimatedSprite.prototype.constructor, 13 | 'tileSprite': Bots.TileSprite.prototype.constructor, 14 | 'button': Bots.Button.prototype.constructor, 15 | 'menuRobotChooser': Bots.MenuRobotChooser.prototype.constructor, 16 | 'menuBackgroundChooser': Bots.MenuBackgroundChooser.prototype.constructor, 17 | 'pauseDialogSpawner': Bots.PauseDialogSpawner.prototype.constructor, 18 | 'selectableSprite': Bots.SelectableSprite.prototype.constructor, 19 | 'sound': Bots.SoundPrefab.prototype.constructor, 20 | 'menuRobotSpawner': Bots.MenuRobotSpawner.prototype.constructor, 21 | 'sound': Bots.SoundPrefab.prototype.constructor 22 | } 23 | }; 24 | 25 | Bots.Menu.prototype = Object.create(Phaser.State.prototype); 26 | Bots.Menu.prototype.constructor = Bots.Menu; 27 | 28 | Bots.Menu.prototype.create = function () { 29 | this.game.time.advancedTiming = true; 30 | } 31 | 32 | Bots.Menu.prototype.init = function (data) { 33 | this.data = data; 34 | this.game.physics.startSystem(Phaser.Physics.ARCADE); 35 | } 36 | 37 | Bots.Menu.prototype.create = function () { 38 | this.game.time.advancedTiming = true 39 | 40 | this.game.stage.backgroundColor = '#212A31'; 41 | this.groups = {}; 42 | this.prefabs = {}; 43 | 44 | this.data.groups.forEach(groupName => (this.groups[groupName] = this.game.add.group()), this); 45 | for (var prefabName in this.data.prefabs) { 46 | if (this.data.prefabs.hasOwnProperty(prefabName)) { 47 | this.createPrefab(prefabName, this.data.prefabs[prefabName]); 48 | } 49 | } 50 | 51 | /* Animations */ 52 | 53 | /* Clouds */ 54 | this.game.add.tween(getMemberByName(this.groups.logo, 'middleCloud')) 55 | .to({ alpha: 1 }, 500, Phaser.Easing.Circular.InOut, true); 56 | this.game.add.tween(getMemberByName(this.groups.logo, 'leftCloud')) 57 | .to({ x: 35 }, 550, Phaser.Easing.Circular.InOut, true, 500) 58 | .onComplete.add(() => { 59 | getMemberByName(this.groups.logo, 'leftCloud').x = 35; 60 | this.game.add.tween(getMemberByName(this.groups.logo, 'leftCloud')) 61 | .to({ x: getMemberByName(this.groups.logo, 'leftCloud').x + 10 }, 5000, Phaser.Easing.Linear.None, true, 25, -1, true); 62 | this.game.add.tween(getMemberByName(this.groups.logo, 'leftCloud')) 63 | .to({ y: getMemberByName(this.groups.logo, 'leftCloud').y + 8 }, 7200, Phaser.Easing.Linear.None, true, 75, -1, true); 64 | }, this); 65 | this.game.add.tween(getMemberByName(this.groups.logo, 'rightCloud')) 66 | .to({ x: 500 }, 550, Phaser.Easing.Circular.InOut, true, 500) 67 | .onComplete.add(() => { 68 | getMemberByName(this.groups.logo, 'rightCloud').x = 500; 69 | this.game.add.tween(getMemberByName(this.groups.logo, 'rightCloud')) 70 | .to({ x: getMemberByName(this.groups.logo, 'rightCloud').x - 8 }, 4500, Phaser.Easing.Linear.None, true, 50, -1, true); 71 | this.game.add.tween(getMemberByName(this.groups.logo, 'rightCloud')) 72 | .to({ y: getMemberByName(this.groups.logo, 'rightCloud').y + 4 }, 9000, Phaser.Easing.Linear.None, true, 82, -1, true); 73 | }, this); 74 | 75 | /* robots */ 76 | this.game.add.tween(getMemberByName(this.groups.logo, 'logoRobotGreen')) 77 | .to({ alpha: 1, x: 442 }, 500, Phaser.Easing.Circular.InOut, true, 500); 78 | this.game.add.tween(getMemberByName(this.groups.logo, 'logoRobotRed')) 79 | .to({ alpha: 1, x: 274 }, 500, Phaser.Easing.Circular.InOut, true, 500); 80 | this.game.add.tween(getMemberByName(this.groups.logo, 'logoBulletRight')) 81 | .to({ alpha: 1, x: 510, y: 42 }, 500, Phaser.Easing.Circular.InOut, true, 500); 82 | this.game.add.tween(getMemberByName(this.groups.logo, 'logoBulletLeft')) 83 | .to({ alpha: 1, x: 194, y: 36 }, 500, Phaser.Easing.Circular.InOut, true, 500); 84 | 85 | /* chooser */ 86 | 87 | getMemberByName(this.groups.chooser, 'redRobotMoving').play('driving'); 88 | getMemberByName(this.groups.chooser, 'greenRobotMoving').play('driving'); 89 | getMemberByName(this.groups.chooser, 'greyRobotMoving').play('driving'); 90 | getMemberByName(this.groups.chooser, 'yellowRobotMoving').play('driving'); 91 | 92 | this.chooser = getMemberByName(this.groups.spawners, 'menuChooser'); 93 | this.chooser.showRobot(0, true); 94 | 95 | this.backgroundChooser = getMemberByName(this.groups.spawners, 'menuBackgroundChooser'); 96 | getMemberByName(this.groups.hud, 'soundButton').loadTexture(Bots.soundsEnabled ? 'uiMusicOn' : 'uiMusicOff'); 97 | }; 98 | 99 | Bots.Menu.prototype.createPrefab = function (prefabName, properties) { 100 | if (this.prefabClasses.hasOwnProperty(properties.type)) { 101 | const position = new Phaser.Point(properties.position.x, properties.position.y); 102 | const prefab = new this.prefabClasses[properties.type](this, prefabName, position, properties.properties); 103 | 104 | this.prefabs[prefabName] = prefab; 105 | } 106 | }; 107 | 108 | Bots.Menu.prototype.update = function () { 109 | this.game.physics.arcade.collide(this.groups.robots); 110 | } 111 | 112 | Bots.Menu.prototype.onButtonPressed = function (button) { 113 | if (button.name === 'leftButton') { 114 | this.chooser.showPrevious(); 115 | } 116 | 117 | if (button.name === 'rightButton') { 118 | this.chooser.showNext(); 119 | } 120 | 121 | if (button.name === 'startButton') { 122 | const content = this.game.cache.getText('level'); 123 | const payload = JSON.parse(content); 124 | Bots.background = this.backgroundChooser.selectedTile.properties.key; 125 | payload.prefabs.robotSpawner.properties.spawnKey = this.chooser.getChosenRobot().properties.secondKey; 126 | payload.prefabs.background.properties.key = this.backgroundChooser.selectedTile.properties.key; 127 | 128 | Bots.humanRobotKey = this.chooser.getChosenRobot().properties.secondKey; 129 | this.chooser.chooseRobot(500); 130 | this.fadeOutUI('level', payload); 131 | } 132 | 133 | if (button.name === 'informationButton') { 134 | const content = this.game.cache.getText('credits'); 135 | const payload = JSON.parse(content); 136 | Bots.background = this.backgroundChooser.selectedTile.properties.key; 137 | payload.prefabs.background.properties.key = this.backgroundChooser.selectedTile.properties.key; 138 | 139 | Bots.humanRobotKey = this.chooser.getChosenRobot().properties.secondKey; 140 | this.fadeOutUI('credits', payload); 141 | } 142 | 143 | if (button.name === 'soundButton') { 144 | Bots.soundsEnabled = !Bots.soundsEnabled; 145 | button.loadTexture(Bots.soundsEnabled ? 'uiMusicOn' : 'uiMusicOff'); 146 | } 147 | } 148 | 149 | Bots.Menu.prototype.fadeOutUI = function (nextState, payload) { 150 | this.game.add.tween(this.groups.logo).to({ y: -200 }, 500, Phaser.Easing.Elastic.In, true); 151 | this.game.add.tween(this.groups.hud).to({ alpha: 0 }, 500, Phaser.Easing.Quintic.Out, true) 152 | .onComplete.add(function () { 153 | this.game.state.start('loading', true, false, payload, nextState); 154 | }, this); 155 | } -------------------------------------------------------------------------------- /js/utilities/arrayUtilities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 19/07/17. 3 | */ 4 | 5 | const sample = (array, exception) => { 6 | const temp = Object.assign([], array).filter(item => item !== exception); 7 | return temp[Math.floor(Math.random() * temp.length)]; 8 | } -------------------------------------------------------------------------------- /js/utilities/groupUtilities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 19/07/17. 3 | */ 4 | 5 | const getMemberByName = (group, name) => { 6 | if (!!group && !!name) { 7 | return group.filter(item => item.name === name).list[0]; 8 | } 9 | } 10 | 11 | const getHumanRobot = (robotsGroup) => { 12 | return robotsGroup.filter(item => item.human).list[0]; 13 | } 14 | 15 | const killFromGroup = (item, group) => { 16 | if (item) { 17 | item.kill(); 18 | item.destroy(); 19 | group.remove(item); 20 | } 21 | } -------------------------------------------------------------------------------- /js/utilities/mathUtilities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 19/07/17. 3 | */ 4 | 5 | const calculateDamage = (attack, defense) => { 6 | const baseDamage = Math.pow(attack, 3) / 32 + 32; 7 | const damageReduction = Math.pow(defense - 280.4, 2) / 110 + 16; 8 | const baseDamage2 = baseDamage * damageReduction / 730; 9 | 10 | return baseDamage2 * (730 - (defense * 51 - Math.pow(defense, 2) / 11) / 10) / 7300; 11 | } 12 | 13 | const calculateDamage2 = (attack, defense) => { 14 | return attack * attack / (attack + defense); 15 | } 16 | 17 | const mod = (number, mod) => ((number % mod) + mod) % mod; 18 | 19 | const randomBoolean = () => randomInteger(10) < 5; -------------------------------------------------------------------------------- /js/utilities/nameUtilities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by s.neidig on 22/07/17. 3 | */ 4 | 5 | const parseRule = (rule) => { 6 | return rule.substr(1).split('$'); 7 | } 8 | 9 | const structure = () => { 10 | return { 11 | vowel: ['a', 'e', 'i', 'o', 'u', 'y'], 12 | start: ['Aer', 'Al', 'Am', 'An', 'Ar', 'Arm', 'Arth', 'B', 'Bal', 'Bar', 'Be', 'Bel', 'Ber', 'Bok', 'Bor', 'Bran', 'Breg', 'Bren', 'Brod', 'Cam', 'Chal', 'Cham', 'Ch', 'Cuth', 'Dag', 'Daim', 'Dair', 'Del', 'Dr', 'Dur', 'Duv', 'Ear', 'Elen', 'Er', 'Erel', 'Erem', 'Fal', 'Ful', 'Gal', 'G', 'Get', 'Gil', 'Gor', 'Grin', 'Gun', 'H', 'Hal', 'Han', 'Har', 'Hath', 'Hett', 'Hur', 'Iss', 'Khel', 'K', 'Kor', 'Lel', 'Lor', 'M', 'Mal', 'Man', 'Mard', 'N', 'Ol', 'Radh', 'Rag', 'Relg', 'Rh', 'Run', 'Sam', 'Tarr', 'T', 'Tor', 'Tul', 'Tur', 'Ul', 'Ulf', 'Unr', 'Ur', 'Urth', 'Yar', 'Z', 'Zan', 'Zer'], 13 | middle: ['de', 'do', 'dra', 'du', 'duna', 'ga', 'go', 'hara', 'kaltho', 'la', 'latha', 'le', 'ma', 'nari', 'ra', 're', 'rego', 'ro', 'rodda', 'romi', 'rui', 'sa', 'to', 'ya', 'zila'], 14 | end: ['bar', 'bers', 'blek', 'chak', 'chik', 'dan', 'dar', 'das', 'dig', 'dil', 'din', 'dir', 'dor', 'dur', 'fang', 'fast', 'gar', 'gas', 'gen', 'gorn', 'grim', 'gund', 'had', 'hek', 'hell', 'hir', 'hor', 'kan', 'kath', 'khad', 'kor', 'lach', 'lar', 'ldil', 'ldir', 'leg', 'len', 'lin', 'mas', 'mnir', 'ndil', 'ndur', 'neg', 'nik', 'ntir', 'rab', 'rach', 'rain', 'rak', 'ran', 'rand', 'rath', 'rek', 'rig', 'rim', 'rin', 'rion', 'sin', 'sta', 'stir', 'sus', 'tar', 'thad', 'thel', 'tir', 'von', 'vor', 'yon', 'zor'], 15 | rule: '$start$vowel$35$middle$10$middle$end' 16 | }; 17 | } 18 | 19 | const randomInteger = (max) => { 20 | return Math.floor(Math.random() * max); 21 | } 22 | 23 | const isNameValid = (name) 24 | 25 | const shortenName = (name, length = 10) => { 26 | if (name.length > length) { 27 | return name.substring(0, length) + '...'; 28 | } else { 29 | return name; 30 | } 31 | }; 32 | 33 | const getRandomName = () => { 34 | const rule = parseRule(structure().rule); 35 | const ruleCount = rule.length; 36 | let name = ''; 37 | 38 | for (let i = 0; i < ruleCount; i++) { 39 | const percent = parseInt(rule[i]); 40 | if (isNaN(percent)) { 41 | if (rule[i] === '_') { 42 | name += ' '; 43 | } else { 44 | const segCount = structure()[rule[i]].length; 45 | name += structure()[rule[i]][randomInteger(segCount)]; 46 | } 47 | } else if (randomInteger(100) > percent && i < (ruleCount - 1)) { 48 | i += 1; 49 | } 50 | } 51 | 52 | return name.replace(/^\s+|\s+$/g, ""); 53 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dasheck-hackathon-phaser", 3 | "version": "1.0.0", 4 | "description": "This is my entry for the 2017 phaser hackathon", 5 | "main": " ", 6 | "dependencies": { 7 | "textversionjs": "^1.0.2" 8 | }, 9 | "devDependencies": { 10 | "babel-cli": "^6.24.1", 11 | "babel-preset-es2015": "^6.24.1", 12 | "get-folder-size": "^1.0.0", 13 | "gulp": "^3.9.1", 14 | "gulp-babel": "^6.1.2", 15 | "gulp-imagemin": "^3.3.0", 16 | "gulp-minify": "^1.0.0", 17 | "opn": "^5.1.0" 18 | }, 19 | "scripts": { 20 | "test": "echo \"Error: no test specified\" && exit 1" 21 | }, 22 | "keywords": [ 23 | "phaser", 24 | "hackathon", 25 | "nodejs" 26 | ], 27 | "author": "Stefan Neidig (http://appcom-interactive.de)", 28 | "license": "MIT" 29 | } 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Robots 2 | 3 | This is my contribution to the [2017 Zenva Phaser Hackathon](https://gamedevacademy.org/first-zenva-phaser-hackathon/?a=13). 4 | The competion is held from July 6th to July 30th 2017 with the goal to create 5 | a game only by using phaser. However there were some rules each contestant 6 | had to respect. The most notably onews were that only predefined assets 7 | could be used and that the complete game must not exceed 500 KB of disk space. 8 | 9 | ## Game 10 | 11 | ### Installation 12 | 13 | To create the games dist folder you have to setup the build 14 | pipeline. This is as easy as running `npm install` on the projects 15 | directory. This will install required dependencies (i.e. gulp). Then 16 | run `gulp transpile minify` to create the `dist` directory, which will 17 | contain the games sources. You can verify that the required space does not 18 | exceed 500 KB by running `gulp calculateSize`. Then open the `index.html` 19 | and the game should start. 20 | 21 | ### Objective 22 | 23 | Robots is a game where you control a robot and try to survive as long as 24 | you can. Other robots will spawn and attack you. But fear not! Dodge 25 | their bullets and fire your own to destroy them and gain loot and other 26 | goodies. These will help to upgrade your robot. 27 | 28 | ### Features 29 | 30 | #### Comprehensive battle system 31 | 32 | Your robot has 4 main states, namely attack, defense, speed and health. 33 | Attack and defense are used for damage calculation once your robot is hit. 34 | The formula is quite complex and tweaked, such that you last at least a few 35 | hits before you die. Speed controls not only your translation speed but 36 | also how fast you can rotate. And health is the most important stat you 37 | need to focus on. Once it drops below zero you are dead. Don't worry! 38 | Your health is replenished after killing an enemy robot. 39 | 40 | ### Loots 41 | 42 | There are several possibilities to gain loot within the game. The most 43 | obvious one is to open chests by destroying them. Once they are opened 44 | you get a persistent boost of one of your main stats. So do not focus 45 | that much on killing robots and get some chests too! 46 | 47 | ### Bosses 48 | 49 | Every once in a while there spawns a boss robot. There will be a special 50 | notification for this event. The boss will be displayed as a red dot on 51 | the minimap. But be careful the boss has way better stats than any other 52 | robot including yourself (probably). Also the boss has special attacks 53 | like the stun jump and a periodic meteor hail. Each robot will explode 54 | instantaneously upon boss collision. Boss fights are only for the best 55 | of the best. But believe me it is worth it. According to the legend one 56 | will receive its power when a boss dies! 57 | 58 | ### Environment 59 | 60 | The world of Bots is dangerous by itself. But pay attention to your 61 | surroundings. There are random events, which you should avoid. This can 62 | randomly placed oil on the road, which will slow you down or even 63 | meteors dropping from the sky, which will likely kill you instantly. 64 | Sometimes the earth shatters for no reason, stunning each robot nearby 65 | for a certain time. 66 | 67 | ### HUD 68 | 69 | Keep everything in sight by using your hud. Simply press shift (or tap 70 | the button when you are on mobile) and show your HUD. This contains 71 | information about yourself, the current robots ranking based on their level 72 | and a basic help as well as a "how to". Never get lost with your HUD! 73 | 74 | ## Screenshots 75 | 76 | 77 | 78 | 79 | 80 | 81 | ## Road map 82 | 83 | ### Crucial 84 | 85 | * Check licenses 86 | 87 | ### Important 88 | 89 | ### Nice to have 90 | 91 | ### Not for hackathon 92 | 93 | * Add more robot ai types (timid, circeling, random) 94 | * Add consumables - invisible, mirror, stun enemies, 95 | * Add randomly placed obstacles (destroyable and not destroyable) 96 | * Add mines as secondary weapons and add camera shake for explosion 97 | * Scrolling message window (like a ticker) 98 | * Add more weapon graphics 99 | * Increase size of robot for the minimap based on kill counter 100 | * Add temp stat boosts for special actions 101 | * Add task systems, which give medals and stat boosts 102 | * Add stats for controlling weapon system 103 | * Add randomly placed structures (like a maze/labyrinth) 104 | * Add pause mode in game 105 | 106 | ### Done 107 | 108 | * ~~Minify assets~~ 109 | * ~~Tweaking game parameters~~ 110 | * ~~Add help for minimap!~~ 111 | * ~~Show hud in the first game or a hint so that the player knows how to show it~~ 112 | * ~~Do not spawn boss continuously and place warning when he appears (with warning symbol, flashing screen and shaking)~~ 113 | * ~~Revamp damage calculation~~ 114 | * ~~Atk, Def, Spd, Health fixed values based on chosen robot (yellow -> good def)~~ 115 | * ~~Add sounds~~ 116 | * ~~Spawn protect~~ 117 | * ~~Robot should emit smoke when on low health (only bosses)~~ 118 | * ~~Add randomly driving robots for menu (just to make it more dynamic)~~ 119 | * ~~Add oil on street again~~ 120 | * ~~Draw healthbar in different colors based on HP~~ 121 | * ~~Add menu, settings, credits, options~~ 122 | * ~~Animate gaining loots and stat boosts~~ 123 | * ~~Drop loot after killing another robot~~ 124 | * ~~Statistics per TAB Button (With points, ranks, history, etc)~~ 125 | * ~~Add start button in menu~~ 126 | * ~~Add bosses (Can jump and stun robots within distance, can drop missiles, yield medals uopn defeat)~~ 127 | * ~~Add more crate graphics~~ 128 | * ~~Add robot shadows~~ 129 | * ~~Kill notification like in CS:GO~~ 130 | * ~~Funny names for bots~~ 131 | * ~~Draw human robot in another color for the minimap~~ 132 | * ~~Respawn player after death~~ 133 | * ~~Add support for mobile~~ 134 | * ~~Add explosion tweens and scorch marks after killing a robot~~ 135 | * ~~Add tracks to robot for the last 100 meters~~ 136 | 137 | ## Considerations 138 | 139 | This game was developed as part of a hackathon. Keep that in mind. The code 140 | and its structure does not need to apply to the highest quality standards 141 | and this game might contain bugs. If you have feedback to both see the about me 142 | section to find out how you can get in contact with me to actually tell me 143 | your feedback. 144 | 145 | While the game runs on 60 fps on my machine it does not need to do so on 146 | yours (especially when your device is a mobile device). There are many 147 | objects, which need to be rendered and calculated. There can be many 148 | optimizations done, but again, this was a hackathon. So bear with me! 149 | 150 | ## Used assets 151 | 152 | ### Images 153 | 154 | * [Robot pack](http://kenney.nl/assets/robot-pack) 155 | * [Tanks](http://kenney.nl/assets/tanks) 156 | * [Smoke Particle Assets](https://opengameart.org/content/smoke-particle-assets) 157 | * [Topdown Tanks](https://kenney.nl/assets/topdown-tanks) 158 | * [Game icons](https://opengameart.org/content/game-icons) 159 | * [Cloud set](https://opengameart.org/content/cloud-set) 160 | * [Onscreen - Controls](http://kenney.nl/assets/onscreen-controls) 161 | * [Sokoban (100+ Tiles)](https://opengameart.org/content/sokoban-100-tiles) 162 | * [Space Shooter Redux](https://opengameart.org/content/space-shooter-redux) 163 | * [FREE UI ASSET PACK 1](https://opengameart.org/content/free-ui-asset-pack-1) 164 | * [Stone blocks](https://opengameart.org/content/stoneblocks) 165 | * [50 free textures 5 - with normalmaps](https://opengameart.org/content/50-free-textures-5-with-normalmaps) 166 | * [Explosion](https://opengameart.org/content/explosion) 167 | * [Powers Icons](https://opengameart.org/content/powers-icons) 168 | 169 | ### Sounds 170 | 171 | * [droplet4](http://freesound.org/people/willy_ineedthatapp_com/sounds/167329/) by willy_ineedthatapp 172 | * [whack01](http://freesound.org/people/Qat/sounds/114682/) by Qat 173 | * [LightBulletPing](http://freesound.org/people/wilhellboy/sounds/351369/) by wilhellby 174 | * [PVC Rocket Cannon_2](http://freesound.org/people/bowlingballout/sounds/151714/) by bowlingballout 175 | * [MoCa abstract kick](http://freesound.org/people/moca/sounds/49030/) by moca 176 | 177 | ## Assets removed due to insufficient licenses 178 | 179 | * [Hand Painted Texture - Sandstone](https://opengameart.org/content/hand-painted-texture-sandstone) 180 | * [Hand Painted Texture - Floor Tile](https://opengameart.org/content/hand-painted-texture-floor-tile) 181 | * [95 Game icons](https://opengameart.org/content/95-game-icons) 182 | * [Bomb Explosion Animation](https://opengameart.org/content/bomb-explosion-animation) 183 | * [LCP Terrain Pack](https://opengameart.org/content/lpc-terrain-repack) 184 | * [2d Lost Garden Zelda style tiles resized to 32x32 with additions](https://opengameart.org/content/2d-lost-garden-zelda-style-tiles-resized-to-32x32-with-additions) 185 | 186 | ## About me 187 | 188 | I am from Germany and involved with programming for almost 15 years. I 189 | actually started with developing games back in the days with C++ and OpenGL, 190 | before switching to Irrlicht 3D, Unity 3D and finally PhaserJS. So far 191 | PhaserJS gave me the best experience, since it is easy to understand 192 | and extremly powerful letting me completely focus on the actual game. 193 | Projects with the previously mentioned engines were never completed, since 194 | I got stuck in patching the engine or building missing parts 195 | (i.e. gamestates, object pooling, ...). 196 | 197 | This is the first bigger game I finished. You can play it on [itch.io](https://dasheck.itch.io/bots). 198 | Any feedback is appreciated. You can contact my via twitter, email or provide the feedback directly via itch.io. 199 | Thanks for reading, playing and feedbacking! 200 | 201 | ## License 202 | 203 | This game is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT) 204 | -------------------------------------------------------------------------------- /watch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | fswatch -o -r ./assets ./js index.html | xargs -n1 bash ./deliver.sh --------------------------------------------------------------------------------