├── lib-ts
├── index.d.ts
├── interfaces
│ ├── UiGraph
│ │ ├── NodeParams.d.ts
│ │ ├── Event.d.ts
│ │ ├── Metadata.d.ts
│ │ ├── SpriteNodeParams.d.ts
│ │ ├── Graph.d.ts
│ │ ├── TextNode.d.ts
│ │ ├── SpriteNode.d.ts
│ │ ├── TextNodeParams.d.ts
│ │ ├── Node.d.ts
│ │ └── index.d.ts
│ ├── PixiTypePolyfill
│ │ └── LoaderAddParam.d.ts
│ ├── UpdateObject.d.ts
│ ├── master
│ │ ├── UnitMaster.d.ts
│ │ ├── CastleMaster.d.ts
│ │ ├── AttackableMaster.d.ts
│ │ ├── StageMaster.d.ts
│ │ └── UnitAnimationMaster.d.ts
│ ├── api
│ │ └── UserBattle.d.ts
│ ├── Transition.d.ts
│ ├── BattleParameter.d.ts
│ └── BattleLogicDelegate.d.ts
├── Config.d.ts
├── enum
│ ├── AttackableState.d.ts
│ └── BattleSceneState.d.ts
├── entity
│ ├── UnitEntity.d.ts
│ ├── CastleEntity.d.ts
│ └── AttackableEntity.d.ts
├── modules
│ ├── UiNodeFactory
│ │ ├── TextFactory.d.ts
│ │ ├── battle
│ │ │ └── UnitButtonFactory.d.ts
│ │ ├── SpriteFactory.d.ts
│ │ └── UiNodeFactory.d.ts
│ ├── UiGraph.d.ts
│ ├── BattleLogicConfig.d.ts
│ ├── Sound.d.ts
│ └── BattleLogic.d.ts
├── scenes
│ ├── TitleScene.d.ts
│ ├── transition
│ │ ├── Immediate.d.ts
│ │ └── Fade.d.ts
│ ├── OrderScene.d.ts
│ ├── Scene.d.ts
│ └── BattleScene.d.ts
├── display
│ └── battle
│ │ ├── single_shot
│ │ ├── Dead.d.ts
│ │ ├── AttackSmoke.d.ts
│ │ ├── CollapseExplodeEffect.d.ts
│ │ └── HealthGauge.d.ts
│ │ ├── BattleResult.d.ts
│ │ ├── UnitButton.d.ts
│ │ ├── Castle.d.ts
│ │ ├── Attackable.d.ts
│ │ ├── Unit.d.ts
│ │ └── Field.d.ts
├── managers
│ ├── GameManager.d.ts
│ ├── IndexedDBManager.d.ts
│ └── SoundManager.d.ts
└── Resource.d.ts
├── .gitignore
├── www
├── assets
│ ├── units
│ │ ├── 1.png
│ │ ├── 10.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ ├── 9.png
│ │ ├── 2.json
│ │ ├── 3.json
│ │ ├── 1.json
│ │ ├── 5.json
│ │ └── 4.json
│ ├── audio
│ │ ├── se_bomb.mp3
│ │ ├── se_lose.mp3
│ │ ├── se_win.mp3
│ │ ├── bgm_battle.mp3
│ │ ├── bgm_title.mp3
│ │ ├── se_attack_1.mp3
│ │ ├── se_attack_2.mp3
│ │ └── se_unit_spawn.mp3
│ ├── battle
│ │ ├── bg_1_1.png
│ │ ├── bg_1_2.png
│ │ ├── bg_1_3.png
│ │ ├── bg_1_4.png
│ │ ├── bg_1_5.png
│ │ ├── bg_1_6.png
│ │ ├── bg_1_7.png
│ │ ├── bg_1_8.png
│ │ ├── bg_1_9.png
│ │ ├── bg_2_1.png
│ │ ├── bg_2_2.png
│ │ ├── bg_2_3.png
│ │ ├── bg_2_4.png
│ │ ├── bg_2_5.png
│ │ ├── bg_2_6.png
│ │ ├── bg_3_1.png
│ │ ├── bg_3_2.png
│ │ ├── bg_3_3.png
│ │ ├── bg_1_10.png
│ │ ├── castle
│ │ │ ├── 1.png
│ │ │ ├── 2.png
│ │ │ ├── 3.png
│ │ │ ├── 4.png
│ │ │ ├── 2.json
│ │ │ ├── 3.json
│ │ │ ├── 4.json
│ │ │ └── 1.json
│ │ └── effects
│ │ │ ├── dead
│ │ │ ├── dead_bucket.png
│ │ │ └── dead_spirit.png
│ │ │ ├── attack_smoke
│ │ │ ├── attack_smoke.png
│ │ │ └── attack_smoke.json
│ │ │ └── collapse_explode
│ │ │ ├── collapse_explode.png
│ │ │ └── collapse_explode.json
│ ├── ui
│ │ ├── arrow_left.png
│ │ ├── battle_win.png
│ │ ├── arrow_right.png
│ │ ├── battle_lose.png
│ │ ├── order_start_off.png
│ │ ├── order_start_on.png
│ │ ├── title_button_start_off.png
│ │ ├── title_button_start_on.png
│ │ └── units_panel
│ │ │ └── button
│ │ │ ├── unit_1.png
│ │ │ ├── unit_2.png
│ │ │ ├── unit_3.png
│ │ │ ├── unit_4.png
│ │ │ ├── unit_5.png
│ │ │ └── unit_empty.png
│ ├── font
│ │ └── MisakiGothic.ttf
│ ├── api_mock
│ │ └── user_battle.json
│ ├── master
│ │ ├── stage_master_1.json
│ │ ├── stage_master_2.json
│ │ ├── stage_master_3.json
│ │ ├── castle_master.json
│ │ └── unit_master.json
│ └── ui_graph
│ │ ├── battle_scene.json
│ │ └── title_scene.json
├── base.css
└── index.html
├── docs
└── assets
│ └── images
│ ├── icons.png
│ ├── icons@2x.png
│ ├── widgets.png
│ └── widgets@2x.png
├── raw_assets
├── base
│ ├── base_1_1.png
│ ├── base_1_2.png
│ ├── base_2_1.png
│ ├── base_3_1.png
│ └── base_4_1.png
├── effects
│ ├── effect_1_1.png
│ ├── effect_1_2.png
│ ├── effect_1_3.png
│ ├── effect_1_4.png
│ ├── effect_1_5.png
│ ├── effect_2_1.png
│ ├── effect_2_2.png
│ └── effect_2_3.png
└── units
│ ├── 1
│ ├── unit_1_wait_1.png
│ ├── unit_1_wait_2.png
│ ├── unit_1_walk_1.png
│ ├── unit_1_walk_2.png
│ ├── unit_1_walk_3.png
│ ├── unit_1_walk_4.png
│ ├── unit_1_walk_5.png
│ ├── unit_1_walk_6.png
│ ├── unit_1_attack_1.png
│ ├── unit_1_attack_2.png
│ ├── unit_1_attack_3.png
│ ├── unit_1_attack_4.png
│ ├── unit_1_attack_5.png
│ ├── unit_1_attack_6.png
│ ├── unit_1_attack_7.png
│ ├── unit_1_attack_8.png
│ └── unit_1_damage_1.png
│ ├── 2
│ ├── unit_2_wait_1.png
│ ├── unit_2_wait_2.png
│ ├── unit_2_walk_1.png
│ ├── unit_2_walk_2.png
│ ├── unit_2_walk_3.png
│ ├── unit_2_walk_4.png
│ ├── unit_2_walk_5.png
│ ├── unit_2_walk_6.png
│ ├── unit_2_attack_1.png
│ ├── unit_2_attack_2.png
│ ├── unit_2_attack_3.png
│ ├── unit_2_attack_4.png
│ ├── unit_2_attack_5.png
│ ├── unit_2_attack_6.png
│ └── unit_2_damage_1.png
│ ├── 3
│ ├── unit_3_wait_1.png
│ ├── unit_3_wait_2.png
│ ├── unit_3_walk_1.png
│ ├── unit_3_walk_2.png
│ ├── unit_3_walk_3.png
│ ├── unit_3_walk_4.png
│ ├── unit_3_walk_5.png
│ ├── unit_3_walk_6.png
│ ├── unit_3_attack_1.png
│ ├── unit_3_attack_2.png
│ ├── unit_3_attack_3.png
│ ├── unit_3_attack_4.png
│ ├── unit_3_attack_5.png
│ ├── unit_3_attack_6.png
│ ├── unit_3_attack_7.png
│ └── unit_3_damage_1.png
│ ├── 4
│ ├── unit_4_wait_1.png
│ ├── unit_4_wait_2.png
│ ├── unit_4_walk_1.png
│ ├── unit_4_walk_2.png
│ ├── unit_4_walk_3.png
│ ├── unit_4_walk_4.png
│ ├── unit_4_walk_5.png
│ ├── unit_4_walk_6.png
│ ├── unit_4_attack_1.png
│ ├── unit_4_attack_2.png
│ ├── unit_4_attack_3.png
│ ├── unit_4_attack_4.png
│ ├── unit_4_attack_5.png
│ ├── unit_4_attack_6.png
│ ├── unit_4_attack_7.png
│ ├── unit_4_attack_8.png
│ ├── unit_4_attack_9.png
│ ├── unit_4_damage_1.png
│ ├── unit_4_attack_10.png
│ └── unit_4_attack_11.png
│ └── 5
│ ├── unit_5_wait_1.png
│ ├── unit_5_wait_2.png
│ ├── unit_5_walk_1.png
│ ├── unit_5_walk_2.png
│ ├── unit_5_walk_3.png
│ ├── unit_5_walk_4.png
│ ├── unit_5_walk_5.png
│ ├── unit_5_walk_6.png
│ ├── unit_5_attack_1.png
│ ├── unit_5_attack_2.png
│ ├── unit_5_attack_3.png
│ ├── unit_5_attack_4.png
│ ├── unit_5_attack_5.png
│ ├── unit_5_attack_6.png
│ ├── unit_5_attack_7.png
│ ├── unit_5_attack_8.png
│ ├── unit_5_attack_9.png
│ └── unit_5_damage_1.png
├── src
├── interfaces
│ ├── UiGraph
│ │ ├── NodeParams.ts
│ │ ├── Event.ts
│ │ ├── Metadata.ts
│ │ ├── Graph.ts
│ │ ├── SpriteNodeParams.ts
│ │ ├── TextNode.ts
│ │ ├── SpriteNode.ts
│ │ ├── TextNodeParams.ts
│ │ ├── Node.ts
│ │ └── index.ts
│ ├── PixiTypePolyfill
│ │ └── LoaderAddParam.ts
│ ├── UpdateObject.ts
│ ├── master
│ │ ├── UnitMaster.ts
│ │ ├── CastleMaster.ts
│ │ ├── StageMaster.ts
│ │ ├── AttackableMaster.ts
│ │ └── UnitAnimationMaster.ts
│ ├── api
│ │ └── UserBattle.ts
│ ├── BattleParameter.ts
│ ├── Transition.ts
│ └── BattleLogicDelegate.ts
├── enum
│ ├── AttackableState.ts
│ └── BattleSceneState.ts
├── Config.ts
├── entity
│ ├── UnitEntity.ts
│ ├── CastleEntity.ts
│ └── AttackableEntity.ts
├── modules
│ ├── UiNodeFactory
│ │ ├── battle
│ │ │ └── UnitButtonFactory.ts
│ │ ├── SpriteFactory.ts
│ │ ├── TextFactory.ts
│ │ └── UiNodeFactory.ts
│ ├── UiGraph.ts
│ ├── BattleLogicConfig.ts
│ └── Sound.ts
├── scenes
│ ├── transition
│ │ ├── Immediate.ts
│ │ └── Fade.ts
│ └── TitleScene.ts
├── index.ts
├── display
│ └── battle
│ │ ├── BattleResult.ts
│ │ ├── single_shot
│ │ ├── AttackSmoke.ts
│ │ ├── CollapseExplodeEffect.ts
│ │ ├── Dead.ts
│ │ └── HealthGauge.ts
│ │ ├── UnitButton.ts
│ │ ├── Attackable.ts
│ │ ├── Castle.ts
│ │ └── Unit.ts
└── Resource.ts
├── tslint.json
├── tsconfig.json
├── karma.conf.js
├── package.json
├── LICENSE
└── webpack.config.js
/lib-ts/index.d.ts:
--------------------------------------------------------------------------------
1 | import 'Config';
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS
2 | .DS_Store
3 |
4 | # node
5 | node_modules
6 |
7 |
--------------------------------------------------------------------------------
/www/assets/units/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/1.png
--------------------------------------------------------------------------------
/www/assets/units/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/10.png
--------------------------------------------------------------------------------
/www/assets/units/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/2.png
--------------------------------------------------------------------------------
/www/assets/units/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/3.png
--------------------------------------------------------------------------------
/www/assets/units/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/4.png
--------------------------------------------------------------------------------
/www/assets/units/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/5.png
--------------------------------------------------------------------------------
/www/assets/units/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/6.png
--------------------------------------------------------------------------------
/www/assets/units/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/7.png
--------------------------------------------------------------------------------
/www/assets/units/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/8.png
--------------------------------------------------------------------------------
/www/assets/units/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/units/9.png
--------------------------------------------------------------------------------
/docs/assets/images/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/docs/assets/images/icons.png
--------------------------------------------------------------------------------
/raw_assets/base/base_1_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/base/base_1_1.png
--------------------------------------------------------------------------------
/raw_assets/base/base_1_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/base/base_1_2.png
--------------------------------------------------------------------------------
/raw_assets/base/base_2_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/base/base_2_1.png
--------------------------------------------------------------------------------
/raw_assets/base/base_3_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/base/base_3_1.png
--------------------------------------------------------------------------------
/raw_assets/base/base_4_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/base/base_4_1.png
--------------------------------------------------------------------------------
/www/assets/audio/se_bomb.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/audio/se_bomb.mp3
--------------------------------------------------------------------------------
/www/assets/audio/se_lose.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/audio/se_lose.mp3
--------------------------------------------------------------------------------
/www/assets/audio/se_win.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/audio/se_win.mp3
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_1.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_2.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_3.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_4.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_5.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_6.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_7.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_8.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_9.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_2_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_2_1.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_2_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_2_2.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_2_3.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_2_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_2_4.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_2_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_2_5.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_2_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_2_6.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_3_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_3_1.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_3_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_3_2.png
--------------------------------------------------------------------------------
/www/assets/battle/bg_3_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_3_3.png
--------------------------------------------------------------------------------
/www/assets/ui/arrow_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/arrow_left.png
--------------------------------------------------------------------------------
/www/assets/ui/battle_win.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/battle_win.png
--------------------------------------------------------------------------------
/docs/assets/images/icons@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/docs/assets/images/icons@2x.png
--------------------------------------------------------------------------------
/docs/assets/images/widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/docs/assets/images/widgets.png
--------------------------------------------------------------------------------
/www/assets/audio/bgm_battle.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/audio/bgm_battle.mp3
--------------------------------------------------------------------------------
/www/assets/audio/bgm_title.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/audio/bgm_title.mp3
--------------------------------------------------------------------------------
/www/assets/battle/bg_1_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/bg_1_10.png
--------------------------------------------------------------------------------
/www/assets/battle/castle/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/castle/1.png
--------------------------------------------------------------------------------
/www/assets/battle/castle/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/castle/2.png
--------------------------------------------------------------------------------
/www/assets/battle/castle/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/castle/3.png
--------------------------------------------------------------------------------
/www/assets/battle/castle/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/castle/4.png
--------------------------------------------------------------------------------
/www/assets/ui/arrow_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/arrow_right.png
--------------------------------------------------------------------------------
/www/assets/ui/battle_lose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/battle_lose.png
--------------------------------------------------------------------------------
/docs/assets/images/widgets@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/docs/assets/images/widgets@2x.png
--------------------------------------------------------------------------------
/raw_assets/effects/effect_1_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/effects/effect_1_1.png
--------------------------------------------------------------------------------
/raw_assets/effects/effect_1_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/effects/effect_1_2.png
--------------------------------------------------------------------------------
/raw_assets/effects/effect_1_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/effects/effect_1_3.png
--------------------------------------------------------------------------------
/raw_assets/effects/effect_1_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/effects/effect_1_4.png
--------------------------------------------------------------------------------
/raw_assets/effects/effect_1_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/effects/effect_1_5.png
--------------------------------------------------------------------------------
/raw_assets/effects/effect_2_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/effects/effect_2_1.png
--------------------------------------------------------------------------------
/raw_assets/effects/effect_2_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/effects/effect_2_2.png
--------------------------------------------------------------------------------
/raw_assets/effects/effect_2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/effects/effect_2_3.png
--------------------------------------------------------------------------------
/www/assets/audio/se_attack_1.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/audio/se_attack_1.mp3
--------------------------------------------------------------------------------
/www/assets/audio/se_attack_2.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/audio/se_attack_2.mp3
--------------------------------------------------------------------------------
/www/assets/font/MisakiGothic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/font/MisakiGothic.ttf
--------------------------------------------------------------------------------
/www/assets/ui/order_start_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/order_start_off.png
--------------------------------------------------------------------------------
/www/assets/ui/order_start_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/order_start_on.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_wait_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_wait_1.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_wait_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_wait_2.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_walk_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_walk_1.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_walk_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_walk_2.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_walk_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_walk_3.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_walk_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_walk_4.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_walk_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_walk_5.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_walk_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_walk_6.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_wait_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_wait_1.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_wait_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_wait_2.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_walk_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_walk_1.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_walk_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_walk_2.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_walk_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_walk_3.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_walk_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_walk_4.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_walk_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_walk_5.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_walk_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_walk_6.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_wait_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_wait_1.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_wait_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_wait_2.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_walk_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_walk_1.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_walk_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_walk_2.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_walk_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_walk_3.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_walk_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_walk_4.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_walk_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_walk_5.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_walk_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_walk_6.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_wait_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_wait_1.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_wait_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_wait_2.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_walk_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_walk_1.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_walk_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_walk_2.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_walk_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_walk_3.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_walk_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_walk_4.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_walk_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_walk_5.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_walk_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_walk_6.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_wait_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_wait_1.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_wait_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_wait_2.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_walk_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_walk_1.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_walk_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_walk_2.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_walk_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_walk_3.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_walk_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_walk_4.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_walk_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_walk_5.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_walk_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_walk_6.png
--------------------------------------------------------------------------------
/www/assets/audio/se_unit_spawn.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/audio/se_unit_spawn.mp3
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_attack_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_attack_1.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_attack_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_attack_2.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_attack_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_attack_3.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_attack_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_attack_4.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_attack_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_attack_5.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_attack_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_attack_6.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_attack_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_attack_7.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_attack_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_attack_8.png
--------------------------------------------------------------------------------
/raw_assets/units/1/unit_1_damage_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/1/unit_1_damage_1.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_attack_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_attack_1.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_attack_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_attack_2.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_attack_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_attack_3.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_attack_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_attack_4.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_attack_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_attack_5.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_attack_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_attack_6.png
--------------------------------------------------------------------------------
/raw_assets/units/2/unit_2_damage_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/2/unit_2_damage_1.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_attack_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_attack_1.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_attack_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_attack_2.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_attack_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_attack_3.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_attack_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_attack_4.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_attack_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_attack_5.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_attack_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_attack_6.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_attack_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_attack_7.png
--------------------------------------------------------------------------------
/raw_assets/units/3/unit_3_damage_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/3/unit_3_damage_1.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_1.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_2.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_3.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_4.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_5.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_6.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_7.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_8.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_9.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_damage_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_damage_1.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_1.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_2.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_3.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_4.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_5.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_6.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_7.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_8.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_attack_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_attack_9.png
--------------------------------------------------------------------------------
/raw_assets/units/5/unit_5_damage_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/5/unit_5_damage_1.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_10.png
--------------------------------------------------------------------------------
/raw_assets/units/4/unit_4_attack_11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/raw_assets/units/4/unit_4_attack_11.png
--------------------------------------------------------------------------------
/www/assets/ui/title_button_start_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/title_button_start_off.png
--------------------------------------------------------------------------------
/www/assets/ui/title_button_start_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/title_button_start_on.png
--------------------------------------------------------------------------------
/www/assets/ui/units_panel/button/unit_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/units_panel/button/unit_1.png
--------------------------------------------------------------------------------
/www/assets/ui/units_panel/button/unit_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/units_panel/button/unit_2.png
--------------------------------------------------------------------------------
/www/assets/ui/units_panel/button/unit_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/units_panel/button/unit_3.png
--------------------------------------------------------------------------------
/www/assets/ui/units_panel/button/unit_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/units_panel/button/unit_4.png
--------------------------------------------------------------------------------
/www/assets/ui/units_panel/button/unit_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/units_panel/button/unit_5.png
--------------------------------------------------------------------------------
/www/assets/battle/effects/dead/dead_bucket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/effects/dead/dead_bucket.png
--------------------------------------------------------------------------------
/www/assets/battle/effects/dead/dead_spirit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/effects/dead/dead_spirit.png
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/NodeParams.ts:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * UiGraph ノードパラメータ定義
4 | */
5 | export default interface NodeParams {
6 | [key: string]: any;
7 | }
8 |
--------------------------------------------------------------------------------
/www/assets/ui/units_panel/button/unit_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/ui/units_panel/button/unit_empty.png
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/NodeParams.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * UiGraph ノードパラメータ定義
3 | */
4 | export default interface NodeParams {
5 | [key: string]: any;
6 | }
7 |
--------------------------------------------------------------------------------
/www/assets/battle/effects/attack_smoke/attack_smoke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/effects/attack_smoke/attack_smoke.png
--------------------------------------------------------------------------------
/www/assets/battle/effects/collapse_explode/collapse_explode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dolow/pixi-tower-diffense/HEAD/www/assets/battle/effects/collapse_explode/collapse_explode.png
--------------------------------------------------------------------------------
/lib-ts/Config.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 設定オブジェクト
3 | */
4 | declare const Config: Readonly<{
5 | ResourceBaseUrl: string;
6 | MaxUnitSlotCount: number;
7 | }>;
8 | export default Config;
9 |
--------------------------------------------------------------------------------
/src/interfaces/PixiTypePolyfill/LoaderAddParam.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * PIXI.loader.add の引数オブジェクトの定義
3 | */
4 | export default interface LoaderAddParam {
5 | name: string;
6 | url: string;
7 | }
8 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/Event.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * UiGraph Event コンポーネント定義
3 | */
4 | export default interface Event {
5 | type: string;
6 | callback: string;
7 | arguments: any[];
8 | }
9 |
--------------------------------------------------------------------------------
/src/interfaces/UpdateObject.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 更新処理が行われるオブジェクトが提供すべきインターフェース
3 | */
4 | export default interface UpdateObject {
5 | isDestroyed(): boolean;
6 | update(_dt: number): void;
7 | }
8 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/PixiTypePolyfill/LoaderAddParam.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * PIXI.loader.add の引数オブジェクトの定義
3 | */
4 | export default interface LoaderAddParam {
5 | name: string;
6 | url: string;
7 | }
8 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/Event.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * UiGraph Event コンポーネント定義
3 | */
4 | export default interface Event {
5 | type: string;
6 | callback: string;
7 | arguments: any[];
8 | }
9 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/Metadata.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * UiGraph メタデータ定義
3 | */
4 | export default interface Metadata {
5 | screen: {
6 | width: number;
7 | height: number;
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UpdateObject.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 更新処理が行われるオブジェクトが提供すべきインターフェース
3 | */
4 | export default interface UpdateObject {
5 | isDestroyed(): boolean;
6 | update(_dt: number): void;
7 | }
8 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/Metadata.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * UiGraph メタデータ定義
3 | */
4 | export default interface Metadata {
5 | screen: {
6 | width: number;
7 | height: number;
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/src/interfaces/master/UnitMaster.ts:
--------------------------------------------------------------------------------
1 | import AttackableMaster from 'interfaces/master/AttackableMaster';
2 | /**
3 | * ユニットパラメータマスターのスキーマ定義
4 | */
5 | export default interface UnitMaster extends AttackableMaster {
6 | unitId: number;
7 | }
8 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/master/UnitMaster.d.ts:
--------------------------------------------------------------------------------
1 | import AttackableMaster from 'interfaces/master/AttackableMaster';
2 | /**
3 | * ユニットパラメータマスターのスキーマ定義
4 | */
5 | export default interface UnitMaster extends AttackableMaster {
6 | unitId: number;
7 | }
8 |
--------------------------------------------------------------------------------
/src/interfaces/master/CastleMaster.ts:
--------------------------------------------------------------------------------
1 | import AttackableMaster from 'interfaces/master/AttackableMaster';
2 | /**
3 | * 拠点パラメータマスターのスキーマ定義
4 | */
5 | export default interface CastleMaster extends AttackableMaster {
6 | castleId: number;
7 | }
8 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/master/CastleMaster.d.ts:
--------------------------------------------------------------------------------
1 | import AttackableMaster from 'interfaces/master/AttackableMaster';
2 | /**
3 | * 拠点パラメータマスターのスキーマ定義
4 | */
5 | export default interface CastleMaster extends AttackableMaster {
6 | castleId: number;
7 | }
8 |
--------------------------------------------------------------------------------
/src/enum/AttackableState.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * バトルエンティティのステート
3 | */
4 | const AttackableState = Object.freeze({
5 | IDLE: 1,
6 | ENGAGED: 2,
7 | KNOCK_BACK: 3,
8 | DEAD: 4,
9 | WAIT: 5
10 | });
11 |
12 | export default AttackableState;
13 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/SpriteNodeParams.d.ts:
--------------------------------------------------------------------------------
1 | import NodeParams from 'interfaces/UiGraph/NodeParams';
2 | /**
3 | * UiGraph スプライトノードパラメータ定義
4 | */
5 | export default interface SpriteNodeParams extends NodeParams {
6 | textureName?: string;
7 | url: string;
8 | }
9 |
--------------------------------------------------------------------------------
/src/enum/BattleSceneState.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * BattleScene のステート
3 | */
4 | const BattleSceneState = Object.freeze({
5 | LOADING_RESOURCES: 1,
6 | RESOURCE_LOADED: 2,
7 | READY: 3,
8 | INGAME: 4,
9 | FINISHED: 5
10 | });
11 |
12 | export default BattleSceneState;
13 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/Graph.d.ts:
--------------------------------------------------------------------------------
1 | import Node from 'interfaces/UiGraph/Node';
2 | import Metadata from 'interfaces/UiGraph/Metadata';
3 | /**
4 | * UiGparh ルートオブジェクト定義
5 | */
6 | export default interface Graph {
7 | nodes: Node[];
8 | metadata: Metadata;
9 | }
10 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/TextNode.d.ts:
--------------------------------------------------------------------------------
1 | import Node from 'interfaces/UiGraph/Node';
2 | import TextNodeParams from 'interfaces/UiGraph/TextNodeParams';
3 | /**
4 | * UiGraph テキストノード定義
5 | */
6 | export default interface TextNode extends Node {
7 | params: TextNodeParams;
8 | }
9 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/Graph.ts:
--------------------------------------------------------------------------------
1 | import Node from 'interfaces/UiGraph/Node';
2 | import Metadata from 'interfaces/UiGraph/Metadata';
3 |
4 | /**
5 | * UiGparh ルートオブジェクト定義
6 | */
7 | export default interface Graph {
8 | nodes: Node[];
9 | metadata: Metadata;
10 | }
11 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/SpriteNodeParams.ts:
--------------------------------------------------------------------------------
1 | import NodeParams from 'interfaces/UiGraph/NodeParams';
2 |
3 | /**
4 | * UiGraph スプライトノードパラメータ定義
5 | */
6 | export default interface SpriteNodeParams extends NodeParams {
7 | textureName?: string;
8 | url: string;
9 | }
10 |
--------------------------------------------------------------------------------
/lib-ts/enum/AttackableState.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * バトルエンティティのステート
3 | */
4 | declare const AttackableState: Readonly<{
5 | IDLE: number;
6 | ENGAGED: number;
7 | KNOCK_BACK: number;
8 | DEAD: number;
9 | WAIT: number;
10 | }>;
11 | export default AttackableState;
12 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/SpriteNode.d.ts:
--------------------------------------------------------------------------------
1 | import Node from 'interfaces/UiGraph/Node';
2 | import SpriteNodeParams from 'interfaces/UiGraph/SpriteNodeParams';
3 | /**
4 | * UiGraph スプライトノード定義
5 | */
6 | export default interface SpriteNode extends Node {
7 | params: SpriteNodeParams;
8 | }
9 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/TextNode.ts:
--------------------------------------------------------------------------------
1 | import Node from 'interfaces/UiGraph/Node';
2 | import TextNodeParams from 'interfaces/UiGraph/TextNodeParams';
3 |
4 | /**
5 | * UiGraph テキストノード定義
6 | */
7 | export default interface TextNode extends Node {
8 | params: TextNodeParams;
9 | }
10 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/SpriteNode.ts:
--------------------------------------------------------------------------------
1 | import Node from 'interfaces/UiGraph/Node';
2 | import SpriteNodeParams from 'interfaces/UiGraph/SpriteNodeParams';
3 |
4 | /**
5 | * UiGraph スプライトノード定義
6 | */
7 | export default interface SpriteNode extends Node {
8 | params: SpriteNodeParams;
9 | }
10 |
--------------------------------------------------------------------------------
/src/interfaces/master/StageMaster.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ステージ情報マスターのスキーマ定義
3 | */
4 | export default interface StageMaster {
5 | id: number;
6 | length: number;
7 | zLines: number;
8 | aiCastleId: number;
9 | waves: {
10 | [key: string]: {
11 | unitId: number;
12 | }[];
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/www/base.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'MisakiGothic';
3 | src: url('assets/font/MisakiGothic.ttf') format('truetype');
4 | }
5 |
6 | * {
7 | margin: 0px;
8 | }
9 |
10 | body {
11 | background-color: #222222;
12 | }
13 |
14 | canvas {
15 | display: block;
16 | margin: 0 auto;
17 | }
18 |
--------------------------------------------------------------------------------
/lib-ts/enum/BattleSceneState.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * BattleScene のステート
3 | */
4 | declare const BattleSceneState: Readonly<{
5 | LOADING_RESOURCES: number;
6 | RESOURCE_LOADED: number;
7 | READY: number;
8 | INGAME: number;
9 | FINISHED: number;
10 | }>;
11 | export default BattleSceneState;
12 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/master/AttackableMaster.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 拠点とユニットのパラメータマスターの基本 I/F
3 | */
4 | export default interface AttackableMaster {
5 | cost: number;
6 | maxHealth: number;
7 | power: number;
8 | speed: number;
9 | knockBackFrames: number;
10 | knockBackSpeed: number;
11 | }
12 |
--------------------------------------------------------------------------------
/src/Config.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 |
3 | /**
4 | * 設定オブジェクト
5 | */
6 | const Config = Object.freeze({
7 | // リソースのエントリーポイント
8 | ResourceBaseUrl: 'assets/',
9 | // ユニット枠最大数
10 | MaxUnitSlotCount: 5
11 | });
12 |
13 | PIXI.loader.baseUrl = Config.ResourceBaseUrl;
14 |
15 | export default Config;
16 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/TextNodeParams.ts:
--------------------------------------------------------------------------------
1 | import NodeParams from 'interfaces/UiGraph/NodeParams';
2 |
3 | /**
4 | * UiGraph テキストノードパラメータ定義
5 | */
6 | export default interface TextNodeParams extends NodeParams {
7 | family: string;
8 | text: string;
9 | size: number;
10 | color: string;
11 | padding: number;
12 | }
13 |
--------------------------------------------------------------------------------
/src/interfaces/master/AttackableMaster.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 拠点とユニットのパラメータマスターの基本 I/F
3 | */
4 | export default interface AttackableMaster {
5 | cost: number;
6 | maxHealth: number;
7 | power: number;
8 | speed: number;
9 | knockBackFrames: number;
10 | knockBackSpeed: number;
11 | }
12 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/master/StageMaster.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ステージ情報マスターのスキーマ定義
3 | */
4 | export default interface StageMaster {
5 | id: number;
6 | length: number;
7 | zLines: number;
8 | aiCastleId: number;
9 | waves: {
10 | [key: string]: {
11 | unitId: number;
12 | }[];
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/Node.ts:
--------------------------------------------------------------------------------
1 | import Event from 'interfaces/UiGraph/Event';
2 |
3 | /**
4 | * UiGraph 基本ノード定義
5 | */
6 | export default interface Node {
7 | id: string;
8 | type: string;
9 | position: number[];
10 | children: Node[];
11 | params?: {
12 | [key: string]: any;
13 | };
14 | events?: Event[];
15 | }
16 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/TextNodeParams.d.ts:
--------------------------------------------------------------------------------
1 | import NodeParams from 'interfaces/UiGraph/NodeParams';
2 | /**
3 | * UiGraph テキストノードパラメータ定義
4 | */
5 | export default interface TextNodeParams extends NodeParams {
6 | family: string;
7 | text: string;
8 | size: number;
9 | color: string;
10 | padding: number;
11 | }
12 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/Node.d.ts:
--------------------------------------------------------------------------------
1 | import Event from 'interfaces/UiGraph/Event';
2 | /**
3 | * UiGraph 基本ノード定義
4 | */
5 | export default interface Node {
6 | id: string;
7 | type: string;
8 | position: number[];
9 | children: Node[];
10 | params?: {
11 | [key: string]: any;
12 | };
13 | events?: Event[];
14 | }
15 |
--------------------------------------------------------------------------------
/lib-ts/entity/UnitEntity.d.ts:
--------------------------------------------------------------------------------
1 | import AttackableEntity from 'entity/AttackableEntity';
2 | /**
3 | * ユニットのパラメータ
4 | */
5 | export default class UnitEntity extends AttackableEntity {
6 | /**
7 | * ユニットID
8 | */
9 | unitId: number;
10 | /**
11 | * コンストラクタ
12 | */
13 | constructor(unitId: number, isPlayer: boolean);
14 | }
15 |
--------------------------------------------------------------------------------
/src/interfaces/api/UserBattle.ts:
--------------------------------------------------------------------------------
1 | import CastleMaster from 'interfaces/master/CastleMaster';
2 | /**
3 | * user_battle API のスキーマ定義
4 | */
5 | export default interface UserBattle {
6 | unlockedUnitIds: number[];
7 | unlockedStageId: number;
8 | castle: CastleMaster;
9 | cost: {
10 | max: number;
11 | recoveryPerFrame: number;
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/api/UserBattle.d.ts:
--------------------------------------------------------------------------------
1 | import CastleMaster from 'interfaces/master/CastleMaster';
2 | /**
3 | * user_battle API のスキーマ定義
4 | */
5 | export default interface UserBattle {
6 | unlockedUnitIds: number[];
7 | unlockedStageId: number;
8 | castle: CastleMaster;
9 | cost: {
10 | max: number;
11 | recoveryPerFrame: number;
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/lib-ts/modules/UiNodeFactory/TextFactory.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import * as UI from 'interfaces/UiGraph/index';
3 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
4 | /**
5 | * PIXI.Text のファクトリ
6 | */
7 | export default class TextFactory extends UiNodeFactory {
8 | createUiNode(nodeParams?: UI.TextNodeParams): PIXI.Container | null;
9 | }
10 |
--------------------------------------------------------------------------------
/src/interfaces/BattleParameter.ts:
--------------------------------------------------------------------------------
1 | import CastleMaster from 'interfaces/master/CastleMaster';
2 | /**
3 | * バトル開始時に渡すパラメータのインターフェース
4 | */
5 | export default interface BattleParameter {
6 | unitSlotCount: number;
7 | stageId: number;
8 | unitIds: number[];
9 | playerCastle: CastleMaster;
10 | cost: {
11 | recoveryPerFrame: number;
12 | max: number;
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/src/interfaces/Transition.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 |
3 | /**
4 | * シーントランジションのインターフェース
5 | */
6 | export default interface Transition {
7 | getContainer(): PIXI.Container | null;
8 | begin(): void;
9 | isBegan(): boolean;
10 | isFinished(): boolean;
11 | isActive(): boolean;
12 | update(dt: number): void;
13 | setCallback(callback: () => void): void;
14 | }
15 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/Transition.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | /**
3 | * シーントランジションのインターフェース
4 | */
5 | export default interface Transition {
6 | getContainer(): PIXI.Container | null;
7 | begin(): void;
8 | isBegan(): boolean;
9 | isFinished(): boolean;
10 | isActive(): boolean;
11 | update(dt: number): void;
12 | setCallback(callback: () => void): void;
13 | }
14 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/BattleParameter.d.ts:
--------------------------------------------------------------------------------
1 | import CastleMaster from 'interfaces/master/CastleMaster';
2 | /**
3 | * バトル開始時に渡すパラメータのインターフェース
4 | */
5 | export default interface BattleParameter {
6 | unitSlotCount: number;
7 | stageId: number;
8 | unitIds: number[];
9 | playerCastle: CastleMaster;
10 | cost: {
11 | recoveryPerFrame: number;
12 | max: number;
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/src/interfaces/master/UnitAnimationMaster.ts:
--------------------------------------------------------------------------------
1 | export type UnitAnimationTypeIndex = 'wait' | 'walk' | 'attack' | 'damage';
2 | /**
3 | * ユニットアニメーションマスターのスキーマ定義
4 | */
5 | export default interface UnitAnimationMaster {
6 | unitId: number;
7 | hitFrame: number;
8 | types: {
9 | [key in UnitAnimationTypeIndex]: {
10 | updateDuration: number;
11 | frames: string[];
12 | }
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | tower diffense
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lib-ts/entity/CastleEntity.d.ts:
--------------------------------------------------------------------------------
1 | import AttackableEntity from 'entity/AttackableEntity';
2 | import CastleMaster from 'interfaces/master/CastleMaster';
3 | /**
4 | * 拠点のパラメータ
5 | */
6 | export default class CastleEntity extends AttackableEntity {
7 | /**
8 | * 拠点 ID
9 | */
10 | castleId: number;
11 | /**
12 | * コンストラクタ
13 | */
14 | constructor(master: CastleMaster, isPlayer: boolean);
15 | }
16 |
--------------------------------------------------------------------------------
/src/entity/UnitEntity.ts:
--------------------------------------------------------------------------------
1 | import AttackableEntity from 'entity/AttackableEntity';
2 |
3 | /**
4 | * ユニットのパラメータ
5 | */
6 | export default class UnitEntity extends AttackableEntity {
7 | /**
8 | * ユニットID
9 | */
10 | public unitId: number = 0;
11 |
12 | /**
13 | * コンストラクタ
14 | */
15 | constructor(unitId: number, isPlayer: boolean) {
16 | super(isPlayer);
17 |
18 | this.unitId = unitId;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib-ts/modules/UiGraph.d.ts:
--------------------------------------------------------------------------------
1 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
2 | /**
3 | * UI を静的に定義しランタイムでロードするためのモジュール
4 | * 指定されたノードのファクトリを生成して保持する
5 | */
6 | export default class UiGraph {
7 | /**
8 | * ファクトリのキャッシュ
9 | */
10 | private static cachedFactory;
11 | /**
12 | * ファクトリを取得
13 | * なければキャッシュを作る
14 | */
15 | static getFactory(type: string): UiNodeFactory | null;
16 | }
17 |
--------------------------------------------------------------------------------
/lib-ts/modules/UiNodeFactory/battle/UnitButtonFactory.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import * as UI from 'interfaces/UiGraph/index';
3 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
4 | /**
5 | * バトルで用いる UnitButton のファクトリ
6 | * UnitButton インスタンスを返す
7 | */
8 | export default class UnitButtonFactory extends UiNodeFactory {
9 | createUiNode(nodeParams?: UI.SpriteNodeParams): PIXI.Container | null;
10 | }
11 |
--------------------------------------------------------------------------------
/www/assets/api_mock/user_battle.json:
--------------------------------------------------------------------------------
1 | {
2 | "unlockedUnitIds": [-1, 1, 2, 3, 4, 5],
3 | "unlockedStageId": 3,
4 | "castle": {
5 | "castleId": 1,
6 | "cost": 0,
7 | "maxHealth": 100,
8 | "power": 0,
9 | "speed": 0,
10 | "hitFrame": 0,
11 | "knockBackFrames": 0,
12 | "knockBackSpeed": 0
13 | },
14 | "cost": {
15 | "max": 100,
16 | "recoveryPerFrame": 0.05
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/master/UnitAnimationMaster.d.ts:
--------------------------------------------------------------------------------
1 | export declare type UnitAnimationTypeIndex = 'wait' | 'walk' | 'attack' | 'damage';
2 | /**
3 | * ユニットアニメーションマスターのスキーマ定義
4 | */
5 | export default interface UnitAnimationMaster {
6 | unitId: number;
7 | hitFrame: number;
8 | types: {
9 | [key in UnitAnimationTypeIndex]: {
10 | updateDuration: number;
11 | frames: string[];
12 | };
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/lib-ts/modules/UiNodeFactory/SpriteFactory.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import * as UI from 'interfaces/UiGraph/index';
3 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
4 | /**
5 | * PIXI.Sprite のファクトリ
6 | * テクスチャに、定義されているテクスチャ名で PIXI.utils.TextureCache から引いたデータを用いる
7 | */
8 | export default class SpriteFactory extends UiNodeFactory {
9 | createUiNode(nodeParams?: UI.SpriteNodeParams): PIXI.Container | null;
10 | }
11 |
--------------------------------------------------------------------------------
/www/assets/master/stage_master_1.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": 1,
3 | "length": 2000,
4 | "zLines": 10,
5 | "aiCastleId": 2,
6 | "waves": {
7 | "10": [
8 | { "unitId": 1 }
9 | ],
10 | "300": [
11 | { "unitId": 1 }
12 | ],
13 | "600": [
14 | { "unitId": 1 }
15 | ],
16 | "900": [
17 | { "unitId": 1 }
18 | ],
19 | "960": [
20 | { "unitId": 1 }
21 | ],
22 | "1020": [
23 | { "unitId": 1 }
24 | ]
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint-config-airbnb"
5 | ],
6 | "jsRules": {},
7 | "rules": {
8 | "indent": [true, "spaces", 4],
9 | "interface-name": false,
10 | "prefer-for-of": false,
11 | "max-line-length": [true, 80],
12 | "object-literal-sort-keys": false,
13 | "ordered-imports": false,
14 | "trailing-comma": false,
15 | "no-console": false,
16 | "no-increment-decrement": false,
17 | "variable-name": false
18 | },
19 | "rulesDirectory": []
20 | }
21 |
--------------------------------------------------------------------------------
/src/entity/CastleEntity.ts:
--------------------------------------------------------------------------------
1 | import AttackableEntity from 'entity/AttackableEntity';
2 | import CastleMaster from 'interfaces/master/CastleMaster';
3 |
4 | /**
5 | * 拠点のパラメータ
6 | */
7 | export default class CastleEntity extends AttackableEntity {
8 | /**
9 | * 拠点 ID
10 | */
11 | public castleId: number = 0;
12 |
13 | /**
14 | * コンストラクタ
15 | */
16 | constructor(master: CastleMaster, isPlayer: boolean) {
17 | super(isPlayer);
18 |
19 | this.castleId = master.castleId;
20 | this.maxHealth = master.maxHealth;
21 | this.currentHealth = this.maxHealth;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/www/assets/battle/castle/2.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "base_2_1.png":
4 | {
5 | "frame": {"x":1,"y":1,"w":480,"h":312},
6 | "rotated": false,
7 | "trimmed": false,
8 | "spriteSourceSize": {"x":0,"y":0,"w":480,"h":312},
9 | "sourceSize": {"w":480,"h":312}
10 | }},
11 | "animations": {
12 | },
13 | "meta": {
14 | "app": "https://www.codeandweb.com/texturepacker",
15 | "version": "1.0",
16 | "image": "2.png",
17 | "format": "RGBA8888",
18 | "size": {"w":482,"h":314},
19 | "scale": "1",
20 | "smartupdate": "$TexturePacker:SmartUpdate:dbc4170e527e9d58a1e4076ed40967d0:df7dd0830a8b06859a82b01dddd19130:5ed6fcaeb66fa059fba7886eb3eee15a$"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/www/assets/battle/castle/3.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "base_3_1.png":
4 | {
5 | "frame": {"x":1,"y":1,"w":388,"h":284},
6 | "rotated": false,
7 | "trimmed": false,
8 | "spriteSourceSize": {"x":0,"y":0,"w":388,"h":284},
9 | "sourceSize": {"w":388,"h":284}
10 | }},
11 | "animations": {
12 | },
13 | "meta": {
14 | "app": "https://www.codeandweb.com/texturepacker",
15 | "version": "1.0",
16 | "image": "3.png",
17 | "format": "RGBA8888",
18 | "size": {"w":390,"h":286},
19 | "scale": "1",
20 | "smartupdate": "$TexturePacker:SmartUpdate:b33049db7891851a2ee317d7f0cc7ef8:d69c08a0ad9231474e66e076b47b7fc6:4e25ec866a209ce3a44bf419a5862c0c$"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/www/assets/battle/castle/4.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "base_4_1.png":
4 | {
5 | "frame": {"x":1,"y":1,"w":412,"h":256},
6 | "rotated": false,
7 | "trimmed": false,
8 | "spriteSourceSize": {"x":0,"y":0,"w":412,"h":256},
9 | "sourceSize": {"w":412,"h":256}
10 | }},
11 | "animations": {
12 | },
13 | "meta": {
14 | "app": "https://www.codeandweb.com/texturepacker",
15 | "version": "1.0",
16 | "image": "4.png",
17 | "format": "RGBA8888",
18 | "size": {"w":414,"h":258},
19 | "scale": "1",
20 | "smartupdate": "$TexturePacker:SmartUpdate:45149af9f44540361d97859c6d360fe0:fd9d65d3bb1346440e0fb28d6be25074:5969e3cdce764dec8974e89b279b41c5$"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/UiGraph/index.d.ts:
--------------------------------------------------------------------------------
1 | import Node from 'interfaces/UiGraph/Node';
2 | import NodeParams from 'interfaces/UiGraph/NodeParams';
3 | import Event from 'interfaces/UiGraph/Event';
4 | import TextNode from 'interfaces/UiGraph/TextNode';
5 | import TextNodeParams from 'interfaces/UiGraph/TextNodeParams';
6 | import SpriteNode from 'interfaces/UiGraph/SpriteNode';
7 | import SpriteNodeParams from 'interfaces/UiGraph/SpriteNodeParams';
8 | import Metadata from 'interfaces/UiGraph/Metadata';
9 | import Graph from 'interfaces/UiGraph/Graph';
10 | export { Node, NodeParams, SpriteNode, SpriteNodeParams, TextNode, TextNodeParams, Event, Metadata, Graph };
11 |
--------------------------------------------------------------------------------
/lib-ts/modules/UiNodeFactory/UiNodeFactory.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import * as UI from 'interfaces/UiGraph/index';
3 | /**
4 | * UiGraph 要素のファクトリの基本クラス
5 | */
6 | export default class UiNodeFactory {
7 | /**
8 | * 派生クラスで実装し、適切な UiGraph ノードを生成する
9 | * デフォルトでは PIXI.Container インスタンスを返す
10 | */
11 | createUiNode(_?: UI.NodeParams): PIXI.Container | null;
12 | /**
13 | * 静的なノードデータから PIXI.Container 派生オブジェクトを生成する
14 | */
15 | createUiNodeByGraphElement(nodeData: UI.Node): PIXI.Container | null;
16 | /**
17 | * 定義されたイベントを実装する
18 | */
19 | attachUiEventByGraphElement(events: UI.Event[], node: PIXI.Container, target: any): void;
20 | }
21 |
--------------------------------------------------------------------------------
/www/assets/master/stage_master_2.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": 2,
3 | "length": 3000,
4 | "zLines": 10,
5 | "aiCastleId": 3,
6 | "waves": {
7 | "60": [
8 | { "unitId": 1 }
9 | ],
10 | "120": [
11 | { "unitId": 1 }
12 | ],
13 | "180": [
14 | { "unitId": 1 }
15 | ],
16 | "600": [
17 | { "unitId": 2 }
18 | ],
19 | "720": [
20 | { "unitId": 2 }
21 | ],
22 | "900": [
23 | { "unitId": 1 },
24 | { "unitId": 1 }
25 | ],
26 | "1080": [
27 | { "unitId": 2 }
28 | ],
29 | "1140": [
30 | { "unitId": 2 }
31 | ],
32 | "1320": [
33 | { "unitId": 2 },
34 | { "unitId": 2 }
35 | ]
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib-ts/modules/BattleLogicConfig.d.ts:
--------------------------------------------------------------------------------
1 | export default class BattleLogicConfig {
2 | /**
3 | * フレームごとのコスト回復量
4 | */
5 | costRecoveryPerFrame: number;
6 | /**
7 | * 利用可能コストの上限値
8 | */
9 | maxAvailableCost: number;
10 | /**
11 | * 1 対 1 の接敵のみを許可するかどうか
12 | */
13 | chivalrousEngage: boolean;
14 | /**
15 | * ノックバック条件となる体力閾値
16 | * [0.5] の場合、体力が 0.5 以上から 0.5 未満に変動した場合にノックバックする
17 | */
18 | knockBackHealthThreasholds: number[];
19 | constructor(params?: {
20 | costRecoveryPerFrame?: number;
21 | maxAvailableCost?: number;
22 | chivalrousEngage?: boolean;
23 | knockBackHealthThreasholds?: number[];
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/src/interfaces/UiGraph/index.ts:
--------------------------------------------------------------------------------
1 | import Node from 'interfaces/UiGraph/Node';
2 | import NodeParams from 'interfaces/UiGraph/NodeParams';
3 | import Event from 'interfaces/UiGraph/Event';
4 | import TextNode from 'interfaces/UiGraph/TextNode';
5 | import TextNodeParams from 'interfaces/UiGraph/TextNodeParams';
6 | import SpriteNode from 'interfaces/UiGraph/SpriteNode';
7 | import SpriteNodeParams from 'interfaces/UiGraph/SpriteNodeParams';
8 | import Metadata from 'interfaces/UiGraph/Metadata';
9 | import Graph from 'interfaces/UiGraph/Graph';
10 |
11 | export {
12 | Node,
13 | NodeParams,
14 | SpriteNode,
15 | SpriteNodeParams,
16 | TextNode,
17 | TextNodeParams,
18 | Event,
19 | Metadata,
20 | Graph
21 | };
22 |
--------------------------------------------------------------------------------
/www/assets/master/stage_master_3.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": 3,
3 | "length": 4000,
4 | "zLines": 10,
5 | "aiCastleId": 4,
6 | "waves": {
7 | "60": [
8 | { "unitId": 2 }
9 | ],
10 | "210": [
11 | { "unitId": 1 }
12 | ],
13 | "600": [
14 | { "unitId": 3 }
15 | ],
16 | "660": [
17 | { "unitId": 1 }
18 | ],
19 | "960": [
20 | { "unitId": 2 },
21 | { "unitId": 4 }
22 | ],
23 | "1020": [
24 | { "unitId": 1 }
25 | ],
26 | "1380": [
27 | { "unitId": 2 }
28 | ],
29 | "2400": [
30 | { "unitId": 5 }
31 | ],
32 | "2460": [
33 | { "unitId": 1 }
34 | ],
35 | "2490": [
36 | { "unitId": 4 }
37 | ],
38 | "2520": [
39 | { "unitId": 3 }
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib-ts/scenes/TitleScene.d.ts:
--------------------------------------------------------------------------------
1 | import LoaderAddParam from 'interfaces/PixiTypePolyfill/LoaderAddParam';
2 | import Scene from 'scenes/Scene';
3 | /**
4 | * タイトルシーン
5 | */
6 | export default class TitleScene extends Scene {
7 | /**
8 | * TOUCH TO START テキストの明滅感覚
9 | */
10 | private readonly textAppealDuration;
11 | /**
12 | * コンストラクタ
13 | */
14 | constructor();
15 | /**
16 | * リソースリストを作成し返却する
17 | */
18 | protected createInitialResourceList(): (LoaderAddParam | string)[];
19 | /**
20 | * リソースがロードされた時のコールバック
21 | */
22 | protected onResourceLoaded(): void;
23 | /**
24 | * 毎フレームの更新処理
25 | */
26 | update(dt: number): void;
27 | /**
28 | * 編成ボタンが離されたときのコールバック
29 | */
30 | startOrder(): void;
31 | }
32 |
--------------------------------------------------------------------------------
/src/modules/UiNodeFactory/battle/UnitButtonFactory.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import * as UI from 'interfaces/UiGraph/index';
3 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
4 | import UnitButton from 'display/battle/UnitButton';
5 |
6 | /**
7 | * バトルで用いる UnitButton のファクトリ
8 | * UnitButton インスタンスを返す
9 | */
10 | export default class UnitButtonFactory extends UiNodeFactory {
11 | public createUiNode(nodeParams?: UI.SpriteNodeParams): PIXI.Container | null {
12 | let texture = undefined;
13 |
14 | if (nodeParams) {
15 | const textureName = nodeParams.textureName;
16 | if (textureName && PIXI.utils.TextureCache[textureName]) {
17 | texture = PIXI.utils.TextureCache[textureName];
18 | }
19 | }
20 |
21 | return new UnitButton(texture);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/single_shot/Dead.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import UpdateObject from 'interfaces/UpdateObject';
3 | /**
4 | * 死亡を表現するエフェクト
5 | */
6 | export default class Dead extends PIXI.Container implements UpdateObject {
7 | /**
8 | * 経過フレーム数
9 | */
10 | private elapsedFrameCount;
11 | private bucket;
12 | private spirit;
13 | /**
14 | * このエフェクトで使用するリソースリスト
15 | */
16 | static readonly resourceList: string[];
17 | /**
18 | * コンストラクタ
19 | */
20 | constructor(flip: boolean);
21 | /**
22 | * UpdateObject インターフェース実装
23 | * 削除フラグが立っているか返す
24 | */
25 | isDestroyed(): boolean;
26 | /**
27 | * UpdateObject インターフェース実装
28 | * requestAnimationFrame 毎のアップデート処理
29 | */
30 | update(_delta: number): void;
31 | }
32 |
--------------------------------------------------------------------------------
/www/assets/battle/castle/1.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "base_1_1.png":
4 | {
5 | "frame": {"x":1,"y":1,"w":268,"h":348},
6 | "rotated": false,
7 | "trimmed": false,
8 | "spriteSourceSize": {"x":0,"y":0,"w":268,"h":348},
9 | "sourceSize": {"w":268,"h":348}
10 | },
11 | "base_1_2.png":
12 | {
13 | "frame": {"x":271,"y":1,"w":268,"h":348},
14 | "rotated": false,
15 | "trimmed": false,
16 | "spriteSourceSize": {"x":0,"y":0,"w":268,"h":348},
17 | "sourceSize": {"w":268,"h":348}
18 | }},
19 | "animations": {
20 | "base_1": ["base_1_1.png","base_1_2.png"]
21 | },
22 | "meta": {
23 | "app": "https://www.codeandweb.com/texturepacker",
24 | "version": "1.0",
25 | "image": "1.png",
26 | "format": "RGBA8888",
27 | "size": {"w":540,"h":350},
28 | "scale": "1",
29 | "smartupdate": "$TexturePacker:SmartUpdate:ce8bb6907bd7bb0a22c55435100dece4:7df210472dd324cc5b056b23defea5c4:d31de202d7213cc8961db402b7b4c95a$"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib-ts/entity/AttackableEntity.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 拠点のパラメータ
3 | */
4 | export default class AttackableEntity {
5 | /**
6 | * 一意の ID
7 | * エンティティ生成順に動的に割り当てられる
8 | */
9 | id: number;
10 | /**
11 | * プレイヤー側のユニットかどうか
12 | */
13 | isPlayer: boolean;
14 | /**
15 | * ステート
16 | */
17 | state: number;
18 | /**
19 | * 最大体力
20 | */
21 | maxHealth: number;
22 | /**
23 | * 現在の体力
24 | */
25 | currentHealth: number;
26 | /**
27 | * 現在フレームでのダメージ数
28 | */
29 | currentFrameDamage: number;
30 | /**
31 | * ノックバック経過フレーム数
32 | */
33 | currentKnockBackFrameCount: number;
34 | /**
35 | * 拠点からの距離
36 | */
37 | distance: number;
38 | /**
39 | * 接敵中のエンティティ
40 | */
41 | engagedEntity: AttackableEntity | null;
42 | /**
43 | * コンストラクタ
44 | */
45 | constructor(isPlayer: boolean);
46 | }
47 |
--------------------------------------------------------------------------------
/src/modules/UiNodeFactory/SpriteFactory.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import * as UI from 'interfaces/UiGraph/index';
3 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
4 |
5 | /**
6 | * PIXI.Sprite のファクトリ
7 | * テクスチャに、定義されているテクスチャ名で PIXI.utils.TextureCache から引いたデータを用いる
8 | */
9 | export default class SpriteFactory extends UiNodeFactory {
10 | public createUiNode(nodeParams?: UI.SpriteNodeParams): PIXI.Container | null {
11 | const sprite = new PIXI.Sprite();
12 |
13 | if (nodeParams) {
14 | const textureName = nodeParams.textureName;
15 | if (textureName && PIXI.utils.TextureCache[textureName]) {
16 | sprite.texture = PIXI.utils.TextureCache[textureName];
17 | }
18 | if (nodeParams.anchor) {
19 | sprite.anchor.x = nodeParams.anchor[0];
20 | sprite.anchor.y = nodeParams.anchor[1];
21 | }
22 | }
23 |
24 | return sprite;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/BattleResult.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import UpdateObject from 'interfaces/UpdateObject';
3 | /**
4 | * ゲーム結果を表現する
5 | */
6 | export default class BattleResult extends PIXI.Container implements UpdateObject {
7 | /**
8 | * アニメーション終了フラグ
9 | */
10 | animationEnded: boolean;
11 | /**
12 | * アニメーション終了時コールバック
13 | */
14 | onAnimationEnded: () => void;
15 | /**
16 | * 表示する PIXI.Sprite インスタンス
17 | */
18 | private sprite;
19 | /**
20 | * このエフェクトで使用するリソースリスト
21 | */
22 | static readonly resourceList: string[];
23 | /**
24 | * コンストラクタ
25 | */
26 | constructor(win: boolean);
27 | /**
28 | * UpdateObject インターフェース実装
29 | * 削除フラグが立っているか返す
30 | */
31 | isDestroyed(): boolean;
32 | /**
33 | * UpdateObject インターフェース実装
34 | * requestAnimationFrame 毎のアップデート処理
35 | */
36 | update(_delta: number): void;
37 | }
38 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/single_shot/AttackSmoke.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import UpdateObject from 'interfaces/UpdateObject';
3 | /**
4 | * 攻撃時のもくもくエフェクト
5 | */
6 | export default class AttackSmokeEffect extends PIXI.Container implements UpdateObject {
7 | /**
8 | * スプライトアニメーションを更新する頻度
9 | */
10 | static readonly TextureFrameUpdateFrequency: number;
11 | /**
12 | * 経過フレーム数
13 | */
14 | private elapsedFrameCount;
15 | /**
16 | * 表示する PIXI.Sprite インスタンス
17 | */
18 | private sprite;
19 | /**
20 | * このエフェクトで使用するリソースリスト
21 | */
22 | static readonly resourceList: string[];
23 | /**
24 | * コンストラクタ
25 | */
26 | constructor();
27 | /**
28 | * UpdateObject インターフェース実装
29 | * 削除フラグが立っているか返す
30 | */
31 | isDestroyed(): boolean;
32 | /**
33 | * UpdateObject インターフェース実装
34 | * requestAnimationFrame 毎のアップデート処理
35 | */
36 | update(_delta: number): void;
37 | }
38 |
--------------------------------------------------------------------------------
/src/entity/AttackableEntity.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 拠点のパラメータ
3 | */
4 | export default class AttackableEntity {
5 | /**
6 | * 一意の ID
7 | * エンティティ生成順に動的に割り当てられる
8 | */
9 | public id: number = 0;
10 | /**
11 | * プレイヤー側のユニットかどうか
12 | */
13 | public isPlayer: boolean = true;
14 | /**
15 | * ステート
16 | */
17 | public state: number = 0;
18 | /**
19 | * 最大体力
20 | */
21 | public maxHealth: number = 0;
22 | /**
23 | * 現在の体力
24 | */
25 | public currentHealth: number = 0;
26 | /**
27 | * 現在フレームでのダメージ数
28 | */
29 | public currentFrameDamage: number = 0;
30 | /**
31 | * ノックバック経過フレーム数
32 | */
33 | public currentKnockBackFrameCount: number = 0;
34 | /**
35 | * 拠点からの距離
36 | */
37 | public distance: number = 0;
38 | /**
39 | * 接敵中のエンティティ
40 | */
41 | public engagedEntity: AttackableEntity | null = null;
42 |
43 | /**
44 | * コンストラクタ
45 | */
46 | constructor(isPlayer: boolean) {
47 | this.isPlayer = isPlayer;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/modules/UiGraph.ts:
--------------------------------------------------------------------------------
1 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
2 | import TextFactory from 'modules/UiNodeFactory/TextFactory';
3 | import SpriteFactory from 'modules/UiNodeFactory/SpriteFactory';
4 |
5 | /**
6 | * UI を静的に定義しランタイムでロードするためのモジュール
7 | * 指定されたノードのファクトリを生成して保持する
8 | */
9 | export default class UiGraph {
10 | /**
11 | * ファクトリのキャッシュ
12 | */
13 | private static cachedFactory: {
14 | [key: string]: UiNodeFactory;
15 | } = {};
16 |
17 | /**
18 | * ファクトリを取得
19 | * なければキャッシュを作る
20 | */
21 | public static getFactory(type: string): UiNodeFactory | null {
22 | if (!UiGraph.cachedFactory[type]) {
23 | let Factory;
24 |
25 | switch (type) {
26 | case 'text': Factory = TextFactory; break;
27 | case 'sprite': Factory = SpriteFactory; break;
28 | }
29 |
30 | if (!Factory) {
31 | return null;
32 | }
33 |
34 | UiGraph.cachedFactory[type] = new Factory();
35 | }
36 |
37 | return UiGraph.cachedFactory[type];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/UnitButton.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | /**
3 | * ユニット生成をリクエストするための UI 用のボタン
4 | */
5 | export default class UnitButton extends PIXI.Container {
6 | /**
7 | * ボタン枠のインデックス
8 | */
9 | slotIndex: number;
10 | /**
11 | * ボタンに割り当てられたユニットの ID
12 | */
13 | unitId: number;
14 | /**
15 | * ボタン画像
16 | */
17 | private button;
18 | /**
19 | * コストテキスト
20 | */
21 | private text;
22 | /**
23 | * フィルター
24 | */
25 | private filter;
26 | /**
27 | * コンストラクタ
28 | */
29 | constructor(texture?: PIXI.Texture);
30 | /**
31 | * ボタン枠インデックスとユニット ID で初期化する
32 | */
33 | init(slotIndex: number, unitId?: number, cost?: number): void;
34 | /**
35 | * ColorMatrixFilter の有効/無効を切り替える
36 | */
37 | toggleFilter(enabled: boolean): void;
38 | /**
39 | * ユニットを変更する
40 | */
41 | changeUnit(unitId?: number, cost?: number): void;
42 | /**
43 | * 指定したユニット ID のテクスチャを変更する
44 | */
45 | private getTexture;
46 | }
47 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/single_shot/CollapseExplodeEffect.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import UpdateObject from 'interfaces/UpdateObject';
3 | /**
4 | * 破壊時の爆発を表現するエフェクト
5 | */
6 | export default class CollapseExplodeEffect extends PIXI.Container implements UpdateObject {
7 | /**
8 | * スプライトアニメーションを更新する頻度
9 | */
10 | static readonly TextureFrameUpdateFrequency: number;
11 | /**
12 | * 経過フレーム数
13 | */
14 | private elapsedFrameCount;
15 | /**
16 | * 表示する PIXI.Sprite インスタンス
17 | */
18 | private sprite;
19 | /**
20 | * このエフェクトで使用するリソースリスト
21 | */
22 | static readonly resourceList: string[];
23 | /**
24 | * コンストラクタ
25 | */
26 | constructor();
27 | /**
28 | * UpdateObject インターフェース実装
29 | * 削除フラグが立っているか返す
30 | */
31 | isDestroyed(): boolean;
32 | /**
33 | * UpdateObject インターフェース実装
34 | * requestAnimationFrame 毎のアップデート処理
35 | */
36 | update(_delta: number): void;
37 | /**
38 | * 効果音を再生する
39 | */
40 | private playSe;
41 | }
42 |
--------------------------------------------------------------------------------
/lib-ts/scenes/transition/Immediate.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Transition from 'interfaces/Transition';
3 | /**
4 | * 即座にシーン遷移させるトランジション
5 | */
6 | export default class Immediate implements Transition {
7 | private onTransitionFinished;
8 | private finished;
9 | /**
10 | * トランジション描画物を含む PIXI.Container インスタンスを返す
11 | */
12 | getContainer(): PIXI.Container | null;
13 | /**
14 | * トランジション開始処理
15 | * このトランジションは即時終了させる
16 | */
17 | begin(): void;
18 | /**
19 | * トランジションが開始しているかどうかを返す
20 | * このトランジションは即時終了するため true になることなはない
21 | */
22 | isBegan(): boolean;
23 | /**
24 | * トランジションが終了しているかどうかを返す
25 | */
26 | isFinished(): boolean;
27 | /**
28 | * トランジションが実行中かどうかを返す
29 | * このトランジションは即時終了するため true になることなはない
30 | */
31 | isActive(): boolean;
32 | /**
33 | * トランジションを更新する
34 | * このトランジションは即時終了するため何も行わない
35 | */
36 | update(_dt: number): void;
37 | /**
38 | * トランジション終了時のコールバックを登録する
39 | */
40 | setCallback(callback: () => void): void;
41 | }
42 |
--------------------------------------------------------------------------------
/www/assets/battle/effects/attack_smoke/attack_smoke.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "effect_2_1.png":
4 | {
5 | "frame": {"x":1,"y":129,"w":154,"h":130},
6 | "rotated": false,
7 | "trimmed": true,
8 | "spriteSourceSize": {"x":63,"y":75,"w":154,"h":130},
9 | "sourceSize": {"w":280,"h":280}
10 | },
11 | "effect_2_2.png":
12 | {
13 | "frame": {"x":1,"y":261,"w":154,"h":130},
14 | "rotated": false,
15 | "trimmed": true,
16 | "spriteSourceSize": {"x":63,"y":75,"w":154,"h":130},
17 | "sourceSize": {"w":280,"h":280}
18 | },
19 | "effect_2_3.png":
20 | {
21 | "frame": {"x":1,"y":1,"w":154,"h":126},
22 | "rotated": false,
23 | "trimmed": true,
24 | "spriteSourceSize": {"x":63,"y":75,"w":154,"h":126},
25 | "sourceSize": {"w":280,"h":280}
26 | }},
27 | "animations": {
28 | "effect_2": ["effect_2_1.png","effect_2_2.png","effect_2_3.png"]
29 | },
30 | "meta": {
31 | "app": "https://www.codeandweb.com/texturepacker",
32 | "version": "1.0",
33 | "image": "attack_smoke.png",
34 | "format": "RGBA8888",
35 | "size": {"w":156,"h":392},
36 | "scale": "1",
37 | "smartupdate": "$TexturePacker:SmartUpdate:6ba90ad53afabbe53245c98ae5cd62b9:a272a8823fe53ea82d33dfbb3bc1bbcb:94ab1914b3c54d869f8f68a0102d6259$"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/www/assets/master/castle_master.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "castleId": 1,
4 | "cost": 0,
5 | "maxHealth": 100,
6 | "power": 0,
7 | "speed": 0,
8 | "hitFrame": 0,
9 | "knockBackFrames": 0,
10 | "knockBackSpeed": 0
11 | },
12 | {
13 | "castleId": 2,
14 | "cost": 0,
15 | "maxHealth": 200,
16 | "power": 0,
17 | "speed": 0,
18 | "hitFrame": 0,
19 | "knockBackFrames": 0,
20 | "knockBackSpeed": 0
21 | },
22 | {
23 | "castleId": 3,
24 | "cost": 0,
25 | "maxHealth": 300,
26 | "power": 0,
27 | "speed": 0,
28 | "hitFrame": 0,
29 | "knockBackFrames": 0,
30 | "knockBackSpeed": 0
31 | },
32 | {
33 | "castleId": 4,
34 | "cost": 0,
35 | "maxHealth": 400,
36 | "power": 0,
37 | "speed": 0,
38 | "hitFrame": 0,
39 | "knockBackFrames": 0,
40 | "knockBackSpeed": 0
41 | },
42 | {
43 | "castleId": 2,
44 | "cost": 0,
45 | "maxHealth": 500,
46 | "power": 0,
47 | "speed": 0,
48 | "hitFrame": 0,
49 | "knockBackFrames": 0,
50 | "knockBackSpeed": 0
51 | }
52 | ]
53 |
--------------------------------------------------------------------------------
/www/assets/master/unit_master.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "unitId": 1,
4 | "cost": 8,
5 | "maxHealth": 20,
6 | "power": 6,
7 | "speed": 2,
8 | "hitFrame": 4,
9 | "knockBackFrames": 30,
10 | "knockBackSpeed": 4
11 | },
12 | {
13 | "unitId": 2,
14 | "cost": 15,
15 | "maxHealth": 60,
16 | "power": 2,
17 | "speed": 1,
18 | "hitFrame": 2,
19 | "knockBackFrames": 30,
20 | "knockBackSpeed": 4
21 | },
22 | {
23 | "unitId": 3,
24 | "cost": 24,
25 | "maxHealth": 20,
26 | "power": 4,
27 | "speed": 3,
28 | "hitFrame": 3,
29 | "knockBackFrames": 30,
30 | "knockBackSpeed": 4
31 | },
32 | {
33 | "unitId": 4,
34 | "cost": 32,
35 | "maxHealth": 40,
36 | "power": 16,
37 | "speed": 2,
38 | "hitFrame": 4,
39 | "knockBackFrames": 30,
40 | "knockBackSpeed": 4
41 | },
42 | {
43 | "unitId": 5,
44 | "cost": 40,
45 | "maxHealth": 100,
46 | "power": 22,
47 | "speed": 1.5,
48 | "hitFrame": 5,
49 | "knockBackFrames": 30,
50 | "knockBackSpeed": 4
51 | }
52 | ]
53 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "esnext",
5 | "lib": [
6 | "esnext",
7 | "dom"
8 | ],
9 | "baseUrl": "./src",
10 | "outDir": "./lib-ts",
11 | "declaration": true,
12 | "sourceMap": true,
13 | "allowJs": false,
14 | "forceConsistentCasingInFileNames": true,
15 | "allowSyntheticDefaultImports": false,
16 | "moduleResolution": "node",
17 | "strict": true,
18 | "alwaysStrict": true,
19 | "noImplicitReturns": true,
20 | "noFallthroughCasesInSwitch": false,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true,
23 | "preserveConstEnums": false
24 | },
25 | "compileOnSave": true,
26 | "include": [
27 | "src/**/*"
28 | ],
29 | "exclude": [
30 | ".git",
31 | "node_modules",
32 | "lib"
33 | ],
34 | "typedocOptions": {
35 | "name": "tower-diffence",
36 | "mode": "file",
37 | "out": "./docs",
38 | "gitRevision": "develop",
39 | "ignoreCompilerErrors": true,
40 | "includeDeclarations": true,
41 | "excludeExternals": true,
42 | "excludePrivate": false,
43 | "excludeProtected": false,
44 | "excludeNotExported": false,
45 | "preserveConstEnums": true
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/modules/BattleLogicConfig.ts:
--------------------------------------------------------------------------------
1 | export default class BattleLogicConfig {
2 | /**
3 | * フレームごとのコスト回復量
4 | */
5 | public costRecoveryPerFrame: number = 0;
6 | /**
7 | * 利用可能コストの上限値
8 | */
9 | public maxAvailableCost: number = 100;
10 | /**
11 | * 1 対 1 の接敵のみを許可するかどうか
12 | */
13 | public chivalrousEngage: boolean = true;
14 | /**
15 | * ノックバック条件となる体力閾値
16 | * [0.5] の場合、体力が 0.5 以上から 0.5 未満に変動した場合にノックバックする
17 | */
18 | public knockBackHealthThreasholds: number[] = [0.25, 0.5, 0.75];
19 |
20 | constructor(params?: {
21 | costRecoveryPerFrame?: number,
22 | maxAvailableCost?: number,
23 | chivalrousEngage?: boolean,
24 | knockBackHealthThreasholds?: number[]
25 | }) {
26 | if (!params) {
27 | return;
28 | }
29 |
30 | if (params.costRecoveryPerFrame) {
31 | this.costRecoveryPerFrame = params.costRecoveryPerFrame;
32 | }
33 | if (params.maxAvailableCost) {
34 | this.maxAvailableCost = params.maxAvailableCost;
35 | }
36 | if (params.chivalrousEngage) {
37 | this.chivalrousEngage = params.chivalrousEngage;
38 | }
39 | if (params.knockBackHealthThreasholds) {
40 | this.knockBackHealthThreasholds = params.knockBackHealthThreasholds.sort().reverse();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/Castle.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Attackable from 'display/battle/Attackable';
3 | /**
4 | * 拠点の振舞い、及び見た目に関する処理を行う
5 | * Attackable を継承する
6 | */
7 | export default class Castle extends Attackable {
8 | /**
9 | * 爆発エフェクト用コンテナ
10 | */
11 | explodeContainer: PIXI.Container;
12 | /**
13 | * 拠点 ID
14 | */
15 | protected castleId: number;
16 | /**
17 | * このクラスで利用するリソースリスト
18 | */
19 | static readonly resourceList: string[];
20 | /**
21 | * コンストラクタ
22 | */
23 | constructor(castleId: number, spawnPosition: {
24 | x: number;
25 | y: number;
26 | });
27 | /**
28 | * UpdateObject インターフェース実装
29 | * requestAnimationFrame 毎のアップデート処理
30 | */
31 | update(_dt: number): void;
32 | /**
33 | * アニメーションを初期化する
34 | */
35 | resetAnimation(): void;
36 | /**
37 | * 破壊状態にする
38 | */
39 | collapse(): void;
40 | /**
41 | * ユニット生成状態にする
42 | */
43 | spawn(playSe: boolean): void;
44 | /**
45 | * アニメーションを更新する
46 | */
47 | updateAnimation(): void;
48 | /**
49 | * 破壊時の爆発を生成する
50 | */
51 | private spawnCollapseExplode;
52 | /**
53 | * ユニット生成時の効果音を再生する
54 | */
55 | private playSpawnSe;
56 | }
57 |
--------------------------------------------------------------------------------
/src/modules/UiNodeFactory/TextFactory.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import * as UI from 'interfaces/UiGraph/index';
3 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
4 |
5 | /**
6 | * PIXI.Text のファクトリ
7 | */
8 | export default class TextFactory extends UiNodeFactory {
9 | public createUiNode(nodeParams?: UI.TextNodeParams): PIXI.Container | null {
10 | const textStyleParams: PIXI.TextStyleOptions = {};
11 |
12 | const container = new PIXI.Text();
13 |
14 | if (nodeParams) {
15 | if (nodeParams.family !== undefined) {
16 | textStyleParams.fontFamily = nodeParams.family;
17 | }
18 | if (nodeParams.size !== undefined) {
19 | textStyleParams.fontSize = nodeParams.size;
20 | }
21 | if (nodeParams.color !== undefined) {
22 | textStyleParams.fill = nodeParams.color;
23 | }
24 | if (nodeParams.padding !== undefined) {
25 | textStyleParams.padding = nodeParams.padding;
26 | }
27 | if (nodeParams.anchor !== undefined) {
28 | container.anchor.set(...nodeParams.anchor);
29 | }
30 | if (nodeParams.text !== undefined) {
31 | container.text = nodeParams.text;
32 | }
33 | }
34 |
35 | container.style = new PIXI.TextStyle(textStyleParams);
36 |
37 | return container;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/modules/UiNodeFactory/UiNodeFactory.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import * as UI from 'interfaces/UiGraph/index';
3 |
4 | /**
5 | * UiGraph 要素のファクトリの基本クラス
6 | */
7 | export default class UiNodeFactory {
8 | /**
9 | * 派生クラスで実装し、適切な UiGraph ノードを生成する
10 | * デフォルトでは PIXI.Container インスタンスを返す
11 | */
12 | public createUiNode(_?: UI.NodeParams): PIXI.Container | null {
13 | return new PIXI.Container();
14 | }
15 |
16 | /**
17 | * 静的なノードデータから PIXI.Container 派生オブジェクトを生成する
18 | */
19 | public createUiNodeByGraphElement(nodeData: UI.Node): PIXI.Container | null {
20 | const node = this.createUiNode(nodeData.params);
21 |
22 | if (node) {
23 | node.name = nodeData.id;
24 | node.position.set(nodeData.position[0], nodeData.position[1]);
25 | }
26 |
27 | return node;
28 | }
29 |
30 | /**
31 | * 定義されたイベントを実装する
32 | */
33 | public attachUiEventByGraphElement(
34 | events: UI.Event[],
35 | node: PIXI.Container,
36 | target: any
37 | ): void {
38 | node.interactive = true;
39 |
40 | for (let i = 0; i < events.length; i++) {
41 | const event = events[i];
42 | const fx = target[event.callback];
43 | if (!fx) {
44 | continue;
45 | }
46 |
47 | node.on(event.type, () => fx.call(target, ...event.arguments));
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib-ts/modules/Sound.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * サウンド処理を行うクラス
3 | */
4 | export default class Sound {
5 | /**
6 | * ボリュームのセッタ
7 | */
8 | /**
9 | * ボリュームのゲッタ
10 | */
11 | volume: number;
12 | /**
13 | * サウンド再生時間を返す
14 | */
15 | readonly elapsedTime: number;
16 | /**
17 | * paused の public ゲッタ
18 | */
19 | isPaused(): boolean;
20 | /**
21 | * GainNode インスタンス
22 | */
23 | gainNode: GainNode;
24 | /**
25 | * ループ再生フラグ
26 | */
27 | loop: boolean;
28 | /**
29 | * AudioBuffer インスタンス
30 | */
31 | private buffer;
32 | /**
33 | * AudioBufferSourceNode インスタンス
34 | */
35 | private source;
36 | /**
37 | * 再生開始フラグ
38 | */
39 | private played;
40 | /**
41 | * 一時停止フラグ
42 | */
43 | private paused;
44 | /**
45 | * サウンド再生開始時間オフセット
46 | */
47 | private offset;
48 | /**
49 | * AudioContext インスタンスの currentTime を基準に保持する再生開始時間
50 | */
51 | private playedAt;
52 | /**
53 | * コンストラクタ
54 | * AudioBuffer はユーザ側で用意する
55 | */
56 | constructor(buf: AudioBuffer);
57 | /**
58 | * 再生開始
59 | */
60 | play(loop?: boolean, offset?: number): void;
61 | /**
62 | * 停止
63 | */
64 | stop(): void;
65 | /**
66 | * 一時停止
67 | */
68 | pause(): void;
69 | /**
70 | * 再開
71 | */
72 | resume(): void;
73 | }
74 |
--------------------------------------------------------------------------------
/src/scenes/transition/Immediate.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Transition from 'interfaces/Transition';
3 |
4 | /**
5 | * 即座にシーン遷移させるトランジション
6 | */
7 | export default class Immediate implements Transition {
8 | private onTransitionFinished: () => void = () => {};
9 | private finished: boolean = false;
10 |
11 | /**
12 | * トランジション描画物を含む PIXI.Container インスタンスを返す
13 | */
14 | public getContainer(): PIXI.Container | null {
15 | return null;
16 | }
17 |
18 | /**
19 | * トランジション開始処理
20 | * このトランジションは即時終了させる
21 | */
22 | public begin(): void {
23 | this.finished = true;
24 | this.onTransitionFinished();
25 | }
26 | /**
27 | * トランジションが開始しているかどうかを返す
28 | * このトランジションは即時終了するため true になることなはない
29 | */
30 | public isBegan(): boolean {
31 | return false;
32 | }
33 | /**
34 | * トランジションが終了しているかどうかを返す
35 | */
36 | public isFinished(): boolean {
37 | return this.finished;
38 | }
39 | /**
40 | * トランジションが実行中かどうかを返す
41 | * このトランジションは即時終了するため true になることなはない
42 | */
43 | public isActive(): boolean {
44 | return false;
45 | }
46 |
47 | /**
48 | * トランジションを更新する
49 | * このトランジションは即時終了するため何も行わない
50 | */
51 | public update(_dt: number): void {
52 | return;
53 | }
54 |
55 | /**
56 | * トランジション終了時のコールバックを登録する
57 | */
58 | public setCallback(callback: () => void): void {
59 | this.onTransitionFinished = callback;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const tsconfig = require('./tsconfig');
3 |
4 | module.exports = function(config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['mocha'],
8 |
9 | preprocessors: {
10 | 'test/**/*.js': ['webpack']
11 | },
12 |
13 | // files
14 | files: [
15 | 'test/*.js',
16 | 'test/**/*.js',
17 | 'src/*.ts',
18 | 'src/**/*.ts',
19 | ],
20 |
21 | // logs
22 | reporters: ['mocha'],
23 | colors: true,
24 | logLevel: config.LOG_ERROR,
25 |
26 | // browser
27 | browsers: [
28 | 'ChromeHeadless'
29 | ],
30 | port: 9876,
31 | concurrency: Infinity,
32 |
33 | // watch
34 | autoWatch: false,
35 | singleRun: true,
36 |
37 | // webpack preprocessor config
38 | webpack: {
39 | mode: 'development',
40 |
41 | devtool: 'source-map',
42 |
43 | module: {
44 | rules: [
45 | {
46 | test: /\.ts$/,
47 | exclude: /node_modules/,
48 | use: [
49 | { loader: 'ts-loader' }
50 | ]
51 | }
52 | ]
53 | },
54 | resolve: {
55 | extensions: ['.ts', '.js'],
56 | modules: [
57 | path.resolve(__dirname, 'src'),
58 | "node_modules"
59 | ]
60 | },
61 | node: {
62 | fs: 'empty',
63 | child_process: 'empty'
64 | },
65 | },
66 | });
67 | };
68 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tower-diffense",
3 | "version": "0.0.1",
4 | "description": "sample tower diffense game made with pixi.js",
5 | "main": "index.js",
6 | "scripts": {
7 | "build:develop": "webpack --mode development",
8 | "build:production": "webpack --mode production",
9 | "build:docs": "typedoc 'src/'",
10 | "test:lint": "tslint -p tsconfig.json --format stylish \"src/**/*.ts*\"",
11 | "workflow:build": "npm run build:develop && npm run build:production && npm run build:docs",
12 | "server": "webpack-dev-server"
13 | },
14 | "author": "Smith",
15 | "license": "MIT",
16 | "devDependencies": {
17 | "@types/chai": "^4.1.7",
18 | "@types/mocha": "^5.2.5",
19 | "@types/pixi.js": "^4.8.4",
20 | "@types/webfontloader": "^1.6.29",
21 | "chai": "^4.2.0",
22 | "karma": "^3.1.3",
23 | "karma-chrome-launcher": "^2.2.0",
24 | "karma-mocha": "^1.3.0",
25 | "karma-mocha-reporter": "^2.2.5",
26 | "karma-webpack": "^3.0.5",
27 | "mocha": "^5.2.0",
28 | "sinon": "^7.2.2",
29 | "ts-loader": "^5.3.1",
30 | "tslint": "^5.11.0",
31 | "tslint-config-airbnb": "^5.11.1",
32 | "typedoc": "^0.13.0",
33 | "typescript": "^3.2.2",
34 | "webpack": "^4.27.1",
35 | "webpack-cli": "^3.1.2",
36 | "webpack-dev-server": "^3.1.10"
37 | },
38 | "dependencies": {
39 | "detect-browser": "^4.0.3",
40 | "pixi.js": "^4.8.3",
41 | "webfontloader": "^1.6.28"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/Attackable.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import UpdateObject from 'interfaces/UpdateObject';
3 | /**
4 | * エンティティの振舞い、及び見た目に関する処理を行う
5 | */
6 | export default abstract class Attackable implements UpdateObject {
7 | /**
8 | * 表示する PIXI.Sprite インスタンス
9 | */
10 | sprite: PIXI.Sprite;
11 | /**
12 | * スポーンした座標
13 | */
14 | protected spawnedPosition: PIXI.Point;
15 | /**
16 | * 現在のアニメーション種別
17 | */
18 | animationType: string;
19 | /**
20 | * 経過フレーム数
21 | */
22 | protected elapsedFrameCount: number;
23 | /**
24 | * 破棄フラグ
25 | */
26 | protected destroyed: boolean;
27 | /**
28 | * spawnedPosition を返す
29 | */
30 | readonly distanceBasePosition: PIXI.Point;
31 | constructor(spawnPosition: {
32 | x: number;
33 | y: number;
34 | });
35 | /**
36 | * UpdateObject インターフェース実装
37 | * 削除フラグが立っているか返す
38 | */
39 | isDestroyed(): boolean;
40 | /**
41 | * UpdateObject インターフェース実装
42 | * requestAnimationFrame 毎のアップデート処理
43 | */
44 | update(_dt: number): void;
45 | /**
46 | * 接敵しているかどうかを返す
47 | */
48 | isFoeContact(target: PIXI.Container): boolean;
49 | /**
50 | * アニメーション時間をリセットする
51 | */
52 | resetAnimation(): void;
53 | /**
54 | * アニメーションを更新する
55 | */
56 | updateAnimation(): void;
57 | /**
58 | * このオブジェクトと子要素を破棄する
59 | */
60 | destroy(): void;
61 | }
62 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019 Smith, Pyorosh, Enimur
2 |
3 | A copy or copies of image resource (the "Creative") is/are excluded from the license which applied to the software inclided to this repository.
4 | Permission is hereby granted, free of charge, to any person obtaining the Creative included in this repository, to use, copy, modify, merge copies of the Creative, subject to the following conditions.
5 | The person obtaining a copy or copies of this Creative included in this repository is not granted the rights to publish, distribute, sublicense, and/or sell copies of the Creative.
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Creative.
8 |
9 | THE CREATIVE 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 CREATIVE OR THE USE OR OTHER DEALINGS IN THE CREATIVE.
10 |
11 |
12 | 本リポジトリに含まれる単一/複数の画像リソース(以下「クリエイティヴ」)は、本リポジトリに含まれるソフトウェアに適用されるライセンス対象からは除外されます。
13 | 以下に定める条件に従い、本リポジトリに含まれるクリエイティヴの複製を取得するすべての人に対し、クリエイティヴの複製を使用、複写、変更、結合をする権利を無償で許可します。
14 | 本リポジトリに含まれるクリエイティヴの複製を取得するすべての人に対し、クリエイティヴの複製を掲載、頒布、サブライセンス、および/または販売する権利は許可されていません。
15 |
16 | 上記の著作権表示および本許諾表示を、クリエイティヴのすべての複製または重要な部分に記載するものとします。
17 |
18 | 作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、クリエイティヴに起因または関連し、あるいはクリエイティヴの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとします。
--------------------------------------------------------------------------------
/lib-ts/scenes/transition/Fade.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Transition from 'interfaces/Transition';
3 | /**
4 | * トランジションのフェード表現
5 | */
6 | export default class Fade implements Transition {
7 | /**
8 | * フェード開始時の黒画面アルファ
9 | */
10 | private alphaFrom;
11 | /**
12 | * フェード終了時の黒画面アルファ
13 | */
14 | private alphaTo;
15 | /**
16 | * 1フレーム毎の黒画面アルファ加算値
17 | */
18 | private alphaProgress;
19 | /**
20 | * 黒画面のコンテナ
21 | */
22 | private container;
23 | /**
24 | * 黒画面の描画
25 | */
26 | private overlay;
27 | /**
28 | * トランジション開始フラグ
29 | */
30 | private transitionBegan;
31 | /**
32 | * トランジション終了フラグ
33 | */
34 | private transitionFinished;
35 | /**
36 | * トランジション終了時コールバック
37 | */
38 | private onTransitionFinished;
39 | /**
40 | * コンストラクタ
41 | */
42 | constructor(alphaFrom: number, alphaTo: number, alphaProgress: number);
43 | /**
44 | * トランジション描画物を含む PIXI.Container インスタンスを返す
45 | */
46 | getContainer(): PIXI.Container | null;
47 | /**
48 | * トランジション開始処理
49 | */
50 | begin(): void;
51 | /**
52 | * トランジションが開始しているかどうかを返す
53 | */
54 | isBegan(): boolean;
55 | /**
56 | * トランジションが終了しているかどうかを返す
57 | */
58 | isFinished(): boolean;
59 | /**
60 | * トランジションが実行中かどうかを返す
61 | */
62 | isActive(): boolean;
63 | /**
64 | * トランジションを更新する
65 | */
66 | update(_dt: number): void;
67 | /**
68 | * トランジション終了時のコールバックを登録する
69 | */
70 | setCallback(callback: () => void): void;
71 | }
72 |
--------------------------------------------------------------------------------
/www/assets/battle/effects/collapse_explode/collapse_explode.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "effect_1_1.png":
4 | {
5 | "frame": {"x":1,"y":244,"w":253,"h":190},
6 | "rotated": false,
7 | "trimmed": true,
8 | "spriteSourceSize": {"x":19,"y":63,"w":253,"h":190},
9 | "sourceSize": {"w":272,"h":256}
10 | },
11 | "effect_1_2.png":
12 | {
13 | "frame": {"x":1,"y":1,"w":254,"h":241},
14 | "rotated": false,
15 | "trimmed": true,
16 | "spriteSourceSize": {"x":11,"y":15,"w":254,"h":241},
17 | "sourceSize": {"w":272,"h":256}
18 | },
19 | "effect_1_3.png":
20 | {
21 | "frame": {"x":1,"y":436,"w":242,"h":237},
22 | "rotated": false,
23 | "trimmed": true,
24 | "spriteSourceSize": {"x":15,"y":19,"w":242,"h":237},
25 | "sourceSize": {"w":272,"h":256}
26 | },
27 | "effect_1_4.png":
28 | {
29 | "frame": {"x":1,"y":675,"w":234,"h":218},
30 | "rotated": false,
31 | "trimmed": true,
32 | "spriteSourceSize": {"x":7,"y":7,"w":234,"h":218},
33 | "sourceSize": {"w":272,"h":256}
34 | },
35 | "effect_1_5.png":
36 | {
37 | "frame": {"x":1,"y":895,"w":257,"h":221},
38 | "rotated": true,
39 | "trimmed": true,
40 | "spriteSourceSize": {"x":0,"y":0,"w":257,"h":221},
41 | "sourceSize": {"w":272,"h":256}
42 | }},
43 | "animations": {
44 | "effect_1": ["effect_1_1.png","effect_1_2.png","effect_1_3.png","effect_1_4.png","effect_1_5.png"]
45 | },
46 | "meta": {
47 | "app": "https://www.codeandweb.com/texturepacker",
48 | "version": "1.0",
49 | "image": "collapse_explode.png",
50 | "format": "RGBA8888",
51 | "size": {"w":256,"h":1153},
52 | "scale": "1",
53 | "smartupdate": "$TexturePacker:SmartUpdate:810a59d47b355a715fc729a155721432:cc215e6d9a6cb46f6d4b1f65841d19b7:986daa0d7218cbfd41a445b0257a5fed$"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/single_shot/HealthGauge.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import UpdateObject from 'interfaces/UpdateObject';
3 | /**
4 | * health 増減を表現するエフェクト
5 | */
6 | export default class HealthGaugeEffect extends PIXI.Container implements UpdateObject {
7 | /**
8 | * ゲージの幅
9 | */
10 | gaugeWidth: number;
11 | /**
12 | * ゲージの高さ
13 | */
14 | gaugeHeight: number;
15 | /**
16 | * 最大 health の色
17 | */
18 | maxColor: number;
19 | /**
20 | * 現在の health の色
21 | */
22 | currentColor: number;
23 | /**
24 | * 枠線の色
25 | */
26 | lineColor: number;
27 | /**
28 | * 経過フレーム数
29 | */
30 | private elapsedFrameCount;
31 | /**
32 | * 減少アニメーションのフレーム数
33 | */
34 | private reducingFrameCount;
35 | /**
36 | * 表示するフレーム数
37 | */
38 | private activeFrameCount;
39 | /**
40 | * 最大 health 用の PIXI.Graphics
41 | */
42 | private maxGraphic;
43 | /**
44 | * 現在の health 用の PIXI.Graphics
45 | */
46 | private currentGraphic;
47 | /**
48 | * 減算元のゲージ比率
49 | */
50 | private fromPercent;
51 | /**
52 | * 減算後のゲージ比率
53 | */
54 | private toPercent;
55 | /**
56 | * このエフェクトで使用するリソースリスト
57 | */
58 | static readonly resourceList: string[];
59 | /**
60 | * コンストラクタ
61 | */
62 | constructor(fromPercent: number, toPercent: number);
63 | /**
64 | * UpdateObject インターフェース実装
65 | * 削除フラグが立っているか返す
66 | */
67 | isDestroyed(): boolean;
68 | /**
69 | * UpdateObject インターフェース実装
70 | * requestAnimationFrame 毎のアップデート処理
71 | */
72 | update(_delta: number): void;
73 | }
74 |
--------------------------------------------------------------------------------
/lib-ts/managers/GameManager.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Scene from 'scenes/Scene';
3 | /**
4 | * ゲーム全体のマネージャ
5 | * 主にシーンを扱う
6 | */
7 | export default class GameManager {
8 | /**
9 | * シングルトン新スタンス
10 | */
11 | static instance: GameManager;
12 | /**
13 | * PIXI.Application インスタンス
14 | * 初期化時に生成される
15 | */
16 | game: PIXI.Application;
17 | /**
18 | * シーンのリソースロード完了フラグ
19 | * シーントランジションを制御するためのフラグ
20 | */
21 | private sceneResourceLoaded;
22 | /**
23 | * シーンのトランジション完了フラグ
24 | * シーントランジションを制御するためのフラグ
25 | */
26 | private sceneTransitionOutFinished;
27 | /**
28 | * 現在のシーンインスタンス
29 | */
30 | private currentScene?;
31 | /**
32 | * コンストラクタ
33 | * PIXI.Application インスタンスはユーザ任意のものを使用する
34 | */
35 | constructor(app: PIXI.Application);
36 | /**
37 | * ゲームを起動する
38 | * 画面サイズや PIXI.ApplicationOptions を渡すことができる
39 | */
40 | static start(params: {
41 | glWidth: number;
42 | glHeight: number;
43 | option?: PIXI.ApplicationOptions;
44 | }): void;
45 | /**
46 | * フルスクリーンに切り替える
47 | */
48 | static requestFullScreen(): void;
49 | /**
50 | * 可能であれば新しいシーンへのトランジションを開始する
51 | */
52 | static transitionInIfPossible(newScene: Scene): boolean;
53 | /**
54 | * シーンをロードする
55 | * 新しいシーンのリソース読み込みと古いシーンのトランジションを同時に開始する
56 | * いずれも完了したら、新しいシーンのトランジションを開始する
57 | */
58 | static loadScene(newScene: Scene): void;
59 | /**
60 | * HTML canvas のりサイズ処理を行う
61 | */
62 | static resizeCanvas(): void;
63 | /**
64 | * 動作環境に応じて適切ならフルスクリーン設定をする
65 | */
66 | private static enableFullScreenIfNeeded;
67 | }
68 |
--------------------------------------------------------------------------------
/lib-ts/managers/IndexedDBManager.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * indexed db マネージャ
3 | * レコードを KVS 形式のインターフェースで取り扱う
4 | */
5 | export default class IndexedDBManager {
6 | /**
7 | * このマネージャが扱う固定データベース名
8 | */
9 | static readonly dbName: string;
10 | /**
11 | * このマネージャが扱うデータベースバージョン
12 | */
13 | static readonly dbVersion: number;
14 | /**
15 | * このマネージャが扱う固定ストア名
16 | */
17 | static readonly storeName: string;
18 | /**
19 | * このマネージャが扱う固定ストアのインデックス名称
20 | */
21 | static readonly storeIndex: string;
22 | /**
23 | * IDBDatabase インスタンス
24 | */
25 | private static db;
26 | /**
27 | * マネージャを初期化する
28 | * DB 接続を開き保持しておく
29 | */
30 | static init(onError: (e: Event) => void): void;
31 | /**
32 | * レコードを保存する
33 | */
34 | static put(key: string, data: any, onSuccess?: (e: Event) => void, onError?: (e?: Event) => void): void;
35 | /**
36 | * レコードを取得する
37 | * レコードが存在しなければ undefined を返す
38 | */
39 | static get(key: string, onSuccess: (value: any, key: string | undefined) => void, onError?: (e?: Event) => void): void;
40 | /**
41 | * レコードを削除する
42 | */
43 | static delete(key: string, onSuccess?: (e: Event) => void, onError?: (e?: Event) => void): void;
44 | /**
45 | * すべてのレコードを削除する
46 | */
47 | static clear(onSuccess?: (e: Event) => void, onError?: (e?: Event) => void): void;
48 | /**
49 | * onupgradeneeded コールバックを処理しなければならない時に実行するメソッド
50 | */
51 | private static upgradeDB;
52 | /**
53 | * トランザクションを生成し、ストアオブジェクトを返す
54 | */
55 | private static getStoreObject;
56 | /**
57 | * Key/Value をこのマネージャが扱うオブジェクトに変換する
58 | */
59 | private static createRecordObject;
60 | }
61 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as WebFont from 'webfontloader';
2 | import 'Config';
3 | import Resource from 'Resource';
4 | import TitleScene from 'scenes/TitleScene';
5 | import GameManager from 'managers/GameManager';
6 |
7 | /**
8 | * ゲームの初期化処理
9 | */
10 | function initGame() {
11 | const width = 1136;
12 | const height = 640;
13 |
14 | const pixiAppOption: PIXI.ApplicationOptions = {
15 | backgroundColor: 0x222222
16 | };
17 |
18 | Debug: {
19 | // コンソールからオブジェクトを調査できるように window に生やす
20 | (window as any).GameManager = GameManager;
21 |
22 | // 画面キャプチャ
23 | pixiAppOption.preserveDrawingBuffer = true;
24 | document.body.addEventListener('keydown', (event) => {
25 | if (event.ctrlKey === true && event.key === 'c') {
26 | const a = document.createElement("a");
27 |
28 | a.setAttribute("href", GameManager.instance.game.view.toDataURL());
29 | a.setAttribute("download", `figure_${new Date().getTime()}`);
30 | a.click();
31 | }
32 | });
33 | }
34 |
35 |
36 | GameManager.start({
37 | glWidth: width,
38 | glHeight: height,
39 | option: pixiAppOption
40 | });
41 | // 最初のシーンの読み込み
42 | GameManager.loadScene(new TitleScene());
43 | }
44 |
45 | let fontLoaded = false;
46 | let windowLoaded = false;
47 |
48 | /**
49 | * フォント読みこみ
50 | * window 読み込みも完了していたらゲームを起動する
51 | */
52 | WebFont.load({
53 | custom: {
54 | families: [Resource.FontFamily.Default],
55 | urls: ['base.css']
56 | },
57 | active: () => {
58 | fontLoaded = true;
59 | if (windowLoaded) {
60 | initGame();
61 | }
62 | }
63 | });
64 |
65 | /**
66 | * エントリーポイント
67 | * フォント読み込みも完了していたらゲームを起動する
68 | */
69 | window.onload = () => {
70 | windowLoaded = true;
71 | if (fontLoaded) {
72 | initGame();
73 | }
74 | };
75 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/Unit.d.ts:
--------------------------------------------------------------------------------
1 | import UnitAnimationMaster from 'interfaces/master/UnitAnimationMaster';
2 | import Attackable from 'display/battle/Attackable';
3 | import HealthGauge from 'display/battle/single_shot/HealthGauge';
4 | /**
5 | * ユニットの振舞い、及び見た目に関する処理を行う
6 | * UnitEntity を継承する
7 | */
8 | export default class Unit extends Attackable {
9 | /**
10 | * アニメーション情報
11 | */
12 | protected animationMaster: UnitAnimationMaster;
13 | /**
14 | * 現在のアニメーションフレーム
15 | */
16 | protected animationFrameId: number;
17 | /**
18 | * 再生をリクエストされたアニメーション種別
19 | */
20 | protected requestedAnimation: string | null;
21 | /**
22 | * HealthGauge インスタンス
23 | * Unit で管理する
24 | */
25 | protected healthGauge: HealthGauge | null;
26 | /**
27 | * コンストラクタ
28 | */
29 | constructor(animationMaster: UnitAnimationMaster, spawnPosition: {
30 | x: number;
31 | y: number;
32 | });
33 | /**
34 | * アニメーション再生をリセットする
35 | */
36 | resetAnimation(): void;
37 | /**
38 | * UpdateObject インターフェース実装
39 | * requestAnimationFrame 毎のアップデート処理
40 | */
41 | update(_dt: number): void;
42 | /**
43 | * 人師種別のアニメーションの再生をリクエストする
44 | * リクエストされたアニメーションは再生可能になり次第再生される
45 | */
46 | requestAnimation(type: string): void;
47 | /**
48 | * 現在のアニメーションフレームのインデックスが当たり判定の発生するインデックスかどうかを返す
49 | */
50 | isHitFrame(): boolean;
51 | /**
52 | * 現在のアニメーションが終了するフレーム時間かどうかを返す
53 | */
54 | isAnimationLastFrameTime(): boolean;
55 | /**
56 | * HealthGauge インスタンスを生成し、座標を設定して返す
57 | */
58 | spawnHealthGauge(fromPercent: number, toPercent: number): HealthGauge;
59 | /**
60 | * アニメーションを更新する
61 | */
62 | updateAnimation(): void;
63 | /**
64 | * アニメーション遷移が可能であれば遷移する
65 | */
66 | private transformAnimationIfPossible;
67 | }
68 |
--------------------------------------------------------------------------------
/lib-ts/interfaces/BattleLogicDelegate.d.ts:
--------------------------------------------------------------------------------
1 | import AttackableEntity from 'entity/AttackableEntity';
2 | import UnitEntity from 'entity/UnitEntity';
3 | import CastleEntity from 'entity/CastleEntity';
4 | /**
5 | * BattleLogic が委譲する処理を著したインターフェース
6 | */
7 | export default interface BattleLogicDelegate {
8 | /**
9 | * CastleEntity が生成された時のコールバック
10 | */
11 | onCastleEntitySpawned(entity: CastleEntity, isPlayer: boolean): void;
12 | /**
13 | * UnitEntity が生成された時のコールバック
14 | */
15 | onUnitEntitySpawned(entity: UnitEntity): void;
16 | /**
17 | * エンティティのステートが変更した際のコールバック
18 | */
19 | onAttackableEntityStateChanged(entity: AttackableEntity, oldState: number): void;
20 | /**
21 | * UnitEntity が歩いた時のコールバック
22 | */
23 | onAttackableEntityWalked(entity: AttackableEntity): void;
24 | /**
25 | * UnitEntity がノックバックした時のコールバック
26 | */
27 | onAttackableEntityKnockingBack(entity: AttackableEntity, knockBackRate: number): void;
28 | /**
29 | * エンティティの health が変動した際のコールバック
30 | */
31 | onAttackableEntityHealthUpdated(attacker: AttackableEntity, target: AttackableEntity, fromHealth: number, toHealth: number, maxHealth: number): void;
32 | /**
33 | * 利用可能コストが変動した際のコールバック
34 | */
35 | onAvailableCostUpdated(cost: number, maxCost: number, availablePlayerUnitIds: number[]): void;
36 | /**
37 | * ゲームが終了した際のコールバック
38 | */
39 | onGameOver(isPlayerWon: boolean): void;
40 | /**
41 | * 渡されたエンティティが接敵可能か返す
42 | */
43 | shouldEngageAttackableEntity(attacker: AttackableEntity, target: AttackableEntity): boolean;
44 | /**
45 | * 渡されたエンティティが攻撃可能か返す
46 | */
47 | shouldDamage(attacker: AttackableEntity, target: AttackableEntity): boolean;
48 | /**
49 | * 渡されたユニットが移動可能か返す
50 | */
51 | shouldAttackableWalk(attackable: AttackableEntity): boolean;
52 | }
53 |
--------------------------------------------------------------------------------
/lib-ts/display/battle/Field.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | /**
3 | * ユニットや拠点が配置されるバトル背景のクラス
4 | */
5 | export default class Field extends PIXI.Container {
6 | /**
7 | * 最後に要素を追加した zLine のインデックス
8 | */
9 | lastZlineIndex: number;
10 | /**
11 | * タップダウン数カウント
12 | * タップダウン重複処理を防止するために数える
13 | */
14 | private pointerDownCount;
15 | /**
16 | * タップ位置の X 座標
17 | * スクロール処理のために保持する
18 | */
19 | private lastPointerPositionX;
20 | /**
21 | * スクロールの限界座標値
22 | */
23 | private foregroundScrollLimit;
24 | /**
25 | * 表示上の前後関係を制御するための PIXI.Container オブジェクト
26 | */
27 | private containers;
28 | /**
29 | * ユニットが配置される前景の PIXI.Container 配列
30 | */
31 | private foreZLines;
32 | /**
33 | * このクラスで利用するリソースリスト
34 | */
35 | static readonly resourceList: string[];
36 | /**
37 | * foreZLines の要素の数を返す
38 | */
39 | readonly zLineCount: number;
40 | /**
41 | * コンストラクタ
42 | */
43 | constructor();
44 | /**
45 | * フィールドの長さとユニットを配置するラインの数で初期化する
46 | */
47 | init(options?: any): void;
48 | /**
49 | * 前景内で背景エフェクトとして addChild する
50 | */
51 | addChildAsForeBackgroundEffect(container: PIXI.Container): void;
52 | /**
53 | * 指定した zLine インデックスの PIXI.Container に addChild する
54 | */
55 | addChildToZLine(container: PIXI.Container, zlineIndex: number): void;
56 | /**
57 | * 最後に追加した zLine とは異なるインデクスを返す
58 | */
59 | getDifferentZlineIndex(): number;
60 | /**
61 | * 指定した zLine インデックスの基準 Y 座標を返す
62 | */
63 | getZlineBaseY(zlineIndex: number): number;
64 | /**
65 | * タップ押下時の制御コールバック
66 | */
67 | private onPointerDown;
68 | /**
69 | * タップ移動時の制御コールバック
70 | */
71 | private onPointerMove;
72 | /**
73 | * タップ終了時の制御コールバック
74 | */
75 | private onPointerUp;
76 | }
77 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const TerserPlugin = require('terser-webpack-plugin');
3 | const path = require('path');
4 |
5 | module.exports = (env, argv) => {
6 | const mode = process.env.NODE_ENV || process.env.WEBPACK_ENV || argv.mode || 'development';
7 | const isProduction = (mode === 'production');
8 |
9 | return {
10 | mode: mode,
11 | entry: {
12 | index: path.join(__dirname, 'src', 'index.ts'),
13 | },
14 |
15 | output: {
16 | path: path.join(__dirname, 'www'),
17 | filename: isProduction
18 | ? 'tower-diffense.min.js'
19 | : 'tower-diffense.js',
20 | library: 'tower-diffense',
21 | libraryTarget: 'umd'
22 | },
23 |
24 | // typescript transpiling files
25 | module: {
26 | rules: [
27 | {
28 | test: /\.ts$/,
29 | exclude: /node_modules/,
30 | use: [
31 | { loader: 'ts-loader' }
32 | ]
33 | }
34 | ]
35 | },
36 |
37 | // binding files
38 | resolve: {
39 | extensions: ['.js', '.ts'],
40 | modules: [
41 | path.resolve(__dirname, 'src'),
42 | "node_modules"
43 | ]
44 | },
45 |
46 | node: {
47 | fs: 'empty'
48 | },
49 |
50 | devtool: 'source-map',
51 |
52 | optimization: {
53 | minimizer: [
54 | // クラス名で比較している箇所を機能させる
55 | new TerserPlugin({
56 | sourceMap: !isProduction,
57 | terserOptions: {
58 | keep_classnames: true,
59 | keep_fnames: true
60 | }
61 | })
62 | ]
63 | },
64 |
65 | plugins: [
66 | new webpack.optimize.OccurrenceOrderPlugin(),
67 | new webpack.optimize.AggressiveMergingPlugin()
68 | ],
69 |
70 | devServer: {
71 | contentBase: path.join(__dirname, 'www'),
72 | compress: true,
73 | port: 8080
74 | }
75 | }
76 | };
77 |
--------------------------------------------------------------------------------
/src/interfaces/BattleLogicDelegate.ts:
--------------------------------------------------------------------------------
1 | import AttackableEntity from 'entity/AttackableEntity';
2 | import UnitEntity from 'entity/UnitEntity';
3 | import CastleEntity from 'entity/CastleEntity';
4 |
5 | /**
6 | * BattleLogic が委譲する処理を著したインターフェース
7 | */
8 | export default interface BattleLogicDelegate {
9 | /**
10 | * CastleEntity が生成された時のコールバック
11 | */
12 | onCastleEntitySpawned(entity: CastleEntity, isPlayer: boolean): void;
13 | /**
14 | * UnitEntity が生成された時のコールバック
15 | */
16 | onUnitEntitySpawned(entity: UnitEntity): void;
17 | /**
18 | * エンティティのステートが変更した際のコールバック
19 | */
20 | onAttackableEntityStateChanged(
21 | entity: AttackableEntity,
22 | oldState: number
23 | ): void;
24 | /**
25 | * UnitEntity が歩いた時のコールバック
26 | */
27 | onAttackableEntityWalked(entity: AttackableEntity): void;
28 | /**
29 | * UnitEntity がノックバックした時のコールバック
30 | */
31 | onAttackableEntityKnockingBack(entity: AttackableEntity, knockBackRate: number): void;
32 | /**
33 | * エンティティの health が変動した際のコールバック
34 | */
35 | onAttackableEntityHealthUpdated(
36 | attacker: AttackableEntity,
37 | target: AttackableEntity,
38 | fromHealth: number,
39 | toHealth: number,
40 | maxHealth: number
41 | ): void;
42 | /**
43 | * 利用可能コストが変動した際のコールバック
44 | */
45 | onAvailableCostUpdated(
46 | cost: number,
47 | maxCost: number,
48 | availablePlayerUnitIds: number[]
49 | ): void;
50 | /**
51 | * ゲームが終了した際のコールバック
52 | */
53 | onGameOver(isPlayerWon: boolean): void;
54 | /**
55 | * 渡されたエンティティが接敵可能か返す
56 | */
57 | shouldEngageAttackableEntity(
58 | attacker: AttackableEntity,
59 | target: AttackableEntity
60 | ): boolean;
61 | /**
62 | * 渡されたエンティティが攻撃可能か返す
63 | */
64 | shouldDamage(attacker: AttackableEntity, target: AttackableEntity): boolean;
65 | /**
66 | * 渡されたユニットが移動可能か返す
67 | */
68 | shouldAttackableWalk(attackable: AttackableEntity): boolean;
69 | }
70 |
--------------------------------------------------------------------------------
/www/assets/ui_graph/battle_scene.json:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": [
3 | {
4 | "id": "unit_button_1",
5 | "type": "unit_button",
6 | "position": [120, 500],
7 | "events": [
8 | {
9 | "type": "pointerdown",
10 | "callback": "onUnitButtonTapped",
11 | "arguments": [0]
12 | }
13 | ]
14 | },
15 | {
16 | "id": "unit_button_2",
17 | "type": "unit_button",
18 | "position": [260, 500],
19 | "events": [
20 | {
21 | "type": "pointerdown",
22 | "callback": "onUnitButtonTapped",
23 | "arguments": [1]
24 | }
25 | ]
26 | },
27 | {
28 | "id": "unit_button_3",
29 | "type": "unit_button",
30 | "position": [400, 500],
31 | "events": [
32 | {
33 | "type": "pointerdown",
34 | "callback": "onUnitButtonTapped",
35 | "arguments": [2]
36 | }
37 | ]
38 | },
39 | {
40 | "id": "unit_button_4",
41 | "type": "unit_button",
42 | "position": [540, 500],
43 | "events": [
44 | {
45 | "type": "pointerdown",
46 | "callback": "onUnitButtonTapped",
47 | "arguments": [3]
48 | }
49 | ]
50 | },
51 | {
52 | "id": "unit_button_5",
53 | "type": "unit_button",
54 | "position": [680, 500],
55 | "events": [
56 | {
57 | "type": "pointerdown",
58 | "callback": "onUnitButtonTapped",
59 | "arguments": [4]
60 | }
61 | ]
62 | },
63 | {
64 | "id": "cost_text",
65 | "type": "text",
66 | "position": [860, 540],
67 | "params": {
68 | "family": "MisakiGothic",
69 | "text": "0/0",
70 | "size": 64,
71 | "color": "0xffffff",
72 | "padding": 16
73 | }
74 | }
75 | ],
76 | "metadata": {
77 | "screen": {
78 | "width": 640,
79 | "height": 1136
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/display/battle/BattleResult.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Resource from 'Resource';
3 | import UpdateObject from 'interfaces/UpdateObject';
4 | import GameManager from 'managers/GameManager';
5 |
6 | /**
7 | * ゲーム結果を表現する
8 | */
9 | export default class BattleResult
10 | extends PIXI.Container
11 | implements UpdateObject {
12 | /**
13 | * アニメーション終了フラグ
14 | */
15 | public animationEnded: boolean = false;
16 |
17 | /**
18 | * アニメーション終了時コールバック
19 | */
20 | public onAnimationEnded: () => void = () => {};
21 |
22 | /**
23 | * 表示する PIXI.Sprite インスタンス
24 | */
25 | private sprite!: PIXI.Sprite;
26 |
27 | /**
28 | * このエフェクトで使用するリソースリスト
29 | */
30 | public static get resourceList(): string[] {
31 | return [
32 | Resource.Static.BattleResultWin,
33 | Resource.Static.BattleResultLose
34 | ];
35 | }
36 |
37 | /**
38 | * コンストラクタ
39 | */
40 | constructor(win: boolean) {
41 | super();
42 |
43 | const textureCacheName = (win)
44 | ? Resource.Static.BattleResultWin
45 | : Resource.Static.BattleResultLose;
46 | const texture = PIXI.utils.TextureCache[textureCacheName];
47 |
48 | this.sprite = new PIXI.Sprite(texture);
49 | this.sprite.anchor.set(0.5);
50 |
51 | this.sprite.position.x = GameManager.instance.game.view.width * 0.5;
52 | this.sprite.position.y = -(this.sprite.height * 0.5);
53 |
54 | this.addChild(this.sprite);
55 | }
56 |
57 | /**
58 | * UpdateObject インターフェース実装
59 | * 削除フラグが立っているか返す
60 | */
61 | public isDestroyed(): boolean {
62 | return this._destroyed;
63 | }
64 |
65 | /**
66 | * UpdateObject インターフェース実装
67 | * requestAnimationFrame 毎のアップデート処理
68 | */
69 | public update(_delta: number): void {
70 | if (this.animationEnded) {
71 | return;
72 | }
73 |
74 | this.sprite.position.y += 4;
75 |
76 | if (this.sprite.position.y >= GameManager.instance.game.view.height * 0.5) {
77 | this.animationEnded = true;
78 | this.onAnimationEnded();
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/display/battle/single_shot/AttackSmoke.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Resource from 'Resource';
3 | import UpdateObject from 'interfaces/UpdateObject';
4 |
5 | /**
6 | * 攻撃時のもくもくエフェクト
7 | */
8 | export default class AttackSmokeEffect
9 | extends PIXI.Container
10 | implements UpdateObject {
11 | /**
12 | * スプライトアニメーションを更新する頻度
13 | */
14 | public static readonly TextureFrameUpdateFrequency: number = 4;
15 |
16 | /**
17 | * 経過フレーム数
18 | */
19 | private elapsedFrameCount: number = 0;
20 | /**
21 | * 表示する PIXI.Sprite インスタンス
22 | */
23 | private sprite!: PIXI.Sprite;
24 |
25 | /**
26 | * このエフェクトで使用するリソースリスト
27 | */
28 | public static get resourceList(): string[] {
29 | return [Resource.Static.AttackSmoke];
30 | }
31 |
32 | /**
33 | * コンストラクタ
34 | */
35 | constructor() {
36 | super();
37 |
38 | this.sprite = new PIXI.Sprite(Resource.TextureFrame.AttackSmoke(1));
39 | this.addChild(this.sprite);
40 | }
41 |
42 | /**
43 | * UpdateObject インターフェース実装
44 | * 削除フラグが立っているか返す
45 | */
46 | public isDestroyed(): boolean {
47 | return this._destroyed;
48 | }
49 |
50 | /**
51 | * UpdateObject インターフェース実装
52 | * requestAnimationFrame 毎のアップデート処理
53 | */
54 | public update(_delta: number): void {
55 | if (this.isDestroyed()) {
56 | return;
57 | }
58 |
59 | this.elapsedFrameCount++;
60 | // 半透明を表現
61 | this.sprite.visible = (this.elapsedFrameCount % 2 === 0);
62 |
63 | const frequency = AttackSmokeEffect.TextureFrameUpdateFrequency;
64 | // テクスチャ更新周期になったら次のテクスチャに切り替える
65 | if (this.elapsedFrameCount % frequency === 0) {
66 | const count = this.elapsedFrameCount / frequency;
67 | const index = Math.floor(count) + 1;
68 | // すべてのテクスチャが再生されたら自然消滅させる
69 | if (index > Resource.MaxFrameIndex(Resource.Static.AttackSmoke)) {
70 | this.sprite.destroy();
71 | this.destroy();
72 | return;
73 | }
74 |
75 | this.sprite.texture = Resource.TextureFrame.AttackSmoke(index);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/scenes/TitleScene.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Resource from 'Resource';
3 | import GameManager from 'managers/GameManager';
4 | import SoundManager from 'managers/SoundManager';
5 | import LoaderAddParam from 'interfaces/PixiTypePolyfill/LoaderAddParam';
6 | import Scene from 'scenes/Scene';
7 | import OrderScene from 'scenes/OrderScene';
8 | import Fade from 'scenes/transition/Fade';
9 |
10 | /**
11 | * タイトルシーン
12 | */
13 | export default class TitleScene extends Scene {
14 | /**
15 | * TOUCH TO START テキストの明滅感覚
16 | */
17 | private readonly textAppealDuration: number = 20;
18 |
19 | /**
20 | * コンストラクタ
21 | */
22 | constructor() {
23 | super();
24 |
25 | this.transitionIn = new Fade(1.0, 0.0, -0.02);
26 | this.transitionOut = new Fade(0.0, 1.0, 0.02);
27 |
28 | this.interactive = true;
29 | this.on('pointerup', () => this.startOrder());
30 | }
31 |
32 | /**
33 | * リソースリストを作成し返却する
34 | */
35 | protected createInitialResourceList(): (LoaderAddParam | string)[] {
36 | const assets = super.createInitialResourceList();
37 | assets.push(Resource.Audio.Bgm.Title);
38 | return assets;
39 | }
40 |
41 | /**
42 | * リソースがロードされた時のコールバック
43 | */
44 | protected onResourceLoaded(): void {
45 | super.onResourceLoaded();
46 |
47 | const bgmTitleName = Resource.Audio.Bgm.Title;
48 | const resource = PIXI.loader.resources[bgmTitleName] as any;
49 | SoundManager.createSound(bgmTitleName, resource.buffer);
50 |
51 | this.playBgm(Resource.Audio.Bgm.Title);
52 | }
53 |
54 | /**
55 | * 毎フレームの更新処理
56 | */
57 | public update(dt: number): void {
58 | super.update(dt);
59 |
60 | if (this.elapsedFrameCount % this.textAppealDuration === 0) {
61 | const visible = this.uiGraph.touch_to_start.visible;
62 | this.uiGraph.touch_to_start.visible = !visible;
63 | }
64 | }
65 |
66 | /**
67 | * 編成ボタンが離されたときのコールバック
68 | */
69 | public startOrder(): void {
70 | if (this.transitionIn.isActive() || this.transitionOut.isActive()) {
71 | return;
72 | }
73 |
74 | GameManager.loadScene(new OrderScene());
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/display/battle/UnitButton.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Resource from 'Resource';
3 |
4 | /**
5 | * ユニット生成をリクエストするための UI 用のボタン
6 | */
7 | export default class UnitButton extends PIXI.Container {
8 | /**
9 | * ボタン枠のインデックス
10 | */
11 | public slotIndex: number = -1;
12 | /**
13 | * ボタンに割り当てられたユニットの ID
14 | */
15 | public unitId: number = -1;
16 |
17 | /**
18 | * ボタン画像
19 | */
20 | private button: PIXI.Sprite = new PIXI.Sprite();
21 | /**
22 | * コストテキスト
23 | */
24 | private text: PIXI.Text = new PIXI.Text('', {
25 | fontFamily: Resource.FontFamily.Default,
26 | fontSize: 24,
27 | fill: 0xffffff,
28 | padding: 4
29 | });
30 | /**
31 | * フィルター
32 | */
33 | private filter: PIXI.filters.ColorMatrixFilter = new PIXI.filters.ColorMatrixFilter();
34 |
35 | /**
36 | * コンストラクタ
37 | */
38 | constructor(texture?: PIXI.Texture) {
39 | super();
40 |
41 | this.text.position.set(46, 88);
42 | this.filter.desaturate();
43 | this.toggleFilter(false);
44 | this.button.filters = [this.filter];
45 |
46 | if (texture) {
47 | this.button.texture = texture;
48 | }
49 |
50 | this.addChild(this.button);
51 | this.addChild(this.text);
52 | }
53 |
54 | /**
55 | * ボタン枠インデックスとユニット ID で初期化する
56 | */
57 | public init(slotIndex: number, unitId: number = -1, cost: number = -1): void {
58 | this.slotIndex = slotIndex;
59 | this.changeUnit(unitId, cost);
60 | }
61 |
62 | /**
63 | * ColorMatrixFilter の有効/無効を切り替える
64 | */
65 | public toggleFilter(enabled: boolean): void {
66 | this.filter.enabled = enabled;
67 | }
68 |
69 | /**
70 | * ユニットを変更する
71 | */
72 | public changeUnit(unitId: number = -1, cost: number = -1): void {
73 | const texture = this.getTexture(unitId);
74 | if (!texture) {
75 | return;
76 | }
77 |
78 | this.unitId = unitId;
79 | this.button.texture = texture;
80 | this.text.text = (cost >= 0) ? `${cost}` : '';
81 | }
82 |
83 | /**
84 | * 指定したユニット ID のテクスチャを変更する
85 | */
86 | private getTexture(unitId: number = -1): PIXI.Texture | null {
87 | const resourceId = Resource.Dynamic.UnitPanel(unitId);
88 | const resource = PIXI.loader.resources[resourceId];
89 | if (!resource || !resource.texture) {
90 | return null;
91 | }
92 | return resource.texture;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/display/battle/Attackable.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import UpdateObject from 'interfaces/UpdateObject';
3 |
4 | /**
5 | * エンティティの振舞い、及び見た目に関する処理を行う
6 | */
7 | export default abstract class Attackable implements UpdateObject {
8 | /**
9 | * 表示する PIXI.Sprite インスタンス
10 | */
11 | public sprite!: PIXI.Sprite;
12 | /**
13 | * スポーンした座標
14 | */
15 | protected spawnedPosition!: PIXI.Point;
16 | /**
17 | * 現在のアニメーション種別
18 | */
19 | public animationType!: string;
20 | /**
21 | * 経過フレーム数
22 | */
23 | protected elapsedFrameCount: number = 0;
24 | /**
25 | * 破棄フラグ
26 | */
27 | protected destroyed: boolean = false;
28 |
29 | /**
30 | * spawnedPosition を返す
31 | */
32 | public get distanceBasePosition(): PIXI.Point {
33 | return this.spawnedPosition;
34 | }
35 |
36 | constructor(spawnPosition: { x: number, y: number }) {
37 | this.animationType = '';
38 |
39 | this.sprite = new PIXI.Sprite();
40 | this.sprite.anchor.x = 0.5;
41 | this.sprite.anchor.y = 1.0;
42 | this.sprite.position.set(
43 | spawnPosition.x,
44 | spawnPosition.y
45 | );
46 |
47 | this.spawnedPosition = new PIXI.Point(
48 | this.sprite.position.x,
49 | this.sprite.position.y
50 | );
51 |
52 | Object.freeze(this.spawnedPosition);
53 | }
54 |
55 | /**
56 | * UpdateObject インターフェース実装
57 | * 削除フラグが立っているか返す
58 | */
59 | public isDestroyed(): boolean {
60 | return this.destroyed;
61 | }
62 |
63 | /**
64 | * UpdateObject インターフェース実装
65 | * requestAnimationFrame 毎のアップデート処理
66 | */
67 | public update(_dt: number): void {
68 | // NOOP
69 | }
70 |
71 | /**
72 | * 接敵しているかどうかを返す
73 | */
74 | public isFoeContact(target: PIXI.Container): boolean {
75 | const r1x1 = this.sprite.position.x;
76 | const r1x2 = this.sprite.position.x + this.sprite.width;
77 | const r2x1 = target.position.x;
78 | const r2x2 = target.position.x + target.width;
79 |
80 | return (r1x1 < r2x2 && r1x2 > r2x1);
81 | }
82 |
83 | /**
84 | * アニメーション時間をリセットする
85 | */
86 | public resetAnimation(): void {
87 | // NOOP
88 | }
89 |
90 | /**
91 | * アニメーションを更新する
92 | */
93 | public updateAnimation(): void {
94 | // NOOP
95 | }
96 |
97 | /**
98 | * このオブジェクトと子要素を破棄する
99 | */
100 | public destroy(): void {
101 | this.sprite.destroy();
102 | this.destroyed = true;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/www/assets/ui_graph/title_scene.json:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": [
3 | {
4 | "id": "bg_3_1",
5 | "type": "sprite",
6 | "position": [0, 0],
7 | "params": {
8 | "textureName": "battle/bg_3_1.png",
9 | "url": "battle/bg_3_1.png"
10 | }
11 | },
12 | {
13 | "id": "bg_3_2",
14 | "type": "sprite",
15 | "position": [600, 0],
16 | "params": {
17 | "textureName": "battle/bg_3_2.png",
18 | "url": "battle/bg_3_2.png"
19 | }
20 | },
21 | {
22 | "id": "bg_3_3",
23 | "type": "sprite",
24 | "position": [1200, 0],
25 | "params": {
26 | "textureName": "battle/bg_3_3.png",
27 | "url": "battle/bg_3_3.png"
28 | }
29 | },
30 | {
31 | "id": "bg_2_1",
32 | "type": "sprite",
33 | "position": [0, 0],
34 | "params": {
35 | "textureName": "battle/bg_2_1.png",
36 | "url": "battle/bg_2_1.png"
37 | }
38 | },
39 | {
40 | "id": "bg_2_2",
41 | "type": "sprite",
42 | "position": [600, 0],
43 | "params": {
44 | "textureName": "battle/bg_2_2.png",
45 | "url": "battle/bg_2_2.png"
46 | }
47 | },
48 | {
49 | "id": "bg_2_3",
50 | "type": "sprite",
51 | "position": [1200, 0],
52 | "params": {
53 | "textureName": "battle/bg_2_3.png",
54 | "url": "battle/bg_2_3.png"
55 | }
56 | },
57 | {
58 | "id": "bg_1_5",
59 | "type": "sprite",
60 | "position": [0, 0],
61 | "params": {
62 | "textureName": "battle/bg_1_5.png",
63 | "url": "battle/bg_1_5.png"
64 | }
65 | },
66 | {
67 | "id": "bg_1_6",
68 | "type": "sprite",
69 | "position": [600, 0],
70 | "params": {
71 | "textureName": "battle/bg_1_6.png",
72 | "url": "battle/bg_1_6.png"
73 | }
74 | },
75 | {
76 | "id": "bg_1_7",
77 | "type": "sprite",
78 | "position": [1200, 0],
79 | "params": {
80 | "textureName": "battle/bg_1_7.png",
81 | "url": "battle/bg_1_7.png"
82 | }
83 | },
84 | {
85 | "id": "touch_to_start",
86 | "type": "text",
87 | "position": [568, 320],
88 | "params": {
89 | "family": "MisakiGothic",
90 | "text": "TOUCH TO START",
91 | "size": 48,
92 | "color": "0xffffff",
93 | "anchor": [0.5, 0.5],
94 | "padding": 16
95 | }
96 | }
97 | ],
98 | "metadata": {
99 | "screen": {
100 | "width": 640,
101 | "height": 1136
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/display/battle/single_shot/CollapseExplodeEffect.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Resource from 'Resource';
3 | import SoundManager from 'managers/SoundManager';
4 | import UpdateObject from 'interfaces/UpdateObject';
5 |
6 | /**
7 | * 破壊時の爆発を表現するエフェクト
8 | */
9 | export default class CollapseExplodeEffect
10 | extends PIXI.Container
11 | implements UpdateObject {
12 | /**
13 | * スプライトアニメーションを更新する頻度
14 | */
15 | public static readonly TextureFrameUpdateFrequency: number = 4;
16 |
17 | /**
18 | * 経過フレーム数
19 | */
20 | private elapsedFrameCount: number = 0;
21 | /**
22 | * 表示する PIXI.Sprite インスタンス
23 | */
24 | private sprite!: PIXI.Sprite;
25 |
26 | /**
27 | * このエフェクトで使用するリソースリスト
28 | */
29 | public static get resourceList(): string[] {
30 | return [
31 | Resource.Static.CollapseExplode,
32 | Resource.Audio.Se.Bomb
33 | ];
34 | }
35 |
36 | /**
37 | * コンストラクタ
38 | */
39 | constructor() {
40 | super();
41 |
42 | this.sprite = new PIXI.Sprite(Resource.TextureFrame.CollapseExplode(1));
43 | this.sprite.anchor.set(0.5, 0.5);
44 | this.addChild(this.sprite);
45 | }
46 |
47 | /**
48 | * UpdateObject インターフェース実装
49 | * 削除フラグが立っているか返す
50 | */
51 | public isDestroyed(): boolean {
52 | return this._destroyed;
53 | }
54 |
55 | /**
56 | * UpdateObject インターフェース実装
57 | * requestAnimationFrame 毎のアップデート処理
58 | */
59 | public update(_delta: number): void {
60 | if (this.isDestroyed()) {
61 | return;
62 | }
63 |
64 | this.elapsedFrameCount++;
65 |
66 | // 半透明を表現
67 | this.sprite.visible = (this.elapsedFrameCount % 2 === 0);
68 |
69 | // 最初のフレームで効果音を再生する
70 | if (this.elapsedFrameCount === 1) {
71 | this.playSe();
72 | }
73 |
74 | const frequency = CollapseExplodeEffect.TextureFrameUpdateFrequency;
75 |
76 | // テクスチャ更新周期になったら次のテクスチャに切り替える
77 | if (this.elapsedFrameCount % frequency === 0) {
78 | const count = this.elapsedFrameCount / frequency;
79 | const index = Math.floor(count) + 1;
80 | // すべてのテクスチャが再生されたら自然消滅させる
81 | if (index > Resource.MaxFrameIndex(Resource.Static.CollapseExplode)) {
82 | this.sprite.destroy();
83 | this.destroy();
84 | return;
85 | }
86 |
87 | this.sprite.texture = Resource.TextureFrame.CollapseExplode(index);
88 | }
89 | }
90 |
91 | /**
92 | * 効果音を再生する
93 | */
94 | private playSe(): void {
95 | const sound = SoundManager.getSound(Resource.Audio.Se.Bomb);
96 | if (sound) {
97 | sound.play();
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/lib-ts/Resource.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Scene from 'scenes/Scene';
3 | /**
4 | * リソースの URL や命名規則のマスタ
5 | */
6 | declare const Resource: Readonly<{
7 | /**
8 | * マスターデータ API 情報を有するオブジェクト
9 | */
10 | Api: {
11 | UserBattle: (userId: number) => string;
12 | SceneUiGraph: (scene: Scene) => string;
13 | Stage: (stageId: number) => string;
14 | Unit: (unitIds: number[]) => string;
15 | AllUnit: () => string;
16 | UnitAnimation: (unitIds: number[]) => string;
17 | Castle: (castleIds: number[]) => string;
18 | };
19 | /**
20 | * 渡されたパラメータによって動的に変わる url を有するオブジェクト
21 | */
22 | Dynamic: {
23 | Unit: (unitId: number) => string;
24 | UnitPanel: (unitId: number) => string;
25 | Castle: (castleId: number) => string;
26 | };
27 | /**
28 | * 静的なリソースを有するオブジェクト
29 | */
30 | Static: {
31 | BattleBgFores: string[];
32 | BattleBgMiddles: string[];
33 | BattleBgBacks: string[];
34 | AttackSmoke: string;
35 | DeadBucket: string;
36 | DeadSpirit: string;
37 | CollapseExplode: string;
38 | BattleResultWin: string;
39 | BattleResultLose: string;
40 | };
41 | /**
42 | * サウンドリソースの静的な url を有するオブジェクト
43 | */
44 | Audio: {
45 | Bgm: {
46 | Title: string;
47 | Battle: string;
48 | };
49 | Se: {
50 | Attack1: string;
51 | Attack2: string;
52 | Bomb: string;
53 | UnitSpawn: string;
54 | Win: string;
55 | Lose: string;
56 | };
57 | };
58 | /**
59 | * テクスチャのフレーム名を返す関数を有するオブジェクト
60 | */
61 | TextureFrame: {
62 | Unit: (unitActionType: string, unitId: number, index: number) => PIXI.Texture;
63 | Castle: (castleId: number, index?: number) => PIXI.Texture;
64 | CollapseExplode: (index?: number) => PIXI.Texture;
65 | AttackSmoke: (index?: number) => PIXI.Texture;
66 | };
67 | /**
68 | * アニメーション種別の識別子を有するオブジェクト
69 | */
70 | AnimationTypes: {
71 | Unit: Readonly<{
72 | WAIT: string;
73 | WALK: string;
74 | ATTACK: string;
75 | DAMAGE: string;
76 | }>;
77 | Castle: Readonly<{
78 | IDLE: string;
79 | SPAWN: string;
80 | COLLAPSE: string;
81 | }>;
82 | };
83 | FontFamily: {
84 | Css: string;
85 | Default: string;
86 | };
87 | /**
88 | * スプライトシートの最大フレーム数を返す関数
89 | */
90 | MaxFrameIndex: (resourceKey: string) => number;
91 | }>;
92 | export default Resource;
93 |
--------------------------------------------------------------------------------
/lib-ts/scenes/OrderScene.d.ts:
--------------------------------------------------------------------------------
1 | import LoaderAddParam from 'interfaces/PixiTypePolyfill/LoaderAddParam';
2 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
3 | import Scene from 'scenes/Scene';
4 | /**
5 | * 編成シーン
6 | */
7 | export default class OrderScene extends Scene {
8 | /**
9 | * ユーザのバトル情報
10 | */
11 | private userBattle;
12 | /**
13 | * ユニットマスターのキャッシュ
14 | */
15 | private unitMasterCache;
16 | /**
17 | * ユニットIDと紐つけたユニットパネル用のテクスチャマップ
18 | */
19 | private unitButtonTexturesCache;
20 | /**
21 | * ユニット枠IDと紐つけたユニットパネル用のマップ
22 | */
23 | private unitButtons;
24 | /**
25 | * 選択中のステージID
26 | */
27 | private currentStageId;
28 | /**
29 | * 前回編成したユニットID配列
30 | */
31 | private lastUnitIds;
32 | /**
33 | * コンストラクタ
34 | */
35 | constructor();
36 | /**
37 | * リソースリストを作成し返却する
38 | */
39 | protected createInitialResourceList(): (LoaderAddParam | string)[];
40 | /**
41 | * リソースをロードする
42 | * 基本実装をオーバーライドし、 indexed db のレコードを取得する
43 | */
44 | beginLoadResource(onLoaded: () => void): Promise;
45 | /**
46 | * リソースがロードされた時のコールバック
47 | */
48 | protected onInitialResourceLoaded(): (LoaderAddParam | string)[];
49 | /**
50 | * 追加リソースダウンロード完了時コールバック
51 | */
52 | protected onResourceLoaded(): void;
53 | /**
54 | * ユニットの切り替えボタンが押下された時のコールバック
55 | */
56 | onUnitArrowTapped(slotIndex: number, addValue: number): void;
57 | /**
58 | * ステージの切り替えボタンが押下された時のコールバック
59 | */
60 | onStageArrowTapped(addValue: number): void;
61 | /**
62 | * OK ボタンが押下されたされたときのコールバック
63 | */
64 | onOkButtonDown(): void;
65 | /**
66 | * OK ボタン押下が離されたされたときのコールバック
67 | */
68 | onOkButtonUp(): void;
69 | /**
70 | * 独自 UiGraph 要素のファクトリを返す
71 | * OrderScene は BattleScene と UnitButton を共用している
72 | */
73 | protected getCustomUiGraphFactory(type: string): UiNodeFactory | null;
74 | /**
75 | * 可能であればバトル画面に遷移する
76 | */
77 | private startBattleIfPossible;
78 | /**
79 | * UnitButton を初期化する
80 | */
81 | private initUnitButtons;
82 | /**
83 | * 選択されているステージ ID を更新する
84 | */
85 | private updateCurrentStageId;
86 | /**
87 | * バトル用のパラメータを作成する
88 | */
89 | private createBattleParameter;
90 | /**
91 | * 必要であれば BGM を再生する
92 | */
93 | private playBgmIfNeeded;
94 | /**
95 | * DB へユニットID配列を保存する
96 | */
97 | private saveUnitIdsToDB;
98 | /**
99 | * DB からユニットID配列を取得する
100 | */
101 | private loadUnitIdsFromDB;
102 | /**
103 | * DB へステージIDを保存する
104 | */
105 | private saveStageIdToDB;
106 | /**
107 | * DB からステージIDを取得する
108 | */
109 | private loadStageIdFromDB;
110 | /**
111 | * BGM をフェードアウトする
112 | */
113 | private fadeOutBgm;
114 | }
115 |
--------------------------------------------------------------------------------
/src/display/battle/single_shot/Dead.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Resource from 'Resource';
3 | import UpdateObject from 'interfaces/UpdateObject';
4 |
5 | const TO_RAD = Math.PI / 180.0;
6 |
7 | /**
8 | * 死亡を表現するエフェクト
9 | */
10 | export default class Dead extends PIXI.Container implements UpdateObject {
11 | /**
12 | * 経過フレーム数
13 | */
14 | private elapsedFrameCount: number = 0;
15 |
16 | private bucket!: PIXI.Sprite;
17 | private spirit!: PIXI.Sprite;
18 |
19 | /**
20 | * このエフェクトで使用するリソースリスト
21 | */
22 | public static get resourceList(): string[] {
23 | return [
24 | Resource.Static.DeadBucket,
25 | Resource.Static.DeadSpirit
26 | ];
27 | }
28 |
29 | /**
30 | * コンストラクタ
31 | */
32 | constructor(flip: boolean) {
33 | super();
34 |
35 | const textureCache = PIXI.utils.TextureCache;
36 | const bucketTexture = textureCache[Resource.Static.DeadBucket];
37 | const spiritTexture = textureCache[Resource.Static.DeadSpirit];
38 |
39 | this.bucket = new PIXI.Sprite(bucketTexture);
40 | this.spirit = new PIXI.Sprite(spiritTexture);
41 |
42 | this.bucket.anchor.y = 0.0;
43 | this.spirit.position.y = -this.bucket.height;
44 |
45 | if (flip) {
46 | this.bucket.scale.x = -1;
47 | this.spirit.scale.x = -1;
48 | this.spirit.position.x = -((this.bucket.width - this.spirit.width) * 0.5);
49 | } else {
50 | this.spirit.position.x = (this.bucket.width - this.spirit.width) * 0.5;
51 | }
52 |
53 | this.addChild(this.bucket);
54 | this.addChild(this.spirit);
55 |
56 | this.spirit.visible = false;
57 | }
58 |
59 | /**
60 | * UpdateObject インターフェース実装
61 | * 削除フラグが立っているか返す
62 | */
63 | public isDestroyed(): boolean {
64 | return this._destroyed;
65 | }
66 |
67 | /**
68 | * UpdateObject インターフェース実装
69 | * requestAnimationFrame 毎のアップデート処理
70 | */
71 | public update(_delta: number): void {
72 | if (this.isDestroyed()) {
73 | return;
74 | }
75 |
76 | this.elapsedFrameCount++;
77 |
78 | // 本来はアニメーションを扱うミドルウェアで行う部分
79 | switch (this.elapsedFrameCount) {
80 | case 4: this.bucket.rotation = 25.0 * TO_RAD; break;
81 | case 8: this.bucket.rotation = -25.0 * TO_RAD; break;
82 | case 12: this.bucket.rotation = 15.0 * TO_RAD; break;
83 | case 16: this.bucket.rotation = -15.0 * TO_RAD; break;
84 | case 20: this.bucket.rotation = 5.0 * TO_RAD; break;
85 | case 24: this.bucket.rotation = -5.0 * TO_RAD; break;
86 | case 26: {
87 | this.bucket.rotation = 0.0;
88 | this.spirit.visible = true;
89 | break;
90 | }
91 | case 80: {
92 | // 規定フレーム数再生したら自然消滅させる
93 | this.bucket.destroy();
94 | this.spirit.destroy();
95 | this.destroy();
96 | break;
97 | }
98 | default: {
99 | if (this.elapsedFrameCount > 26) {
100 | this.spirit.visible = (this.elapsedFrameCount % 2 === 0);
101 | this.spirit.y = this.spirit.y - 3;
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/scenes/transition/Fade.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Transition from 'interfaces/Transition';
3 | import GameManager from 'managers/GameManager';
4 |
5 | /**
6 | * トランジションのフェード表現
7 | */
8 | export default class Fade implements Transition {
9 | /**
10 | * フェード開始時の黒画面アルファ
11 | */
12 | private alphaFrom!: number;
13 | /**
14 | * フェード終了時の黒画面アルファ
15 | */
16 | private alphaTo!: number;
17 | /**
18 | * 1フレーム毎の黒画面アルファ加算値
19 | */
20 | private alphaProgress: number;
21 | /**
22 | * 黒画面のコンテナ
23 | */
24 | private container = new PIXI.Container();
25 | /**
26 | * 黒画面の描画
27 | */
28 | private overlay = new PIXI.Graphics();
29 |
30 | /**
31 | * トランジション開始フラグ
32 | */
33 | private transitionBegan: boolean = false;
34 | /**
35 | * トランジション終了フラグ
36 | */
37 | private transitionFinished: boolean = false;
38 | /**
39 | * トランジション終了時コールバック
40 | */
41 | private onTransitionFinished: () => void = () => {};
42 |
43 | /**
44 | * コンストラクタ
45 | */
46 | constructor(alphaFrom: number, alphaTo: number, alphaProgress: number) {
47 | this.alphaFrom = alphaFrom;
48 | this.alphaTo = alphaTo;
49 | this.alphaProgress = alphaProgress;
50 |
51 | const width = GameManager.instance.game.view.width;
52 | const height = GameManager.instance.game.view.height;
53 |
54 | // フェード用の黒い画面
55 | this.overlay.beginFill(0x000000);
56 | this.overlay.moveTo(0, 0);
57 | this.overlay.lineTo(width, 0);
58 | this.overlay.lineTo(width, height);
59 | this.overlay.lineTo(0, height);
60 | this.overlay.endFill();
61 |
62 | this.overlay.alpha = this.alphaFrom;
63 |
64 | this.container.addChild(this.overlay);
65 | }
66 |
67 | /**
68 | * トランジション描画物を含む PIXI.Container インスタンスを返す
69 | */
70 | public getContainer(): PIXI.Container | null {
71 | return this.container;
72 | }
73 |
74 | /**
75 | * トランジション開始処理
76 | */
77 | public begin(): void {
78 | this.transitionBegan = true;
79 | }
80 | /**
81 | * トランジションが開始しているかどうかを返す
82 | */
83 | public isBegan(): boolean {
84 | return this.transitionBegan;
85 | }
86 | /**
87 | * トランジションが終了しているかどうかを返す
88 | */
89 | public isFinished(): boolean {
90 | return this.transitionFinished;
91 | }
92 | /**
93 | * トランジションが実行中かどうかを返す
94 | */
95 | public isActive(): boolean {
96 | return this.isBegan() && !this.isFinished();
97 | }
98 |
99 | /**
100 | * トランジションを更新する
101 | */
102 | public update(_dt: number): void {
103 | if (!this.isBegan()) {
104 | return;
105 | }
106 | if (this.isFinished()) {
107 | return;
108 | }
109 | if (
110 | (this.alphaTo <= this.alphaFrom && this.overlay.alpha <= this.alphaTo) ||
111 | (this.alphaTo >= this.alphaFrom && this.overlay.alpha >= this.alphaTo)
112 | ) {
113 | this.onTransitionFinished();
114 | this.transitionFinished = true;
115 | } else {
116 | this.overlay.alpha += this.alphaProgress;
117 | }
118 | }
119 |
120 | /**
121 | * トランジション終了時のコールバックを登録する
122 | */
123 | public setCallback(callback: () => void): void {
124 | this.onTransitionFinished = callback;
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/display/battle/single_shot/HealthGauge.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import UpdateObject from 'interfaces/UpdateObject';
3 |
4 | /**
5 | * health 増減を表現するエフェクト
6 | */
7 | export default class HealthGaugeEffect
8 | extends PIXI.Container
9 | implements UpdateObject {
10 | /**
11 | * ゲージの幅
12 | */
13 | public gaugeWidth: number = 60;
14 | /**
15 | * ゲージの高さ
16 | */
17 | public gaugeHeight: number = 8;
18 |
19 | /**
20 | * 最大 health の色
21 | */
22 | public maxColor: number = 0xFF4444;
23 | /**
24 | * 現在の health の色
25 | */
26 | public currentColor: number = 0xFFFF44;
27 | /**
28 | * 枠線の色
29 | */
30 | public lineColor: number = 0x222222;
31 |
32 | /**
33 | * 経過フレーム数
34 | */
35 | private elapsedFrameCount: number = 0;
36 | /**
37 | * 減少アニメーションのフレーム数
38 | */
39 | private reducingFrameCount: number = 4;
40 | /**
41 | * 表示するフレーム数
42 | */
43 | private activeFrameCount: number = 24;
44 |
45 | /**
46 | * 最大 health 用の PIXI.Graphics
47 | */
48 | private maxGraphic!: PIXI.Graphics;
49 | /**
50 | * 現在の health 用の PIXI.Graphics
51 | */
52 | private currentGraphic!: PIXI.Graphics;
53 |
54 | /**
55 | * 減算元のゲージ比率
56 | */
57 | private fromPercent!: number;
58 | /**
59 | * 減算後のゲージ比率
60 | */
61 | private toPercent!: number;
62 |
63 | /**
64 | * このエフェクトで使用するリソースリスト
65 | */
66 | public static get resourceList(): string[] {
67 | return [];
68 | }
69 |
70 | /**
71 | * コンストラクタ
72 | */
73 | constructor(fromPercent: number, toPercent: number) {
74 | super();
75 |
76 | this.fromPercent = fromPercent;
77 | this.toPercent = toPercent;
78 |
79 | this.maxGraphic = new PIXI.Graphics();
80 | this.maxGraphic.lineStyle(2, this.lineColor, 1);
81 | this.maxGraphic.beginFill(this.maxColor, 1);
82 | this.maxGraphic.drawRect(0, 0, this.gaugeWidth, this.gaugeHeight);
83 |
84 | this.currentGraphic = new PIXI.Graphics();
85 | this.currentGraphic.beginFill(this.currentColor, 1);
86 | this.currentGraphic.drawRect(0, 0, 0, 22);
87 |
88 | this.addChild(this.maxGraphic);
89 | this.addChild(this.currentGraphic);
90 | }
91 |
92 | /**
93 | * UpdateObject インターフェース実装
94 | * 削除フラグが立っているか返す
95 | */
96 | public isDestroyed(): boolean {
97 | return this._destroyed;
98 | }
99 |
100 | /**
101 | * UpdateObject インターフェース実装
102 | * requestAnimationFrame 毎のアップデート処理
103 | */
104 | public update(_delta: number): void {
105 | if (this.isDestroyed()) {
106 | return;
107 | }
108 |
109 | this.elapsedFrameCount++;
110 |
111 | if (this.elapsedFrameCount <= this.reducingFrameCount) {
112 | // ゲージ増減アニメーション
113 | const reduceDistance = this.fromPercent - this.toPercent;
114 | const reduceProgress = this.elapsedFrameCount / this.reducingFrameCount;
115 | const currentPercent = this.fromPercent - reduceDistance * reduceProgress;
116 |
117 | const width = this.gaugeWidth * currentPercent;
118 |
119 | this.currentGraphic.clear();
120 | this.currentGraphic.beginFill(this.currentColor, 1);
121 | this.currentGraphic.drawRect(0, 0, width, this.gaugeHeight);
122 | } else if (this.elapsedFrameCount > this.activeFrameCount) {
123 | // 規定フレーム数再生したら自然消滅させる
124 | this.maxGraphic.destroy();
125 | this.currentGraphic.destroy();
126 | this.destroy();
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/lib-ts/managers/SoundManager.d.ts:
--------------------------------------------------------------------------------
1 | import { BrowserInfo, BotInfo, NodeInfo } from 'detect-browser';
2 | import Sound from 'modules/Sound';
3 | /**
4 | * サウンドを扱う
5 | * Sound の高級機能
6 | */
7 | export default class SoundManager {
8 | /**
9 | * シングルトンインスタンス
10 | */
11 | static instance: SoundManager;
12 | /**
13 | * AudioCntext インスタンスのゲッタ
14 | * ブラウザによっては生成数に上限があるため、SoundManager では単一のインスタンスのみ生成する
15 | */
16 | static readonly sharedContext: AudioContext | null;
17 | /**
18 | * AudioCntext インスタンス
19 | */
20 | private static context;
21 | /**
22 | * WebAudio 利用の初期化済みフラグ
23 | */
24 | private static webAudioInitialized;
25 | /**
26 | * SoundManager がサポートするサウンドファイル拡張子
27 | */
28 | private static readonly supportedExtensions;
29 | /**
30 | * 一時停止中かどうかのフラグ
31 | */
32 | private paused;
33 | /**
34 | * フェード処理後に削除する Sound インスタンスのリスト
35 | */
36 | private killingSounds;
37 | /**
38 | * SoundManager で監理している Sound インスタンスの Map
39 | */
40 | private managedSounds;
41 | /**
42 | * コンストラクタ
43 | */
44 | constructor();
45 | /**
46 | * 初期化処理
47 | * ユーザで生成した AudioContext を渡すこともできる
48 | */
49 | static init(ctx?: AudioContext): void;
50 | /**
51 | * 毎フレームの更新処理
52 | */
53 | static update(_delta: number): void;
54 | /**
55 | * オーディオデータをパースするための PIXI.Loader ミドルウェアを登録する
56 | */
57 | static useWebAudio(browser: BrowserInfo | BotInfo | NodeInfo): void;
58 | /**
59 | * オーディオデータのデコード処理
60 | */
61 | static decodeAudio(binary: any, callback: (buf: AudioBuffer) => void): void;
62 | /**
63 | * オーディオデータのデコード処理
64 | * ブラウザ種別やバージョンによっては I/F が異なるため、こちらを使う必要がある
65 | */
66 | static decodeAudioWithPromise(binary: any, callback: (buf: AudioBuffer) => void): void;
67 | /**
68 | * サウンドを初期化するためのイベントを登録する
69 | * 多くのブラウザではタップ等のユーザ操作を行わないとサウンドを再生できない
70 | * そのため、初回画面タップ時にダミーの音声を再生させて以降のサウンド再生処理を許容できるようにする
71 | */
72 | static setSoundInitializeEvent(browser: BrowserInfo | BotInfo | NodeInfo): void;
73 | /**
74 | * HTML window のライフサイクルイベントを登録する
75 | * ブラウザのタブ切り替えや非アクティヴ時に音声が鳴ってしまわないようにする
76 | */
77 | static setWindowLifeCycleEvent(browser: BrowserInfo | BotInfo | NodeInfo): void;
78 | /**
79 | * 渡された Sound インスタンスを渡された名前に紐つけて SoundManager 管理下にする
80 | */
81 | static registerSound(name: string, sound: Sound): void;
82 | /**
83 | * 渡された名前に紐ついている Sound インスタンスを SoundManager 管理下からはずす
84 | */
85 | static unregisterSound(name: string): void;
86 | /**
87 | * Sound インスタンスを SoundManager 管理下として生成し返却する
88 | */
89 | static createSound(name: string, buf: AudioBuffer): Sound;
90 | /**
91 | * 渡された名前に紐付く SoundManager 管理下の Sound インスタンスを返す
92 | */
93 | static getSound(name: string): Sound | undefined;
94 | /**
95 | * 渡された名前に紐付く SoundManager 管理下の Sound インスタンスの存在有無を返す
96 | */
97 | static hasSound(name: string): boolean;
98 | /**
99 | * 渡された名前に紐付く SoundManager 管理下の Sound インスタンスを破棄する
100 | */
101 | static destroySound(name: string): void;
102 | /**
103 | * 管理下の Sound インスタンスをすべて一時停止する
104 | */
105 | static pause(): void;
106 | /**
107 | * 管理下の Sound インスタンスの再生をすべて再開する
108 | */
109 | static resume(): void;
110 | /**
111 | * フェード処理を行う
112 | */
113 | static fade(sound: Sound, targetVolume: number, seconds: number, stopOnEnd?: boolean): void;
114 | }
115 |
--------------------------------------------------------------------------------
/lib-ts/scenes/Scene.d.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import LoaderAddParam from 'interfaces/PixiTypePolyfill/LoaderAddParam';
3 | import * as UI from 'interfaces/UiGraph/index';
4 | import Transition from 'interfaces/Transition';
5 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
6 | import UpdateObject from 'interfaces/UpdateObject';
7 | /**
8 | * ゲームシーンの抽象クラス
9 | * UiGraph を利用して UI 情報を透過的に読み込み初期化する
10 | * また、シーン間のトランジションイベントを提供する
11 | * いずれのイベントも実装クラスにて独自処理の実装を行うことができる
12 | */
13 | export default abstract class Scene extends PIXI.Container {
14 | /**
15 | * 経過フレーム数
16 | */
17 | protected elapsedFrameCount: number;
18 | /**
19 | * UiGraph を利用して読み込む UI があるかどうか
20 | */
21 | protected hasSceneUiGraph: boolean;
22 | /**
23 | * UiGraph でロードされた UI データ
24 | */
25 | protected uiGraph: {
26 | [key: string]: PIXI.Container;
27 | };
28 | /**
29 | * UiGraph でロードされた UI データを配置するための PIXI.Container
30 | * 描画順による前後関係を統制するために一つの Container にまとめる
31 | */
32 | protected uiGraphContainer: PIXI.Container;
33 | /**
34 | * 更新すべきオブジェクトを保持する
35 | */
36 | protected objectsToUpdate: UpdateObject[];
37 | /**
38 | * シーン開始用のトランジションオブジェクト
39 | */
40 | protected transitionIn: Transition;
41 | /**
42 | * シーン終了用のトランジションオブジェクト
43 | */
44 | protected transitionOut: Transition;
45 | /**
46 | * GameManager によって requestAnimationFrame 毎に呼び出されるメソッド
47 | */
48 | update(delta: number): void;
49 | /**
50 | * 更新処理を行うべきオブジェクトとして渡されたオブジェクトを登録する
51 | */
52 | protected registerUpdatingObject(object: UpdateObject): void;
53 | /**
54 | * 更新処理を行うべきオブジェクトを更新する
55 | */
56 | protected updateRegisteredObjects(delta: number): void;
57 | /**
58 | * シーン追加トランジション開始
59 | * 引数でトランジション終了時のコールバックを指定できる
60 | */
61 | beginTransitionIn(onTransitionFinished: (scene: Scene) => void): void;
62 | /**
63 | * シーン削除トランジション開始
64 | * 引数でトランジション終了時のコールバックを指定できる
65 | */
66 | beginTransitionOut(onTransitionFinished: (scene: Scene) => void): void;
67 | /**
68 | * loadInitialResource に用いるリソースリストを作成するメソッド
69 | * デフォルトでは UiGraph のリソースリストを作成する
70 | */
71 | protected createInitialResourceList(): (LoaderAddParam | string)[];
72 | /**
73 | * リソースダウンロードのフローを実行する
74 | * デフォルトでは UiGraph 用の情報が取得される
75 | */
76 | beginLoadResource(onLoaded: () => void): Promise;
77 | /**
78 | * リソースダウンロードのフローを実行する
79 | * UiGraph 情報も含まれる
80 | */
81 | protected loadInitialResource(onLoaded: () => void): void;
82 | /**
83 | * loadInitialResource 完了時のコールバックメソッド
84 | */
85 | protected onInitialResourceLoaded(): (LoaderAddParam | string)[];
86 | /**
87 | * 初回リソースロードで発生した追加のリソースをロードする
88 | */
89 | protected loadAdditionalResource(assets: (LoaderAddParam | string)[], onLoaded: () => void): void;
90 | /**
91 | * 追加のリソースロード完了時のコールバック
92 | */
93 | protected onAdditionalResourceLoaded(onLoaded: () => void): void;
94 | /**
95 | * beginLoadResource 完了時のコールバックメソッド
96 | */
97 | protected onResourceLoaded(): void;
98 | /**
99 | * UiGraph 用の PIXI.Container インスタンスに UiGraph 要素をロードする
100 | */
101 | protected prepareUiGraphContainer(uiData: UI.Graph): void;
102 | /**
103 | * UiGraph にシーン独自の要素を追加する場合にこのメソッドを利用する
104 | */
105 | protected getCustomUiGraphFactory(_type: string): UiNodeFactory | null;
106 | /**
107 | * 渡されたアセットのリストからロード済みのものをフィルタリングする
108 | */
109 | private filterLoadedAssets;
110 | /**
111 | * BGM をループ再生する
112 | */
113 | protected playBgm(soundName: string): void;
114 | /**
115 | * BGM 再生を止める
116 | */
117 | protected stopBgm(soundName: string): void;
118 | /**
119 | * 効果音を再生する
120 | */
121 | protected playSe(soundName: string): void;
122 | }
123 |
--------------------------------------------------------------------------------
/www/assets/units/2.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "unit_2_attack_1.png":
4 | {
5 | "frame": {"x":1,"y":747,"w":108,"h":184},
6 | "rotated": true,
7 | "trimmed": false,
8 | "spriteSourceSize": {"x":0,"y":0,"w":108,"h":184},
9 | "sourceSize": {"w":108,"h":184}
10 | },
11 | "unit_2_attack_2.png":
12 | {
13 | "frame": {"x":1,"y":640,"w":105,"h":184},
14 | "rotated": true,
15 | "trimmed": true,
16 | "spriteSourceSize": {"x":0,"y":0,"w":105,"h":184},
17 | "sourceSize": {"w":108,"h":184}
18 | },
19 | "unit_2_attack_3.png":
20 | {
21 | "frame": {"x":1,"y":747,"w":108,"h":184},
22 | "rotated": true,
23 | "trimmed": false,
24 | "spriteSourceSize": {"x":0,"y":0,"w":108,"h":184},
25 | "sourceSize": {"w":108,"h":184}
26 | },
27 | "unit_2_attack_4.png":
28 | {
29 | "frame": {"x":1,"y":640,"w":105,"h":184},
30 | "rotated": true,
31 | "trimmed": true,
32 | "spriteSourceSize": {"x":0,"y":0,"w":105,"h":184},
33 | "sourceSize": {"w":108,"h":184}
34 | },
35 | "unit_2_attack_5.png":
36 | {
37 | "frame": {"x":1,"y":747,"w":108,"h":184},
38 | "rotated": true,
39 | "trimmed": false,
40 | "spriteSourceSize": {"x":0,"y":0,"w":108,"h":184},
41 | "sourceSize": {"w":108,"h":184}
42 | },
43 | "unit_2_attack_6.png":
44 | {
45 | "frame": {"x":1,"y":640,"w":105,"h":184},
46 | "rotated": true,
47 | "trimmed": true,
48 | "spriteSourceSize": {"x":0,"y":0,"w":105,"h":184},
49 | "sourceSize": {"w":108,"h":184}
50 | },
51 | "unit_2_damage_1.png":
52 | {
53 | "frame": {"x":1,"y":550,"w":88,"h":184},
54 | "rotated": true,
55 | "trimmed": false,
56 | "spriteSourceSize": {"x":0,"y":0,"w":88,"h":184},
57 | "sourceSize": {"w":88,"h":184}
58 | },
59 | "unit_2_wait_1.png":
60 | {
61 | "frame": {"x":1,"y":316,"w":76,"h":184},
62 | "rotated": true,
63 | "trimmed": false,
64 | "spriteSourceSize": {"x":0,"y":0,"w":76,"h":184},
65 | "sourceSize": {"w":76,"h":184}
66 | },
67 | "unit_2_wait_2.png":
68 | {
69 | "frame": {"x":1,"y":394,"w":76,"h":181},
70 | "rotated": true,
71 | "trimmed": true,
72 | "spriteSourceSize": {"x":0,"y":3,"w":76,"h":181},
73 | "sourceSize": {"w":76,"h":184}
74 | },
75 | "unit_2_walk_1.png":
76 | {
77 | "frame": {"x":1,"y":472,"w":76,"h":185},
78 | "rotated": true,
79 | "trimmed": true,
80 | "spriteSourceSize": {"x":0,"y":15,"w":76,"h":185},
81 | "sourceSize": {"w":76,"h":200}
82 | },
83 | "unit_2_walk_2.png":
84 | {
85 | "frame": {"x":1,"y":245,"w":69,"h":193},
86 | "rotated": true,
87 | "trimmed": true,
88 | "spriteSourceSize": {"x":0,"y":7,"w":69,"h":193},
89 | "sourceSize": {"w":76,"h":200}
90 | },
91 | "unit_2_walk_3.png":
92 | {
93 | "frame": {"x":1,"y":53,"w":54,"h":193},
94 | "rotated": true,
95 | "trimmed": true,
96 | "spriteSourceSize": {"x":19,"y":7,"w":54,"h":193},
97 | "sourceSize": {"w":76,"h":200}
98 | },
99 | "unit_2_walk_4.png":
100 | {
101 | "frame": {"x":1,"y":109,"w":66,"h":185},
102 | "rotated": true,
103 | "trimmed": true,
104 | "spriteSourceSize": {"x":7,"y":15,"w":66,"h":185},
105 | "sourceSize": {"w":76,"h":200}
106 | },
107 | "unit_2_walk_5.png":
108 | {
109 | "frame": {"x":1,"y":1,"w":50,"h":197},
110 | "rotated": true,
111 | "trimmed": true,
112 | "spriteSourceSize": {"x":11,"y":3,"w":50,"h":197},
113 | "sourceSize": {"w":76,"h":200}
114 | },
115 | "unit_2_walk_6.png":
116 | {
117 | "frame": {"x":1,"y":177,"w":66,"h":200},
118 | "rotated": true,
119 | "trimmed": true,
120 | "spriteSourceSize": {"x":3,"y":0,"w":66,"h":200},
121 | "sourceSize": {"w":76,"h":200}
122 | }},
123 | "animations": {
124 | "unit_2_attack": ["unit_2_attack_1.png","unit_2_attack_2.png","unit_2_attack_3.png","unit_2_attack_4.png","unit_2_attack_5.png","unit_2_attack_6.png"],
125 | "unit_2_wait": ["unit_2_wait_1.png","unit_2_wait_2.png"],
126 | "unit_2_walk": ["unit_2_walk_1.png","unit_2_walk_2.png","unit_2_walk_3.png","unit_2_walk_4.png","unit_2_walk_5.png","unit_2_walk_6.png"]
127 | },
128 | "meta": {
129 | "app": "https://www.codeandweb.com/texturepacker",
130 | "version": "1.0",
131 | "image": "2.png",
132 | "format": "RGBA8888",
133 | "size": {"w":202,"h":856},
134 | "scale": "1",
135 | "smartupdate": "$TexturePacker:SmartUpdate:68a6569c9f89f23ef55b9e4b5b6027cd:f51a3a13551a79f4c475521f4f7b79d2:5ed6fcaeb66fa059fba7886eb3eee15a$"
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/modules/Sound.ts:
--------------------------------------------------------------------------------
1 | import SoundManager from 'managers/SoundManager';
2 |
3 | /**
4 | * サウンド処理を行うクラス
5 | */
6 | export default class Sound {
7 | /**
8 | * ボリュームのセッタ
9 | */
10 | public set volume(value: number) {
11 | if (this.gainNode) {
12 | this.gainNode.gain.value = value;
13 | }
14 | }
15 | /**
16 | * ボリュームのゲッタ
17 | */
18 | public get volume(): number {
19 | return this.gainNode ? this.gainNode.gain.value : -1;
20 | }
21 |
22 | /**
23 | * サウンド再生時間を返す
24 | */
25 | public get elapsedTime(): number {
26 | if (this.paused) {
27 | return this.offset;
28 | }
29 |
30 | const audioContext = SoundManager.sharedContext;
31 | if (!this.source || !audioContext) {
32 | return 0;
33 | }
34 |
35 | const playedTime = audioContext.currentTime - this.playedAt;
36 |
37 | // ループ再生の場合は合計の再生時間から割り出す
38 | if (this.loop) {
39 | const playLength = this.source.loopEnd - this.source.loopStart;
40 | if (playedTime > playLength) {
41 | return this.source.loopStart + (playedTime % playLength);
42 | }
43 | }
44 | return playedTime;
45 | }
46 |
47 | /**
48 | * paused の public ゲッタ
49 | */
50 | public isPaused(): boolean {
51 | return this.paused;
52 | }
53 |
54 | /**
55 | * GainNode インスタンス
56 | */
57 | public gainNode!: GainNode;
58 | /**
59 | * ループ再生フラグ
60 | */
61 | public loop: boolean = false;
62 |
63 | /**
64 | * AudioBuffer インスタンス
65 | */
66 | private buffer!: AudioBuffer;
67 |
68 | /**
69 | * AudioBufferSourceNode インスタンス
70 | */
71 | private source: AudioBufferSourceNode | null = null;
72 |
73 | /**
74 | * 再生開始フラグ
75 | */
76 | private played: boolean = false;
77 | /**
78 | * 一時停止フラグ
79 | */
80 | private paused: boolean = false;
81 | /**
82 | * サウンド再生開始時間オフセット
83 | */
84 | private offset: number = 0;
85 | /**
86 | * AudioContext インスタンスの currentTime を基準に保持する再生開始時間
87 | */
88 | private playedAt: number = 0;
89 |
90 | /**
91 | * コンストラクタ
92 | * AudioBuffer はユーザ側で用意する
93 | */
94 | constructor(buf: AudioBuffer) {
95 | if (!SoundManager.sharedContext) {
96 | return;
97 | }
98 |
99 | this.buffer = buf;
100 | this.gainNode = SoundManager.sharedContext.createGain();
101 | }
102 |
103 | /**
104 | * 再生開始
105 | */
106 | public play(loop: boolean = false, offset: number = 0): void {
107 | const audioContext = SoundManager.sharedContext;
108 | if (!audioContext) {
109 | return;
110 | }
111 |
112 | this.loop = loop;
113 |
114 | // AudioSourceNode の初期化
115 | this.source = audioContext.createBufferSource();
116 | this.source.loop = this.loop;
117 | this.source.loopStart = 0;
118 | this.source.loopEnd = this.buffer.duration as number;
119 | this.source.buffer = this.buffer;
120 | this.source.onended = () => this.stop();
121 |
122 | this.gainNode.connect(audioContext.destination);
123 | this.source.connect(this.gainNode);
124 | this.source.start(0, offset);
125 |
126 | this.playedAt = audioContext.currentTime - offset;
127 |
128 | this.paused = false;
129 | this.played = true;
130 | }
131 | /**
132 | * 停止
133 | */
134 | public stop(): void {
135 | if (!this.source || !this.played) {
136 | return;
137 | }
138 |
139 | this.source.disconnect();
140 |
141 | try {
142 | (this.source as any).buffer = null;
143 | } catch (_e) {
144 | // Chrome 59 以下は null 代入できない
145 | // 後続の処理に問題はないので正常系処理に戻す
146 | }
147 |
148 | this.source.onended = null;
149 | this.source = null;
150 |
151 | this.paused = false;
152 | }
153 | /**
154 | * 一時停止
155 | */
156 | public pause(): void {
157 | if (this.paused || !this.played || !this.source) {
158 | return;
159 | }
160 | this.offset = this.elapsedTime;
161 | this.stop();
162 |
163 | this.paused = true;
164 | }
165 | /**
166 | * 再開
167 | */
168 | public resume(): void {
169 | if (!this.paused || !this.played) {
170 | return;
171 | }
172 | this.play(this.loop, this.offset);
173 |
174 | this.paused = false;
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/www/assets/units/3.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "unit_3_attack_1.png":
4 | {
5 | "frame": {"x":556,"y":1,"w":222,"h":69},
6 | "rotated": false,
7 | "trimmed": true,
8 | "spriteSourceSize": {"x":19,"y":3,"w":222,"h":69},
9 | "sourceSize": {"w":332,"h":72}
10 | },
11 | "unit_3_attack_2.png":
12 | {
13 | "frame": {"x":159,"y":72,"w":222,"h":72},
14 | "rotated": false,
15 | "trimmed": true,
16 | "spriteSourceSize": {"x":15,"y":0,"w":222,"h":72},
17 | "sourceSize": {"w":332,"h":72}
18 | },
19 | "unit_3_attack_3.png":
20 | {
21 | "frame": {"x":780,"y":1,"w":221,"h":69},
22 | "rotated": false,
23 | "trimmed": true,
24 | "spriteSourceSize": {"x":0,"y":3,"w":221,"h":69},
25 | "sourceSize": {"w":332,"h":72}
26 | },
27 | "unit_3_attack_4.png":
28 | {
29 | "frame": {"x":780,"y":1,"w":221,"h":69},
30 | "rotated": false,
31 | "trimmed": true,
32 | "spriteSourceSize": {"x":0,"y":3,"w":221,"h":69},
33 | "sourceSize": {"w":332,"h":72}
34 | },
35 | "unit_3_attack_5.png":
36 | {
37 | "frame": {"x":780,"y":1,"w":221,"h":69},
38 | "rotated": false,
39 | "trimmed": true,
40 | "spriteSourceSize": {"x":0,"y":3,"w":221,"h":69},
41 | "sourceSize": {"w":332,"h":72}
42 | },
43 | "unit_3_attack_6.png":
44 | {
45 | "frame": {"x":296,"y":1,"w":258,"h":69},
46 | "rotated": false,
47 | "trimmed": true,
48 | "spriteSourceSize": {"x":51,"y":3,"w":258,"h":69},
49 | "sourceSize": {"w":332,"h":72}
50 | },
51 | "unit_3_attack_7.png":
52 | {
53 | "frame": {"x":1,"y":1,"w":293,"h":69},
54 | "rotated": false,
55 | "trimmed": true,
56 | "spriteSourceSize": {"x":39,"y":3,"w":293,"h":69},
57 | "sourceSize": {"w":332,"h":72}
58 | },
59 | "unit_3_damage_1.png":
60 | {
61 | "frame": {"x":1,"y":72,"w":156,"h":160},
62 | "rotated": false,
63 | "trimmed": false,
64 | "spriteSourceSize": {"x":0,"y":0,"w":156,"h":160},
65 | "sourceSize": {"w":156,"h":160}
66 | },
67 | "unit_3_wait_1.png":
68 | {
69 | "frame": {"x":827,"y":72,"w":221,"h":69},
70 | "rotated": false,
71 | "trimmed": true,
72 | "spriteSourceSize": {"x":3,"y":3,"w":221,"h":69},
73 | "sourceSize": {"w":224,"h":72}
74 | },
75 | "unit_3_wait_2.png":
76 | {
77 | "frame": {"x":159,"y":146,"w":221,"h":72},
78 | "rotated": false,
79 | "trimmed": true,
80 | "spriteSourceSize": {"x":0,"y":0,"w":221,"h":72},
81 | "sourceSize": {"w":224,"h":72}
82 | },
83 | "unit_3_walk_1.png":
84 | {
85 | "frame": {"x":827,"y":143,"w":220,"h":69},
86 | "rotated": false,
87 | "trimmed": true,
88 | "spriteSourceSize": {"x":0,"y":3,"w":220,"h":69},
89 | "sourceSize": {"w":220,"h":72}
90 | },
91 | "unit_3_walk_2.png":
92 | {
93 | "frame": {"x":383,"y":72,"w":220,"h":72},
94 | "rotated": false,
95 | "trimmed": false,
96 | "spriteSourceSize": {"x":0,"y":0,"w":220,"h":72},
97 | "sourceSize": {"w":220,"h":72}
98 | },
99 | "unit_3_walk_3.png":
100 | {
101 | "frame": {"x":382,"y":146,"w":220,"h":72},
102 | "rotated": false,
103 | "trimmed": false,
104 | "spriteSourceSize": {"x":0,"y":0,"w":220,"h":72},
105 | "sourceSize": {"w":220,"h":72}
106 | },
107 | "unit_3_walk_4.png":
108 | {
109 | "frame": {"x":1050,"y":1,"w":220,"h":69},
110 | "rotated": true,
111 | "trimmed": true,
112 | "spriteSourceSize": {"x":0,"y":3,"w":220,"h":69},
113 | "sourceSize": {"w":220,"h":72}
114 | },
115 | "unit_3_walk_5.png":
116 | {
117 | "frame": {"x":605,"y":72,"w":220,"h":72},
118 | "rotated": false,
119 | "trimmed": false,
120 | "spriteSourceSize": {"x":0,"y":0,"w":220,"h":72},
121 | "sourceSize": {"w":220,"h":72}
122 | },
123 | "unit_3_walk_6.png":
124 | {
125 | "frame": {"x":604,"y":146,"w":220,"h":72},
126 | "rotated": false,
127 | "trimmed": false,
128 | "spriteSourceSize": {"x":0,"y":0,"w":220,"h":72},
129 | "sourceSize": {"w":220,"h":72}
130 | }},
131 | "animations": {
132 | "unit_3_attack": ["unit_3_attack_1.png","unit_3_attack_2.png","unit_3_attack_3.png","unit_3_attack_4.png","unit_3_attack_5.png","unit_3_attack_6.png","unit_3_attack_7.png"],
133 | "unit_3_wait": ["unit_3_wait_1.png","unit_3_wait_2.png"],
134 | "unit_3_walk": ["unit_3_walk_1.png","unit_3_walk_2.png","unit_3_walk_3.png","unit_3_walk_4.png","unit_3_walk_5.png","unit_3_walk_6.png"]
135 | },
136 | "meta": {
137 | "app": "https://www.codeandweb.com/texturepacker",
138 | "version": "1.0",
139 | "image": "3.png",
140 | "format": "RGBA8888",
141 | "size": {"w":1120,"h":233},
142 | "scale": "1",
143 | "smartupdate": "$TexturePacker:SmartUpdate:2352d2738d45f02746287856c198b9ac:9adcd15992ce584d65a6be52cf6e25fb:4e25ec866a209ce3a44bf419a5862c0c$"
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/lib-ts/modules/BattleLogic.d.ts:
--------------------------------------------------------------------------------
1 | import StageMaster from 'interfaces/master/StageMaster';
2 | import UnitMaster from 'interfaces/master/UnitMaster';
3 | import CastleMaster from 'interfaces/master/CastleMaster';
4 | import BattleLogicDelegate from 'interfaces/BattleLogicDelegate';
5 | import BattleLogicConfig from 'modules/BattleLogicConfig';
6 | /**
7 | * ゲーム内バトルパートのマネージャ
8 | * ゲームロジックを中心に扱う
9 | */
10 | export default class BattleLogic {
11 | /**
12 | * バトル設定
13 | */
14 | private config;
15 | /**
16 | * BattleLogicDelegate 実装オブジェクト
17 | */
18 | private delegator?;
19 | /**
20 | * 現在の利用可能なコスト
21 | */
22 | private availableCost;
23 | /**
24 | * 次に割り当てるエンティティID
25 | */
26 | private nextEntityId;
27 | /**
28 | * 生成済みの Unit インスタンスを保持する配列
29 | */
30 | private attackableEntities;
31 | /**
32 | * 生成済みの Castle インスタンスを保持する配列
33 | */
34 | private castleEntities?;
35 | /**
36 | * フィールドマスタのキャッシュ
37 | */
38 | private stageMasterCache;
39 | /**
40 | * UnitMaster をキャッシュするための Map
41 | */
42 | private unitMasterCache;
43 | /**
44 | * CastleMaster をキャッシュするための Map
45 | */
46 | private castleMasterCache;
47 | /**
48 | * StageMaster.waves をキャッシュするための Map
49 | */
50 | private aiWaveCache;
51 | /**
52 | * 外部から生成をリクエストされたユニット情報を保持する配列
53 | */
54 | private spawnRequestedUnitUnitIds;
55 | /**
56 | * 経過フレーム数
57 | */
58 | private passedFrameCount;
59 | /**
60 | * 勝敗が決まっているかどうか
61 | */
62 | private isGameOver;
63 | /**
64 | * プレイヤー情報
65 | */
66 | private player?;
67 | /**
68 | * デリゲータとマスタ情報で初期化
69 | */
70 | init(params: {
71 | delegator: BattleLogicDelegate;
72 | stageMaster: StageMaster;
73 | unitMasters: UnitMaster[];
74 | player: {
75 | unitIds: number[];
76 | castle: CastleMaster;
77 | };
78 | ai: {
79 | castle: CastleMaster;
80 | };
81 | config?: BattleLogicConfig;
82 | }): void;
83 | /**
84 | * Unit 生成をリクエストする
85 | */
86 | requestSpawn(unitId: number, isPlayer: boolean): void;
87 | /**
88 | * Unit 生成をリクエストする
89 | * プレイヤーユニット生成リクエストのシュガー
90 | */
91 | requestSpawnPlayer(unitId: number): void;
92 | /**
93 | * Unit 生成をリクエストする
94 | * AIユニット生成リクエストのシュガー
95 | */
96 | requestSpawnAI(unitId: number): void;
97 | /**
98 | * ゲーム更新処理
99 | * 外部から任意のタイミングでコールする
100 | */
101 | update(): void;
102 | /**
103 | * メインループ後処理
104 | */
105 | private updatePostProcess;
106 | /**
107 | * Unit のパラメータを更新する
108 | * ステートは全てのパラメータが変化した後に更新する
109 | */
110 | private updateEntityParameter;
111 | /**
112 | * エンティティのステートを更新する
113 | * ステート優先順位は右記の通り DEAD > KNOCK_BACK > ENGAGED > IDLE
114 | * ユニット毎に処理を行うとステートを条件にした処理結果が
115 | * タイミングによって異なってしまうのでステート毎に処理を行う
116 | */
117 | private updateEntityState;
118 | /**
119 | * ダメージ判定を行い、必要に応じて以下を更新する。
120 | * - currentHealth
121 | * - currentFrameDamage
122 | */
123 | private updateDamage;
124 | /**
125 | * 移動可能か判定し、必要なら以下を更新する。
126 | * - distance
127 | * - currentKnockBackFrameCount
128 | */
129 | private updateDistance;
130 | /**
131 | * ノックバック時のステート更新処理
132 | */
133 | private updateAttackableKnockBackState;
134 | /**
135 | * 接敵時のステート更新処理
136 | */
137 | private updateAttackableEngagedState;
138 | /**
139 | * 何もしていない状態でのステート更新処理
140 | */
141 | private updateAttackableIdleState;
142 | /**
143 | * バトル状況からゲーム終了かどうかを判断する
144 | */
145 | private updateGameOver;
146 | /**
147 | * プレイヤーが勝利しているかどうかを返す
148 | */
149 | private isPlayerWon;
150 | /**
151 | * AI が勝利しているかどうかを返す
152 | */
153 | private isAiWon;
154 | /**
155 | * 現在のフレームに応じて AI ユニットを生成させる
156 | */
157 | private updateAISpawn;
158 | /**
159 | * 受け付けた Unit 生成リクエストを処理する
160 | * プレイヤーユニットの場合はコストを消費し、Unit 生成を試みる
161 | */
162 | private updateSpawnRequest;
163 | /**
164 | * 利用可能なコストを更新し、専用のコールバックをコールする
165 | */
166 | private updateAvailableCost;
167 | /**
168 | * 1 対 多での接敵を許容する場合は true を返す
169 | * 例外的に 1 対 多 を許容する場合があり、例えば拠点に対しての接敵は true とする
170 | */
171 | private chivalrousFilter;
172 | private spawnCastle;
173 | }
174 |
--------------------------------------------------------------------------------
/src/display/battle/Castle.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Resource from 'Resource';
3 | import SoundManager from 'managers/SoundManager';
4 | import Attackable from 'display/battle/Attackable';
5 | import CollapseExplodeEffect
6 | from 'display/battle/single_shot/CollapseExplodeEffect';
7 |
8 | const castleId1SpawnFrameCount = 16;
9 |
10 | /**
11 | * 拠点の振舞い、及び見た目に関する処理を行う
12 | * Attackable を継承する
13 | */
14 | export default class Castle extends Attackable {
15 | /**
16 | * 爆発エフェクト用コンテナ
17 | */
18 | public explodeContainer: PIXI.Container = new PIXI.Container();
19 |
20 | /**
21 | * 拠点 ID
22 | */
23 | protected castleId!: number;
24 |
25 | /**
26 | * このクラスで利用するリソースリスト
27 | */
28 | public static get resourceList(): string[] {
29 | return [Resource.Audio.Se.UnitSpawn];
30 | }
31 |
32 | /**
33 | * コンストラクタ
34 | */
35 | constructor(
36 | castleId: number,
37 | spawnPosition: { x: number, y: number }
38 | ) {
39 | super(spawnPosition);
40 |
41 | this.castleId = castleId;
42 |
43 | this.animationType = Resource.AnimationTypes.Castle.IDLE;
44 |
45 | this.sprite.texture = Resource.TextureFrame.Castle(castleId);
46 | }
47 |
48 | /**
49 | * UpdateObject インターフェース実装
50 | * requestAnimationFrame 毎のアップデート処理
51 | */
52 | public update(_dt: number): void {
53 | this.updateAnimation();
54 | }
55 |
56 | /**
57 | * アニメーションを初期化する
58 | */
59 | public resetAnimation(): void {
60 | this.animationType = Resource.AnimationTypes.Castle.IDLE;
61 | this.elapsedFrameCount = 0;
62 | }
63 |
64 | /**
65 | * 破壊状態にする
66 | */
67 | public collapse(): void {
68 | this.animationType = Resource.AnimationTypes.Castle.COLLAPSE;
69 | this.elapsedFrameCount = 0;
70 | }
71 | /**
72 | * ユニット生成状態にする
73 | */
74 | public spawn(playSe: boolean): void {
75 | if (playSe) {
76 | this.playSpawnSe();
77 | }
78 |
79 | this.animationType = Resource.AnimationTypes.Castle.SPAWN;
80 | this.elapsedFrameCount = 0;
81 | }
82 |
83 | /**
84 | * アニメーションを更新する
85 | */
86 | public updateAnimation(): void {
87 | switch (this.animationType) {
88 | case Resource.AnimationTypes.Castle.COLLAPSE: {
89 | this.explodeContainer.position.set(
90 | this.sprite.position.x - this.sprite.width * this.sprite.anchor.x,
91 | this.sprite.position.y - this.sprite.height * this.sprite.anchor.y
92 | );
93 | if ((this.elapsedFrameCount % 10) === 0) {
94 | this.spawnCollapseExplode();
95 | }
96 | const direction = (this.elapsedFrameCount % 2 === 0) ? 1 : -1;
97 | this.sprite.position.x = this.sprite.position.x + 4 * direction;
98 | break;
99 | }
100 | case Resource.AnimationTypes.Castle.SPAWN: {
101 | if (this.castleId === 1) {
102 | this.sprite.texture = Resource.TextureFrame.Castle(this.castleId, 2);
103 |
104 | if (this.elapsedFrameCount >= castleId1SpawnFrameCount) {
105 | this.resetAnimation();
106 | }
107 | } else {
108 | this.animationType = Resource.AnimationTypes.Castle.IDLE;
109 | }
110 | break;
111 | }
112 | case Resource.AnimationTypes.Castle.IDLE:
113 | default: {
114 | if (this.castleId === 1) {
115 | this.sprite.texture = Resource.TextureFrame.Castle(this.castleId, 1);
116 | } else {
117 | const r = 20; // range
118 | const t = 400; // duration
119 |
120 | const wave = Math.sin((2 * Math.PI / t) * this.elapsedFrameCount);
121 | this.sprite.position.y = this.spawnedPosition.y + -r * wave;
122 | }
123 |
124 | break;
125 | }
126 | }
127 |
128 | for (let i = 0; i < this.explodeContainer.children.length; i++) {
129 | const effect = this.explodeContainer.children[i];
130 | (effect as CollapseExplodeEffect).update(1);
131 | }
132 |
133 | this.elapsedFrameCount++;
134 | }
135 |
136 | /**
137 | * 破壊時の爆発を生成する
138 | */
139 | private spawnCollapseExplode(): void {
140 | const scale = 1.0 + Math.random() % 0.8 - 0.4;
141 |
142 | const effect = new CollapseExplodeEffect();
143 | effect.position.x = Math.random() * this.sprite.width;
144 | effect.position.y = Math.random() * this.sprite.height;
145 | effect.scale.set(scale);
146 |
147 | this.explodeContainer.addChild(effect);
148 | }
149 |
150 | /**
151 | * ユニット生成時の効果音を再生する
152 | */
153 | private playSpawnSe(): void {
154 | const sound = SoundManager.getSound(Resource.Audio.Se.UnitSpawn);
155 | if (sound) {
156 | sound.play();
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/www/assets/units/1.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "unit_1_attack_1.png":
4 | {
5 | "frame": {"x":175,"y":1,"w":110,"h":105},
6 | "rotated": true,
7 | "trimmed": true,
8 | "spriteSourceSize": {"x":31,"y":7,"w":110,"h":105},
9 | "sourceSize": {"w":172,"h":112}
10 | },
11 | "unit_1_attack_2.png":
12 | {
13 | "frame": {"x":282,"y":1,"w":110,"h":101},
14 | "rotated": true,
15 | "trimmed": true,
16 | "spriteSourceSize": {"x":31,"y":11,"w":110,"h":101},
17 | "sourceSize": {"w":172,"h":112}
18 | },
19 | "unit_1_attack_3.png":
20 | {
21 | "frame": {"x":282,"y":1,"w":110,"h":101},
22 | "rotated": true,
23 | "trimmed": true,
24 | "spriteSourceSize": {"x":31,"y":11,"w":110,"h":101},
25 | "sourceSize": {"w":172,"h":112}
26 | },
27 | "unit_1_attack_4.png":
28 | {
29 | "frame": {"x":1,"y":1,"w":172,"h":112},
30 | "rotated": false,
31 | "trimmed": false,
32 | "spriteSourceSize": {"x":0,"y":0,"w":172,"h":112},
33 | "sourceSize": {"w":172,"h":112}
34 | },
35 | "unit_1_attack_5.png":
36 | {
37 | "frame": {"x":1383,"y":1,"w":172,"h":101},
38 | "rotated": false,
39 | "trimmed": true,
40 | "spriteSourceSize": {"x":0,"y":11,"w":172,"h":101},
41 | "sourceSize": {"w":172,"h":112}
42 | },
43 | "unit_1_attack_6.png":
44 | {
45 | "frame": {"x":1383,"y":1,"w":172,"h":101},
46 | "rotated": false,
47 | "trimmed": true,
48 | "spriteSourceSize": {"x":0,"y":11,"w":172,"h":101},
49 | "sourceSize": {"w":172,"h":112}
50 | },
51 | "unit_1_attack_7.png":
52 | {
53 | "frame": {"x":1243,"y":1,"w":138,"h":102},
54 | "rotated": false,
55 | "trimmed": true,
56 | "spriteSourceSize": {"x":11,"y":7,"w":138,"h":102},
57 | "sourceSize": {"w":172,"h":112}
58 | },
59 | "unit_1_attack_8.png":
60 | {
61 | "frame": {"x":282,"y":1,"w":110,"h":101},
62 | "rotated": true,
63 | "trimmed": true,
64 | "spriteSourceSize": {"x":31,"y":11,"w":110,"h":101},
65 | "sourceSize": {"w":172,"h":112}
66 | },
67 | "unit_1_damage_1.png":
68 | {
69 | "frame": {"x":492,"y":1,"w":108,"h":104},
70 | "rotated": true,
71 | "trimmed": false,
72 | "spriteSourceSize": {"x":0,"y":0,"w":108,"h":104},
73 | "sourceSize": {"w":108,"h":104}
74 | },
75 | "unit_1_wait_1.png":
76 | {
77 | "frame": {"x":598,"y":1,"w":108,"h":104},
78 | "rotated": true,
79 | "trimmed": false,
80 | "spriteSourceSize": {"x":0,"y":0,"w":108,"h":104},
81 | "sourceSize": {"w":108,"h":104}
82 | },
83 | "unit_1_wait_2.png":
84 | {
85 | "frame": {"x":704,"y":1,"w":108,"h":101},
86 | "rotated": true,
87 | "trimmed": true,
88 | "spriteSourceSize": {"x":0,"y":3,"w":108,"h":101},
89 | "sourceSize": {"w":108,"h":104}
90 | },
91 | "unit_1_walk_1.png":
92 | {
93 | "frame": {"x":385,"y":1,"w":108,"h":105},
94 | "rotated": true,
95 | "trimmed": true,
96 | "spriteSourceSize": {"x":0,"y":3,"w":108,"h":105},
97 | "sourceSize": {"w":108,"h":108}
98 | },
99 | "unit_1_walk_2.png":
100 | {
101 | "frame": {"x":899,"y":1,"w":82,"h":108},
102 | "rotated": false,
103 | "trimmed": true,
104 | "spriteSourceSize": {"x":11,"y":0,"w":82,"h":108},
105 | "sourceSize": {"w":108,"h":108}
106 | },
107 | "unit_1_walk_3.png":
108 | {
109 | "frame": {"x":983,"y":1,"w":78,"h":108},
110 | "rotated": false,
111 | "trimmed": true,
112 | "spriteSourceSize": {"x":19,"y":0,"w":78,"h":108},
113 | "sourceSize": {"w":108,"h":108}
114 | },
115 | "unit_1_walk_4.png":
116 | {
117 | "frame": {"x":1143,"y":1,"w":98,"h":105},
118 | "rotated": false,
119 | "trimmed": true,
120 | "spriteSourceSize": {"x":7,"y":3,"w":98,"h":105},
121 | "sourceSize": {"w":108,"h":108}
122 | },
123 | "unit_1_walk_5.png":
124 | {
125 | "frame": {"x":1063,"y":1,"w":78,"h":108},
126 | "rotated": false,
127 | "trimmed": true,
128 | "spriteSourceSize": {"x":19,"y":0,"w":78,"h":108},
129 | "sourceSize": {"w":108,"h":108}
130 | },
131 | "unit_1_walk_6.png":
132 | {
133 | "frame": {"x":807,"y":1,"w":90,"h":108},
134 | "rotated": false,
135 | "trimmed": true,
136 | "spriteSourceSize": {"x":7,"y":0,"w":90,"h":108},
137 | "sourceSize": {"w":108,"h":108}
138 | }},
139 | "animations": {
140 | "unit_1_attack": ["unit_1_attack_1.png","unit_1_attack_2.png","unit_1_attack_3.png","unit_1_attack_4.png","unit_1_attack_5.png","unit_1_attack_6.png","unit_1_attack_7.png","unit_1_attack_8.png"],
141 | "unit_1_wait": ["unit_1_wait_1.png","unit_1_wait_2.png"],
142 | "unit_1_walk": ["unit_1_walk_1.png","unit_1_walk_2.png","unit_1_walk_3.png","unit_1_walk_4.png","unit_1_walk_5.png","unit_1_walk_6.png"]
143 | },
144 | "meta": {
145 | "app": "https://www.codeandweb.com/texturepacker",
146 | "version": "1.0",
147 | "image": "1.png",
148 | "format": "RGBA8888",
149 | "size": {"w":1556,"h":114},
150 | "scale": "1",
151 | "smartupdate": "$TexturePacker:SmartUpdate:5ee39f5806a5bb1e6923f13d08fbda46:e1d44482657ba5b7b0d6c3028faa902a:d31de202d7213cc8961db402b7b4c95a$"
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/www/assets/units/5.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "unit_5_attack_1.png":
4 | {
5 | "frame": {"x":517,"y":1,"w":158,"h":161},
6 | "rotated": false,
7 | "trimmed": true,
8 | "spriteSourceSize": {"x":3,"y":47,"w":158,"h":161},
9 | "sourceSize": {"w":176,"h":208}
10 | },
11 | "unit_5_attack_2.png":
12 | {
13 | "frame": {"x":339,"y":1,"w":176,"h":165},
14 | "rotated": false,
15 | "trimmed": true,
16 | "spriteSourceSize": {"x":0,"y":43,"w":176,"h":165},
17 | "sourceSize": {"w":176,"h":208}
18 | },
19 | "unit_5_attack_3.png":
20 | {
21 | "frame": {"x":677,"y":1,"w":158,"h":161},
22 | "rotated": false,
23 | "trimmed": true,
24 | "spriteSourceSize": {"x":3,"y":47,"w":158,"h":161},
25 | "sourceSize": {"w":176,"h":208}
26 | },
27 | "unit_5_attack_4.png":
28 | {
29 | "frame": {"x":1,"y":1,"w":176,"h":208},
30 | "rotated": false,
31 | "trimmed": false,
32 | "spriteSourceSize": {"x":0,"y":0,"w":176,"h":208},
33 | "sourceSize": {"w":176,"h":208}
34 | },
35 | "unit_5_attack_5.png":
36 | {
37 | "frame": {"x":179,"y":1,"w":158,"h":205},
38 | "rotated": false,
39 | "trimmed": true,
40 | "spriteSourceSize": {"x":3,"y":3,"w":158,"h":205},
41 | "sourceSize": {"w":176,"h":208}
42 | },
43 | "unit_5_attack_6.png":
44 | {
45 | "frame": {"x":1,"y":1,"w":176,"h":208},
46 | "rotated": false,
47 | "trimmed": false,
48 | "spriteSourceSize": {"x":0,"y":0,"w":176,"h":208},
49 | "sourceSize": {"w":176,"h":208}
50 | },
51 | "unit_5_attack_7.png":
52 | {
53 | "frame": {"x":179,"y":1,"w":158,"h":205},
54 | "rotated": false,
55 | "trimmed": true,
56 | "spriteSourceSize": {"x":3,"y":3,"w":158,"h":205},
57 | "sourceSize": {"w":176,"h":208}
58 | },
59 | "unit_5_attack_8.png":
60 | {
61 | "frame": {"x":1,"y":1,"w":176,"h":208},
62 | "rotated": false,
63 | "trimmed": false,
64 | "spriteSourceSize": {"x":0,"y":0,"w":176,"h":208},
65 | "sourceSize": {"w":176,"h":208}
66 | },
67 | "unit_5_attack_9.png":
68 | {
69 | "frame": {"x":968,"y":132,"w":110,"h":125},
70 | "rotated": true,
71 | "trimmed": true,
72 | "spriteSourceSize": {"x":35,"y":83,"w":110,"h":125},
73 | "sourceSize": {"w":176,"h":208}
74 | },
75 | "unit_5_damage_1.png":
76 | {
77 | "frame": {"x":837,"y":1,"w":128,"h":152},
78 | "rotated": false,
79 | "trimmed": false,
80 | "spriteSourceSize": {"x":0,"y":0,"w":128,"h":152},
81 | "sourceSize": {"w":128,"h":152}
82 | },
83 | "unit_5_wait_1.png":
84 | {
85 | "frame": {"x":1077,"y":1,"w":108,"h":128},
86 | "rotated": false,
87 | "trimmed": false,
88 | "spriteSourceSize": {"x":0,"y":0,"w":108,"h":128},
89 | "sourceSize": {"w":108,"h":128}
90 | },
91 | "unit_5_wait_2.png":
92 | {
93 | "frame": {"x":1095,"y":132,"w":108,"h":125},
94 | "rotated": true,
95 | "trimmed": true,
96 | "spriteSourceSize": {"x":0,"y":3,"w":108,"h":125},
97 | "sourceSize": {"w":108,"h":128}
98 | },
99 | "unit_5_walk_1.png":
100 | {
101 | "frame": {"x":967,"y":1,"w":108,"h":129},
102 | "rotated": false,
103 | "trimmed": true,
104 | "spriteSourceSize": {"x":0,"y":3,"w":108,"h":129},
105 | "sourceSize": {"w":108,"h":132}
106 | },
107 | "unit_5_walk_2.png":
108 | {
109 | "frame": {"x":517,"y":164,"w":82,"h":132},
110 | "rotated": true,
111 | "trimmed": true,
112 | "spriteSourceSize": {"x":11,"y":0,"w":82,"h":132},
113 | "sourceSize": {"w":108,"h":132}
114 | },
115 | "unit_5_walk_3.png":
116 | {
117 | "frame": {"x":339,"y":168,"w":78,"h":132},
118 | "rotated": true,
119 | "trimmed": true,
120 | "spriteSourceSize": {"x":19,"y":0,"w":78,"h":132},
121 | "sourceSize": {"w":108,"h":132}
122 | },
123 | "unit_5_walk_4.png":
124 | {
125 | "frame": {"x":1187,"y":1,"w":98,"h":129},
126 | "rotated": false,
127 | "trimmed": true,
128 | "spriteSourceSize": {"x":7,"y":3,"w":98,"h":129},
129 | "sourceSize": {"w":108,"h":132}
130 | },
131 | "unit_5_walk_5.png":
132 | {
133 | "frame": {"x":651,"y":164,"w":78,"h":132},
134 | "rotated": true,
135 | "trimmed": true,
136 | "spriteSourceSize": {"x":19,"y":0,"w":78,"h":132},
137 | "sourceSize": {"w":108,"h":132}
138 | },
139 | "unit_5_walk_6.png":
140 | {
141 | "frame": {"x":837,"y":155,"w":90,"h":129},
142 | "rotated": true,
143 | "trimmed": true,
144 | "spriteSourceSize": {"x":7,"y":3,"w":90,"h":129},
145 | "sourceSize": {"w":108,"h":132}
146 | }},
147 | "animations": {
148 | "unit_5_attack": ["unit_5_attack_1.png","unit_5_attack_2.png","unit_5_attack_3.png","unit_5_attack_4.png","unit_5_attack_5.png","unit_5_attack_6.png","unit_5_attack_7.png","unit_5_attack_8.png","unit_5_attack_9.png"],
149 | "unit_5_wait": ["unit_5_wait_1.png","unit_5_wait_2.png"],
150 | "unit_5_walk": ["unit_5_walk_1.png","unit_5_walk_2.png","unit_5_walk_3.png","unit_5_walk_4.png","unit_5_walk_5.png","unit_5_walk_6.png"]
151 | },
152 | "meta": {
153 | "app": "https://www.codeandweb.com/texturepacker",
154 | "version": "1.0",
155 | "image": "5.png",
156 | "format": "RGBA8888",
157 | "size": {"w":1286,"h":247},
158 | "scale": "1",
159 | "smartupdate": "$TexturePacker:SmartUpdate:4aac6b589fc7b9c0266a219216c53914:139dfd7b9c951556851b82b0b6f324ec:9addbf21a64760fa23b46a82ab6e4587$"
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/src/display/battle/Unit.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Resource from 'Resource';
3 | import UnitAnimationMaster, { UnitAnimationTypeIndex } from 'interfaces/master/UnitAnimationMaster';
4 | import Attackable from 'display/battle/Attackable';
5 | import HealthGauge from 'display/battle/single_shot/HealthGauge';
6 |
7 | /**
8 | * ユニットの振舞い、及び見た目に関する処理を行う
9 | * UnitEntity を継承する
10 | */
11 | export default class Unit extends Attackable {
12 | /**
13 | * アニメーション情報
14 | */
15 | protected animationMaster!: UnitAnimationMaster;
16 |
17 | /**
18 | * 現在のアニメーションフレーム
19 | */
20 | protected animationFrameId: number = 1;
21 | /**
22 | * 再生をリクエストされたアニメーション種別
23 | */
24 | protected requestedAnimation: string | null = null;
25 |
26 | /**
27 | * HealthGauge インスタンス
28 | * Unit で管理する
29 | */
30 | protected healthGauge: HealthGauge | null = null;
31 |
32 | /**
33 | * コンストラクタ
34 | */
35 | constructor(
36 | animationMaster: UnitAnimationMaster,
37 | spawnPosition: { x: number, y: number }
38 | ) {
39 | super(spawnPosition);
40 |
41 | this.animationType = Resource.AnimationTypes.Unit.WAIT;
42 | this.animationMaster = animationMaster;
43 | }
44 |
45 | /**
46 | * アニメーション再生をリセットする
47 | */
48 | public resetAnimation(): void {
49 | this.requestedAnimation = null;
50 | this.elapsedFrameCount = 0;
51 | this.animationFrameId = 1;
52 | }
53 |
54 | /**
55 | * UpdateObject インターフェース実装
56 | * requestAnimationFrame 毎のアップデート処理
57 | */
58 | public update(_dt: number): void {
59 | if (this.requestedAnimation) {
60 | if (this.transformAnimationIfPossible()) {
61 | this.requestedAnimation = null;
62 | }
63 | }
64 |
65 | this.updateAnimation();
66 | }
67 |
68 | /**
69 | * 人師種別のアニメーションの再生をリクエストする
70 | * リクエストされたアニメーションは再生可能になり次第再生される
71 | */
72 | public requestAnimation(type: string): void {
73 | this.requestedAnimation = type;
74 | }
75 |
76 | /**
77 | * 現在のアニメーションフレームのインデックスが当たり判定の発生するインデックスかどうかを返す
78 | */
79 | public isHitFrame(): boolean {
80 | if (this.animationFrameId !== this.animationMaster.hitFrame) {
81 | return false;
82 | }
83 | const index = Resource.AnimationTypes.Unit.ATTACK as UnitAnimationTypeIndex;
84 | const animation = this.animationMaster.types[index];
85 | if (!animation) {
86 | return false;
87 | }
88 |
89 | return (this.elapsedFrameCount % animation.updateDuration) === 0;
90 | }
91 | /**
92 | * 現在のアニメーションが終了するフレーム時間かどうかを返す
93 | */
94 | public isAnimationLastFrameTime(): boolean {
95 | const index = this.animationType as UnitAnimationTypeIndex;
96 | const animation = this.animationMaster.types[index];
97 | if (!animation) {
98 | return false;
99 | }
100 | const duration = animation.updateDuration;
101 | const lastId = animation.frames.length;
102 | const maxFrameTime = duration * lastId;
103 | return this.elapsedFrameCount === maxFrameTime;
104 | }
105 |
106 | /**
107 | * HealthGauge インスタンスを生成し、座標を設定して返す
108 | */
109 | public spawnHealthGauge(fromPercent: number, toPercent: number): HealthGauge {
110 | if (this.healthGauge) {
111 | this.healthGauge.destroy();
112 | }
113 |
114 | const anchor = this.sprite.anchor;
115 | this.healthGauge = new HealthGauge(fromPercent, toPercent);
116 | this.healthGauge.position.set(
117 | this.sprite.position.x - (this.healthGauge.gaugeWidth * anchor.x),
118 | this.sprite.position.y - (this.healthGauge.gaugeHeight * anchor.y)
119 | );
120 |
121 | return this.healthGauge;
122 | }
123 |
124 | /**
125 | * アニメーションを更新する
126 | */
127 | public updateAnimation(): void {
128 | const index = this.animationType as UnitAnimationTypeIndex;
129 | const animation = this.animationMaster.types[index];
130 | if (!animation) {
131 | return;
132 | }
133 | if ((this.elapsedFrameCount % animation.updateDuration) === 0) {
134 | if (this.isAnimationLastFrameTime()) {
135 | this.resetAnimation();
136 | }
137 |
138 | const cacheKey = animation.frames[this.animationFrameId - 1];
139 | this.sprite.texture = PIXI.utils.TextureCache[cacheKey];
140 |
141 | this.animationFrameId++;
142 | }
143 |
144 | this.elapsedFrameCount++;
145 | }
146 |
147 | /**
148 | * アニメーション遷移が可能であれば遷移する
149 | */
150 | private transformAnimationIfPossible(): boolean {
151 | const animationTypes = Resource.AnimationTypes.Unit;
152 |
153 | switch (this.requestedAnimation) {
154 | case animationTypes.WAIT:
155 | case animationTypes.WALK: {
156 | if (this.animationType !== animationTypes.WALK) {
157 | if (this.isAnimationLastFrameTime()) {
158 | this.animationType = this.requestedAnimation;
159 | this.resetAnimation();
160 | return true;
161 | }
162 | }
163 | break;
164 | }
165 | case animationTypes.DAMAGE:
166 | case animationTypes.ATTACK: {
167 | this.animationType = this.requestedAnimation;
168 | this.resetAnimation();
169 | return true;
170 | }
171 | default: break;
172 | }
173 |
174 | return false;
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/lib-ts/scenes/BattleScene.d.ts:
--------------------------------------------------------------------------------
1 | import BattleLogicDelegate from 'interfaces/BattleLogicDelegate';
2 | import BattleParameter from 'interfaces/BattleParameter';
3 | import LoaderAddParam from 'interfaces/PixiTypePolyfill/LoaderAddParam';
4 | import Scene from 'scenes/Scene';
5 | import UiNodeFactory from 'modules/UiNodeFactory/UiNodeFactory';
6 | import AttackableEntity from 'entity/AttackableEntity';
7 | import CastleEntity from 'entity/CastleEntity';
8 | import UnitEntity from 'entity/UnitEntity';
9 | /**
10 | * メインのゲーム部分のシーン
11 | * ゲームロジックは BattleLogic に委譲し、主に描画周りを行う
12 | */
13 | export default class BattleScene extends Scene implements BattleLogicDelegate {
14 | private static readonly castleXOffset;
15 | private static readonly unitLeapHeight;
16 | /**
17 | * UI Graph ユニットボタンのキープリフィックス
18 | */
19 | private static readonly unitButtonPrefix;
20 | /**
21 | * このシーンのステート
22 | */
23 | private state;
24 | /**
25 | * ユニット編成数
26 | */
27 | private unitSlotCount;
28 | /**
29 | * 挑戦するステージID
30 | */
31 | private stageId;
32 | /**
33 | * 編成した拠点パラメータ
34 | */
35 | private playerCastle;
36 | /**
37 | * 編成したユニットID配列
38 | */
39 | private unitIds;
40 | /**
41 | * ゲームロジックを処理する BattleLogic のインスタンス
42 | */
43 | private battleLogic;
44 | /**
45 | * BattleLogic 用の設定
46 | */
47 | private battleLogicConfig;
48 | /**
49 | * 背景の PIXI.Container
50 | */
51 | private field;
52 | /**
53 | * エンティティの ID で紐付けられた有効な Unit インスタンスのマップ
54 | */
55 | private attackables;
56 | /**
57 | * エンティティの ID で紐付けられた有効な Castle インスタンスのマップ
58 | */
59 | private castles;
60 | /**
61 | * ユニットアニメーションマスターのキャッシュ
62 | */
63 | private unitAnimationMasterCache;
64 | /**
65 | * コンストラクタ
66 | */
67 | constructor(params: BattleParameter);
68 | /**
69 | * Scene クラスメソッドオーバーライド
70 | */
71 | /**
72 | * トランジション開始処理
73 | * トランジション終了で可能ならステートを変更する
74 | */
75 | beginTransitionIn(onTransitionFinished: (scene: Scene) => void): void;
76 | /**
77 | * 毎フレームの更新処理
78 | * シーンのステートに応じて処理する
79 | */
80 | update(delta: number): void;
81 | /**
82 | * リソースリストの作成
83 | */
84 | protected createInitialResourceList(): (LoaderAddParam | string)[];
85 | /**
86 | * リソースロード完了コールバック
87 | * BattleLogic にユニットマスタ情報を渡し、フィールドやユニットボタンの初期化を行う
88 | */
89 | protected onInitialResourceLoaded(): (LoaderAddParam | string)[];
90 | /**
91 | * リソースロード完了時のコールバック
92 | */
93 | protected onResourceLoaded(): void;
94 | /**
95 | * 独自 UiGraph 要素のファクトリを返す
96 | * BattleScene は UnitButton を独自で定義している
97 | */
98 | protected getCustomUiGraphFactory(type: string): UiNodeFactory | null;
99 | /**
100 | * BattleLogicDelegate 実装
101 | */
102 | /**
103 | * CastleEntity が生成されたときのコールバック
104 | */
105 | onCastleEntitySpawned(entity: CastleEntity, isPlayer: boolean): void;
106 | /**
107 | * UnitEntity が生成されたときのコールバック
108 | * id に紐つけて表示物を生成する
109 | */
110 | onUnitEntitySpawned(entity: UnitEntity): void;
111 | /**
112 | * エンティティのステートが変更された際のコールバック
113 | */
114 | onAttackableEntityStateChanged(entity: AttackableEntity, _oldState: number): void;
115 | /**
116 | * 利用可能なコストの値が変動したときのコールバック
117 | */
118 | onAvailableCostUpdated(cost: number, maxCost: number, availablePlayerUnitIds: number[]): void;
119 | /**
120 | * 勝敗が決定したときのコールバック
121 | */
122 | onGameOver(isPlayerWon: boolean): void;
123 | /**
124 | * 渡されたエンティティ同士が接敵可能か返す
125 | */
126 | shouldEngageAttackableEntity(attacker: AttackableEntity, target: AttackableEntity): boolean;
127 | /**
128 | * 渡されたエンティティ同士が攻撃可能か返す
129 | */
130 | shouldDamage(attackerEntity: AttackableEntity, targetEntity: AttackableEntity): boolean;
131 | /**
132 | * 渡された UnitEntity の distance が変化した時に呼ばれる
133 | */
134 | onAttackableEntityWalked(entity: AttackableEntity): void;
135 | /**
136 | * 渡された UnitEntity がノックバック中に呼ばれる
137 | */
138 | onAttackableEntityKnockingBack(entity: AttackableEntity, knockBackRate: number): void;
139 | /**
140 | * 渡されたエンティティの health が増減した場合に呼ばれる
141 | */
142 | onAttackableEntityHealthUpdated(_attacker: AttackableEntity, target: AttackableEntity, fromHealth: number, toHealth: number, maxHealth: number): void;
143 | /**
144 | * 渡されたユニットが移動すべきかどうかを返す
145 | */
146 | shouldAttackableWalk(entity: AttackableEntity): boolean;
147 | /**
148 | * 特異メソッド
149 | */
150 | /**
151 | * UnitButton 用のコールバック
152 | * タップされたボタンに応じたユニットの生成を BattleLogic にリクエストする
153 | */
154 | onUnitButtonTapped(buttonIndex: number): void;
155 | /**
156 | * サウンドの初期化
157 | */
158 | private initSound;
159 | /**
160 | * ユニットボタンの初期化
161 | */
162 | private initUnitButtons;
163 | /**
164 | * ボタンインデックスから UnitButton インスタンスを返す
165 | */
166 | private getUiGraphUnitButton;
167 | /**
168 | * 編成画面へ戻る操作を有効にする
169 | */
170 | private enableBackToOrderScene;
171 | /**
172 | * 編成画面へ戻る
173 | */
174 | private backToOrderScene;
175 | }
176 |
--------------------------------------------------------------------------------
/src/Resource.ts:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Scene from 'scenes/Scene';
3 |
4 | /**
5 | * リソースの URL や命名規則のマスタ
6 | */
7 | const Resource = Object.freeze({
8 | /**
9 | * マスターデータ API 情報を有するオブジェクト
10 | */
11 | Api: {
12 | UserBattle: (userId: number): string => {
13 | const query = `?userId=${userId}`;
14 | return `api_mock/user_battle.json${query}`;
15 | },
16 | SceneUiGraph: (scene: Scene): string => {
17 | const snake_case = scene.constructor.name.replace(
18 | /([A-Z])/g,
19 | (s) => { return `_${s.charAt(0).toLowerCase()}`; }
20 | ).replace(/^_/, '');
21 |
22 | return `ui_graph/${snake_case}.json`;
23 | },
24 | Stage: (stageId: number): string => {
25 | return `master/stage_master_${stageId}.json`;
26 | },
27 | Unit: (unitIds: number[]): string => {
28 | const query = unitIds.join('&unitId[]=');
29 | return `master/unit_master.json?unitId[]=${query}`;
30 | },
31 | AllUnit: (): string => {
32 | return 'master/unit_master.json';
33 | },
34 | UnitAnimation: (unitIds: number[]): string => {
35 | const query = unitIds.join('&unitId[]=');
36 | return `master/unit_animation_master.json?unitId[]=${query}`;
37 | },
38 | Castle: (castleIds: number[]): string => {
39 | const query = castleIds.join('&castleId[]=');
40 | return `master/castle_master.json?castleId[]=${query}`;
41 | }
42 | },
43 |
44 | /**
45 | * 渡されたパラメータによって動的に変わる url を有するオブジェクト
46 | */
47 | Dynamic: {
48 | Unit: (unitId: number): string => {
49 | return `units/${unitId}.json`;
50 | },
51 | UnitPanel: (unitId: number): string => {
52 | const id = (unitId > 0) ? unitId : 'empty';
53 | return `ui/units_panel/button/unit_${id}.png`;
54 | },
55 | Castle: (castleId: number): string => {
56 | return `battle/castle/${castleId}.json`;
57 | }
58 | },
59 | /**
60 | * 静的なリソースを有するオブジェクト
61 | */
62 | Static: {
63 | BattleBgFores: [
64 | 'battle/bg_1_1.png',
65 | 'battle/bg_1_2.png',
66 | 'battle/bg_1_3.png',
67 | 'battle/bg_1_4.png',
68 | 'battle/bg_1_5.png',
69 | 'battle/bg_1_6.png',
70 | 'battle/bg_1_7.png',
71 | 'battle/bg_1_8.png',
72 | 'battle/bg_1_9.png',
73 | 'battle/bg_1_10.png'
74 | ],
75 | BattleBgMiddles: [
76 | 'battle/bg_2_1.png',
77 | 'battle/bg_2_2.png',
78 | 'battle/bg_2_3.png',
79 | 'battle/bg_2_4.png',
80 | 'battle/bg_2_5.png',
81 | 'battle/bg_2_6.png'
82 | ],
83 | BattleBgBacks: [
84 | 'battle/bg_3_1.png',
85 | 'battle/bg_3_2.png',
86 | 'battle/bg_3_3.png'
87 | ],
88 | AttackSmoke:
89 | 'battle/effects/attack_smoke/attack_smoke.json',
90 | DeadBucket:
91 | 'battle/effects/dead/dead_bucket.png',
92 | DeadSpirit:
93 | 'battle/effects/dead/dead_spirit.png',
94 | CollapseExplode:
95 | 'battle/effects/collapse_explode/collapse_explode.json',
96 | BattleResultWin:
97 | 'ui/battle_win.png',
98 | BattleResultLose:
99 | 'ui/battle_lose.png'
100 | },
101 | /**
102 | * サウンドリソースの静的な url を有するオブジェクト
103 | */
104 | Audio: {
105 | Bgm: {
106 | Title: 'audio/bgm_title.mp3',
107 | Battle: 'audio/bgm_battle.mp3'
108 | },
109 | Se: {
110 | Attack1: 'audio/se_attack_1.mp3',
111 | Attack2: 'audio/se_attack_2.mp3',
112 | Bomb: 'audio/se_bomb.mp3',
113 | UnitSpawn: 'audio/se_unit_spawn.mp3',
114 | Win: 'audio/se_win.mp3',
115 | Lose: 'audio/se_lose.mp3'
116 | }
117 | },
118 |
119 | /**
120 | * テクスチャのフレーム名を返す関数を有するオブジェクト
121 | */
122 | TextureFrame: {
123 | Unit: (
124 | unitActionType: string,
125 | unitId: number,
126 | index: number
127 | ): PIXI.Texture => {
128 | const key = `unit_${unitId}_${unitActionType}_${index}.png`;
129 | return PIXI.utils.TextureCache[key];
130 | },
131 | Castle: (castleId: number, index: number = 1): PIXI.Texture => {
132 | return PIXI.utils.TextureCache[`base_${castleId}_${index}.png`];
133 | },
134 | CollapseExplode: (index: number = 1): PIXI.Texture => {
135 | return PIXI.utils.TextureCache[`effect_1_${index}.png`];
136 | },
137 | AttackSmoke: (index: number = 1): PIXI.Texture => {
138 | return PIXI.utils.TextureCache[`effect_2_${index}.png`];
139 | }
140 | },
141 |
142 | /**
143 | * アニメーション種別の識別子を有するオブジェクト
144 | */
145 | AnimationTypes: {
146 | Unit: Object.freeze({
147 | WAIT: 'wait',
148 | WALK: 'walk',
149 | ATTACK: 'attack',
150 | DAMAGE: 'damage'
151 | }),
152 | Castle: Object.freeze({
153 | IDLE: 'idle',
154 | SPAWN: 'spawn',
155 | COLLAPSE: 'collapse'
156 | })
157 | },
158 |
159 | FontFamily: {
160 | Css: 'base.css',
161 | Default: 'MisakiGothic'
162 | },
163 |
164 | /**
165 | * スプライトシートの最大フレーム数を返す関数
166 | */
167 | MaxFrameIndex: (resourceKey: string): number => {
168 | const json = PIXI.loader.resources[resourceKey];
169 | if (!json || !json.data || !json.data.frames) {
170 | return -1;
171 | }
172 | return Object.keys(json.data.frames).length;
173 | }
174 | });
175 |
176 | export default Resource;
177 |
--------------------------------------------------------------------------------
/www/assets/units/4.json:
--------------------------------------------------------------------------------
1 | {"frames": {
2 |
3 | "unit_4_attack_1.png":
4 | {
5 | "frame": {"x":600,"y":173,"w":70,"h":82},
6 | "rotated": true,
7 | "trimmed": true,
8 | "spriteSourceSize": {"x":23,"y":31,"w":70,"h":82},
9 | "sourceSize": {"w":120,"h":124}
10 | },
11 | "unit_4_attack_2.png":
12 | {
13 | "frame": {"x":112,"y":1,"w":109,"h":121},
14 | "rotated": false,
15 | "trimmed": true,
16 | "spriteSourceSize": {"x":0,"y":3,"w":109,"h":121},
17 | "sourceSize": {"w":120,"h":124}
18 | },
19 | "unit_4_attack_3.png":
20 | {
21 | "frame": {"x":215,"y":124,"w":109,"h":121},
22 | "rotated": false,
23 | "trimmed": true,
24 | "spriteSourceSize": {"x":0,"y":3,"w":109,"h":121},
25 | "sourceSize": {"w":120,"h":124}
26 | },
27 | "unit_4_attack_4.png":
28 | {
29 | "frame": {"x":1,"y":1,"w":109,"h":124},
30 | "rotated": false,
31 | "trimmed": true,
32 | "spriteSourceSize": {"x":0,"y":0,"w":109,"h":124},
33 | "sourceSize": {"w":120,"h":124}
34 | },
35 | "unit_4_attack_5.png":
36 | {
37 | "frame": {"x":223,"y":1,"w":109,"h":121},
38 | "rotated": false,
39 | "trimmed": true,
40 | "spriteSourceSize": {"x":0,"y":3,"w":109,"h":121},
41 | "sourceSize": {"w":120,"h":124}
42 | },
43 | "unit_4_attack_6.png":
44 | {
45 | "frame": {"x":326,"y":124,"w":109,"h":121},
46 | "rotated": false,
47 | "trimmed": true,
48 | "spriteSourceSize": {"x":0,"y":3,"w":109,"h":121},
49 | "sourceSize": {"w":120,"h":124}
50 | },
51 | "unit_4_attack_7.png":
52 | {
53 | "frame": {"x":100,"y":127,"w":113,"h":113},
54 | "rotated": false,
55 | "trimmed": true,
56 | "spriteSourceSize": {"x":0,"y":11,"w":113,"h":113},
57 | "sourceSize": {"w":120,"h":124}
58 | },
59 | "unit_4_attack_8.png":
60 | {
61 | "frame": {"x":1,"y":127,"w":120,"h":97},
62 | "rotated": true,
63 | "trimmed": true,
64 | "spriteSourceSize": {"x":0,"y":27,"w":120,"h":97},
65 | "sourceSize": {"w":120,"h":124}
66 | },
67 | "unit_4_attack_9.png":
68 | {
69 | "frame": {"x":425,"y":1,"w":113,"h":89},
70 | "rotated": true,
71 | "trimmed": true,
72 | "spriteSourceSize": {"x":0,"y":35,"w":113,"h":89},
73 | "sourceSize": {"w":120,"h":124}
74 | },
75 | "unit_4_attack_10.png":
76 | {
77 | "frame": {"x":334,"y":1,"w":113,"h":89},
78 | "rotated": true,
79 | "trimmed": true,
80 | "spriteSourceSize": {"x":0,"y":35,"w":113,"h":89},
81 | "sourceSize": {"w":120,"h":124}
82 | },
83 | "unit_4_attack_11.png":
84 | {
85 | "frame": {"x":437,"y":116,"w":90,"h":78},
86 | "rotated": true,
87 | "trimmed": true,
88 | "spriteSourceSize": {"x":23,"y":35,"w":90,"h":78},
89 | "sourceSize": {"w":120,"h":124}
90 | },
91 | "unit_4_damage_1.png":
92 | {
93 | "frame": {"x":516,"y":1,"w":84,"h":80},
94 | "rotated": true,
95 | "trimmed": false,
96 | "spriteSourceSize": {"x":0,"y":0,"w":84,"h":80},
97 | "sourceSize": {"w":84,"h":80}
98 | },
99 | "unit_4_wait_1.png":
100 | {
101 | "frame": {"x":684,"y":173,"w":68,"h":81},
102 | "rotated": true,
103 | "trimmed": true,
104 | "spriteSourceSize": {"x":0,"y":3,"w":68,"h":81},
105 | "sourceSize": {"w":68,"h":84}
106 | },
107 | "unit_4_wait_2.png":
108 | {
109 | "frame": {"x":598,"y":1,"w":68,"h":84},
110 | "rotated": false,
111 | "trimmed": false,
112 | "spriteSourceSize": {"x":0,"y":0,"w":68,"h":84},
113 | "sourceSize": {"w":68,"h":84}
114 | },
115 | "unit_4_walk_1.png":
116 | {
117 | "frame": {"x":517,"y":173,"w":72,"h":81},
118 | "rotated": true,
119 | "trimmed": true,
120 | "spriteSourceSize": {"x":0,"y":3,"w":72,"h":81},
121 | "sourceSize": {"w":72,"h":84}
122 | },
123 | "unit_4_walk_2.png":
124 | {
125 | "frame": {"x":517,"y":87,"w":69,"h":84},
126 | "rotated": false,
127 | "trimmed": true,
128 | "spriteSourceSize": {"x":0,"y":0,"w":69,"h":84},
129 | "sourceSize": {"w":72,"h":84}
130 | },
131 | "unit_4_walk_3.png":
132 | {
133 | "frame": {"x":659,"y":87,"w":65,"h":84},
134 | "rotated": false,
135 | "trimmed": true,
136 | "spriteSourceSize": {"x":0,"y":0,"w":65,"h":84},
137 | "sourceSize": {"w":72,"h":84}
138 | },
139 | "unit_4_walk_4.png":
140 | {
141 | "frame": {"x":726,"y":87,"w":61,"h":81},
142 | "rotated": false,
143 | "trimmed": true,
144 | "spriteSourceSize": {"x":0,"y":3,"w":61,"h":81},
145 | "sourceSize": {"w":72,"h":84}
146 | },
147 | "unit_4_walk_5.png":
148 | {
149 | "frame": {"x":668,"y":1,"w":65,"h":84},
150 | "rotated": false,
151 | "trimmed": true,
152 | "spriteSourceSize": {"x":0,"y":0,"w":65,"h":84},
153 | "sourceSize": {"w":72,"h":84}
154 | },
155 | "unit_4_walk_6.png":
156 | {
157 | "frame": {"x":588,"y":87,"w":69,"h":84},
158 | "rotated": false,
159 | "trimmed": true,
160 | "spriteSourceSize": {"x":0,"y":0,"w":69,"h":84},
161 | "sourceSize": {"w":72,"h":84}
162 | }},
163 | "animations": {
164 | "unit_4_attack": ["unit_4_attack_1.png","unit_4_attack_2.png","unit_4_attack_3.png","unit_4_attack_4.png","unit_4_attack_5.png","unit_4_attack_6.png","unit_4_attack_7.png","unit_4_attack_8.png","unit_4_attack_9.png","unit_4_attack_10.png","unit_4_attack_11.png"],
165 | "unit_4_wait": ["unit_4_wait_1.png","unit_4_wait_2.png"],
166 | "unit_4_walk": ["unit_4_walk_1.png","unit_4_walk_2.png","unit_4_walk_3.png","unit_4_walk_4.png","unit_4_walk_5.png","unit_4_walk_6.png"]
167 | },
168 | "meta": {
169 | "app": "https://www.codeandweb.com/texturepacker",
170 | "version": "1.0",
171 | "image": "4.png",
172 | "format": "RGBA8888",
173 | "size": {"w":788,"h":248},
174 | "scale": "1",
175 | "smartupdate": "$TexturePacker:SmartUpdate:d0341326cda7a25cbcc172e97c04060e:073d20d5f219e5c3453fb0a1cab047ed:5969e3cdce764dec8974e89b279b41c5$"
176 | }
177 | }
178 |
--------------------------------------------------------------------------------