├── Little Orion ├── README.md ├── Little Orion │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── icons │ │ │ ├── Contents.json │ │ │ ├── energy-icon.imageset │ │ │ │ ├── energy-icon.png │ │ │ │ ├── energy-icon@2x.png │ │ │ │ └── Contents.json │ │ │ ├── mineral-icon.imageset │ │ │ │ ├── mineral-icon.png │ │ │ │ ├── mineral-icon@2x.png │ │ │ │ └── Contents.json │ │ │ └── science-icon.imageset │ │ │ │ ├── science-icon.png │ │ │ │ ├── science-icon@2x.png │ │ │ │ └── Contents.json │ │ ├── stars │ │ │ ├── Contents.json │ │ │ └── StarParticle.imageset │ │ │ │ ├── Star.png │ │ │ │ └── Contents.json │ │ ├── planets │ │ │ ├── 3D │ │ │ │ ├── Contents.json │ │ │ │ ├── Empty.imageset │ │ │ │ │ ├── Empty.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── MoonTexture.imageset │ │ │ │ │ ├── MoonTexture.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── ToxicTexture.imageset │ │ │ │ │ ├── ToxicTexture.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── DesertTexture.imageset │ │ │ │ │ ├── DesertTexture.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── FrozenTexture.imageset │ │ │ │ │ ├── FrozenTexture.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── OceanicTexture.imageset │ │ │ │ │ ├── OceanicTexture.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── VolcanicTexture.imageset │ │ │ │ │ ├── VolcanicTexture.jpg │ │ │ │ │ └── Contents.json │ │ │ │ └── ContinentalTexture.imageset │ │ │ │ │ ├── ContinentalTexture.jpg │ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Star.imageset │ │ │ │ ├── SunRed.png │ │ │ │ └── Contents.json │ │ │ ├── Desert.imageset │ │ │ │ ├── planet5.png │ │ │ │ └── Contents.json │ │ │ ├── Frozen.imageset │ │ │ │ ├── planet4.png │ │ │ │ └── Contents.json │ │ │ ├── Toxic.imageset │ │ │ │ ├── planet20.png │ │ │ │ └── Contents.json │ │ │ ├── blue.imageset │ │ │ │ ├── SunBlue.png │ │ │ │ └── Contents.json │ │ │ ├── Oceanic.imageset │ │ │ │ ├── planet2.png │ │ │ │ └── Contents.json │ │ │ ├── planet1.imageset │ │ │ │ ├── planet1.png │ │ │ │ └── Contents.json │ │ │ ├── planet6.imageset │ │ │ │ ├── planet6.png │ │ │ │ └── Contents.json │ │ │ ├── planet7.imageset │ │ │ │ ├── planet7.png │ │ │ │ └── Contents.json │ │ │ ├── Continental.imageset │ │ │ │ ├── planet3.png │ │ │ │ └── Contents.json │ │ │ ├── Volcanic.imageset │ │ │ │ ├── planet14.png │ │ │ │ └── Contents.json │ │ │ ├── planet10.imageset │ │ │ │ ├── planet10.png │ │ │ │ └── Contents.json │ │ │ ├── planet11.imageset │ │ │ │ ├── planet11.png │ │ │ │ └── Contents.json │ │ │ ├── planet13.imageset │ │ │ │ ├── planet13.png │ │ │ │ └── Contents.json │ │ │ ├── planet15.imageset │ │ │ │ ├── planet15.png │ │ │ │ └── Contents.json │ │ │ ├── planet16.imageset │ │ │ │ ├── planet16.png │ │ │ │ └── Contents.json │ │ │ ├── planet19.imageset │ │ │ │ ├── planet19.png │ │ │ │ └── Contents.json │ │ │ └── planet18_0.imageset │ │ │ │ ├── planet18_0.png │ │ │ │ └── Contents.json │ │ ├── skybox │ │ │ ├── Contents.json │ │ │ ├── Skybox_NegativeX.imageset │ │ │ │ ├── Skybox_NegativeX.jpg │ │ │ │ └── Contents.json │ │ │ ├── Skybox_NegativeY.imageset │ │ │ │ ├── Skybox_NegativeY.jpg │ │ │ │ └── Contents.json │ │ │ ├── Skybox_NegativeZ.imageset │ │ │ │ ├── Skybox_NegativeZ.jpg │ │ │ │ └── Contents.json │ │ │ ├── Skybox_PositiveX.imageset │ │ │ │ ├── Skybox_PositiveX.jpg │ │ │ │ └── Contents.json │ │ │ ├── Skybox_PositiveY.imageset │ │ │ │ ├── Skybox_PositiveY.jpg │ │ │ │ └── Contents.json │ │ │ └── Skybox_PositiveZ.imageset │ │ │ │ ├── Skybox_PositiveZ.jpg │ │ │ │ └── Contents.json │ │ ├── Spaceship.imageset │ │ │ ├── Spaceship.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── scenes │ │ ├── UniverseScene.sks │ │ └── UniverseScene.swift │ ├── flux │ │ ├── middleware │ │ │ ├── FilterMiddleware.swift │ │ │ └── LogMiddleware.swift │ │ ├── state │ │ │ ├── UniverseState.swift │ │ │ ├── AppState.swift │ │ │ ├── UIState.swift │ │ │ └── PlayerState.swift │ │ ├── actions │ │ │ ├── UniverseActions.swift │ │ │ ├── UIActions.swift │ │ │ └── PlayerActions.swift │ │ └── reducers │ │ │ ├── AppReducer.swift │ │ │ ├── UniverseReducer.swift │ │ │ ├── UIReducer.swift │ │ │ └── PlayerReducer.swift │ ├── models │ │ ├── player │ │ │ ├── AIPlayer.swift │ │ │ ├── components │ │ │ │ ├── PlayerSpriteComponent.swift │ │ │ │ └── PlayerMovementComponent.swift │ │ │ ├── PlayerResources.swift │ │ │ └── Player.swift │ │ ├── space │ │ │ ├── protocols │ │ │ │ ├── Discoverable.swift │ │ │ │ └── Traversable.swift │ │ │ ├── universe │ │ │ │ ├── EmptyEntity.swift │ │ │ │ ├── SystemEntity.swift │ │ │ │ ├── components │ │ │ │ │ └── UniverseSpriteComponent.swift │ │ │ │ └── UniverseEntity.swift │ │ │ ├── bodies │ │ │ │ ├── SystemBody.swift │ │ │ │ ├── StarEntity.swift │ │ │ │ └── PlanetEntity.swift │ │ │ └── Dimension.swift │ │ └── pop │ │ │ ├── Pop.swift │ │ │ ├── Nation.swift │ │ │ └── Race.swift │ ├── AI │ │ └── AIController.swift │ ├── resources │ │ ├── text │ │ │ ├── starsText.plist │ │ │ ├── testsText.plist │ │ │ ├── planetsText.plist │ │ │ └── raceText.plist │ │ ├── modifiers │ │ │ ├── raceForceModifier.plist │ │ │ └── planetResourcesModifier.plist │ │ ├── rules │ │ │ └── universeRules.plist │ │ └── dimensions │ │ │ └── universeDimensions.plist │ ├── helpers │ │ ├── Date.swift │ │ └── ResourcesLoader.swift │ ├── AppDelegate.swift │ ├── ui │ │ ├── BaseUI.swift │ │ ├── selection menu │ │ │ ├── cells │ │ │ │ ├── SelectionMenuTableViewCell.swift │ │ │ │ └── SelectionMenuTableViewCell.xib │ │ │ ├── SelectionMenu.swift │ │ │ └── SelectionMenu.xib │ │ ├── outliner │ │ │ ├── cells │ │ │ │ ├── OutlinerSystemTableViewCell.swift │ │ │ │ └── OutlinerSystemTableViewCell.xib │ │ │ ├── Outliner.swift │ │ │ └── Outliner.xib │ │ ├── BottomBar.swift │ │ ├── Modal.swift │ │ ├── TopBar.swift │ │ ├── SystemUI.swift │ │ ├── StarCell.xib │ │ ├── BottomBar.xib │ │ ├── SystemUI.xib │ │ └── TopBar.xib │ ├── Info.plist │ ├── viewControllers │ │ ├── GameViewController.swift │ │ └── PlanetViewController.swift │ └── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard ├── Little Orion.xcodeproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Podfile ├── Little Orion.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── Podfile.lock ├── UI │ ├── UI.h │ ├── UIButton │ │ └── BarButton.swift │ └── Info.plist └── OrionTests │ ├── Info.plist │ ├── ResourcesTest.swift │ └── RacesTests.swift ├── README.md └── .gitignore /Little Orion/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/stars/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/scenes/UniverseScene.sks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/scenes/UniverseScene.sks -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/Spaceship.imageset/Spaceship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/Spaceship.imageset/Spaceship.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Star.imageset/SunRed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/Star.imageset/SunRed.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/Empty.imageset/Empty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/3D/Empty.imageset/Empty.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Desert.imageset/planet5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/Desert.imageset/planet5.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Frozen.imageset/planet4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/Frozen.imageset/planet4.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Toxic.imageset/planet20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/Toxic.imageset/planet20.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/blue.imageset/SunBlue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/blue.imageset/SunBlue.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Oceanic.imageset/planet2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/Oceanic.imageset/planet2.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet1.imageset/planet1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet1.imageset/planet1.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet6.imageset/planet6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet6.imageset/planet6.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet7.imageset/planet7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet7.imageset/planet7.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/stars/StarParticle.imageset/Star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/stars/StarParticle.imageset/Star.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Continental.imageset/planet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/Continental.imageset/planet3.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Volcanic.imageset/planet14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/Volcanic.imageset/planet14.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet10.imageset/planet10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet10.imageset/planet10.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet11.imageset/planet11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet11.imageset/planet11.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet13.imageset/planet13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet13.imageset/planet13.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet15.imageset/planet15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet15.imageset/planet15.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet16.imageset/planet16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet16.imageset/planet16.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet19.imageset/planet19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet19.imageset/planet19.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/energy-icon.imageset/energy-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/icons/energy-icon.imageset/energy-icon.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet18_0.imageset/planet18_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/planet18_0.imageset/planet18_0.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/energy-icon.imageset/energy-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/icons/energy-icon.imageset/energy-icon@2x.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/mineral-icon.imageset/mineral-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/icons/mineral-icon.imageset/mineral-icon.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/science-icon.imageset/science-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/icons/science-icon.imageset/science-icon.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/mineral-icon.imageset/mineral-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/icons/mineral-icon.imageset/mineral-icon@2x.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/science-icon.imageset/science-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/icons/science-icon.imageset/science-icon@2x.png -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/MoonTexture.imageset/MoonTexture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/3D/MoonTexture.imageset/MoonTexture.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/ToxicTexture.imageset/ToxicTexture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/3D/ToxicTexture.imageset/ToxicTexture.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/DesertTexture.imageset/DesertTexture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/3D/DesertTexture.imageset/DesertTexture.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/FrozenTexture.imageset/FrozenTexture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/3D/FrozenTexture.imageset/FrozenTexture.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/OceanicTexture.imageset/OceanicTexture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/3D/OceanicTexture.imageset/OceanicTexture.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/VolcanicTexture.imageset/VolcanicTexture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/3D/VolcanicTexture.imageset/VolcanicTexture.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeX.imageset/Skybox_NegativeX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeX.imageset/Skybox_NegativeX.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeY.imageset/Skybox_NegativeY.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeY.imageset/Skybox_NegativeY.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeZ.imageset/Skybox_NegativeZ.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeZ.imageset/Skybox_NegativeZ.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveX.imageset/Skybox_PositiveX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveX.imageset/Skybox_PositiveX.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveY.imageset/Skybox_PositiveY.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveY.imageset/Skybox_PositiveY.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveZ.imageset/Skybox_PositiveZ.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveZ.imageset/Skybox_PositiveZ.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/ContinentalTexture.imageset/ContinentalTexture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/LittleOrion/master/Little Orion/Little Orion/Assets.xcassets/planets/3D/ContinentalTexture.imageset/ContinentalTexture.jpg -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/middleware/FilterMiddleware.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterMiddleware.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 22/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/player/AIPlayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AIPlayer.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 22/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class AIPlayer: Player { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/AI/AIController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AIController.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 19/04/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | class AIController { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Little Orion/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | platform :ios, '12.0' 3 | use_frameworks! 4 | inhibit_all_warnings! 5 | 6 | def shared_pods 7 | pod 'ReSwift' 8 | end 9 | 10 | target 'LittleOrion' do 11 | shared_pods 12 | end 13 | 14 | target 'OrionTests' do 15 | shared_pods 16 | end 17 | -------------------------------------------------------------------------------- /Little Orion/Little Orion.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Little Orion/Little Orion.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Little Orion/Little Orion.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Latest 7 | 8 | 9 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/resources/text/starsText.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Nova 6 | Supernova 7 | Dwarf 8 | 9 | 10 | -------------------------------------------------------------------------------- /Little Orion/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ReSwift (4.1.1) 3 | 4 | DEPENDENCIES: 5 | - ReSwift 6 | 7 | SPEC REPOS: 8 | https://github.com/cocoapods/specs.git: 9 | - ReSwift 10 | 11 | SPEC CHECKSUMS: 12 | ReSwift: d925be0033558f55bd73d92869961230dfe19d52 13 | 14 | PODFILE CHECKSUM: 1b1f0c46086663ef1eb499cc7a6d5441844fc44c 15 | 16 | COCOAPODS: 1.6.1 17 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/resources/text/testsText.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test1 6 | test 1 result 7 | test2 8 | test 2 result 9 | 10 | 11 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/state/UniverseState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UniverseState.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | struct UniverseState: Equatable { 13 | var universe: Universe? 14 | } 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/resources/modifiers/raceForceModifier.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | weak 6 | 0.8 7 | average 8 | 1 9 | strong 10 | 1.2 11 | 12 | 13 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/actions/UniverseActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UniverseActions.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | class UniverseActions { 13 | struct CreateUnivserse: Action { 14 | let size: Universe.UniverseSize 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/state/AppState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // State.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | struct AppState: StateType, Equatable { 13 | 14 | var universeState: UniverseState 15 | var playerState: PlayerState 16 | var uiState: UIState 17 | } 18 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/resources/text/planetsText.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Desert 6 | Oceanic 7 | Toxic 8 | Continental 9 | Frozen 10 | Volcanic 11 | 12 | 13 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/resources/text/raceText.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | human 6 | Human are standard 7 | lizard 8 | Lizard are cool 9 | plantoid 10 | Plantoid are not worth it 11 | 12 | 13 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/Spaceship.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "Spaceship.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Star.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "SunRed.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/blue.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "SunBlue.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/Empty.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Empty.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Desert.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet5.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Frozen.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet4.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Oceanic.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet2.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Toxic.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet20.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Volcanic.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet14.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet10.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet10.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet11.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet11.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet13.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet13.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet15.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet15.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet16.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet16.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet19.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet19.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet6.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet6.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet7.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet7.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/stars/StarParticle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Star.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/Continental.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet3.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/planet18_0.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "planet18_0.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/MoonTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "MoonTexture.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/ToxicTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ToxicTexture.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/DesertTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "DesertTexture.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/FrozenTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "FrozenTexture.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/OceanicTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "OceanicTexture.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeX.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Skybox_NegativeX.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeY.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Skybox_NegativeY.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_NegativeZ.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Skybox_NegativeZ.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveX.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Skybox_PositiveX.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveY.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Skybox_PositiveY.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/skybox/Skybox_PositiveZ.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Skybox_PositiveZ.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/VolcanicTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "VolcanicTexture.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/planets/3D/ContinentalTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ContinentalTexture.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/protocols/Discoverable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Discoverable.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 24/03/2018. 6 | // Copyright © 2018 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // Entities which are discoverable by the player need to implement that protocol. 12 | protocol Discoverable: class { 13 | 14 | var discovered: Bool { get } 15 | var dayToDiscover: Int { get } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/energy-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "energy-icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "energy-icon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/mineral-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "mineral-icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "mineral-icon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/icons/science-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "science-icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "science-icon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/middleware/LogMiddleware.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LogMiddleware.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | let logMiddleware: Middleware = { dispatch, getState in 13 | return { next in 14 | return { action in 15 | print(type(of: action)) 16 | return next(action) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/protocols/Traversable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Traversable.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 09/10/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // Entities which are travelable by the player need to implement that protocol. 12 | protocol Travelable: class { 13 | 14 | // The numver of day that it takes to travel trough the entity which implement that function. 15 | var travelTimeDay: Int { get } 16 | } 17 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/universe/EmptyEntity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Empty.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 25/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class EmptyEntity: UniverseEntity { 12 | 13 | override var travelTimeDay: Int { 14 | return 5 15 | } 16 | 17 | override var description: String { 18 | get { 19 | return "Empty part of the universe" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Little Orion/UI/UI.h: -------------------------------------------------------------------------------- 1 | // 2 | // UI.h 3 | // UI 4 | // 5 | // Created by Thomas Ricouard on 08/10/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for UI. 12 | FOUNDATION_EXPORT double UIVersionNumber; 13 | 14 | //! Project version string for UI. 15 | FOUNDATION_EXPORT const unsigned char UIVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/pop/Pop.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pop.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 24/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class Pop: GKEntity { 12 | 13 | let race: Race 14 | 15 | public init(race: Race) { 16 | self.race = race 17 | super.init() 18 | 19 | } 20 | 21 | required init?(coder aDecoder: NSCoder) { 22 | fatalError("init(coder:) has not been implemented") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/resources/rules/universeRules.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | systemSpwawnProbability 6 | 10 7 | superPlanetSpwawnProbability 8 | 10 9 | superPlanetScale 10 | 1.3 11 | basePlanetsRadius 12 | 9500 13 | planetMaxSpace 14 | 50 15 | 16 | 17 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/bodies/SystemBody.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SystemBody.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 25/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class SystemBody: GKEntity { 12 | 13 | let name: String 14 | 15 | public init(name: String) { 16 | self.name = name 17 | super.init() 18 | } 19 | 20 | required init?(coder aDecoder: NSCoder) { 21 | fatalError("init(coder:) has not been implemented") 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Little Orion 2 | 3 | Little Orion is a 4X space strategy game tailored for iOS. 4 | It's vastly insprired from Stellaris and Master of Orion. 5 | 6 | My goal while writing this game is mainly to learn SpriteKit, GameplayKit and SceneKit frameworks from Apple. 7 | 8 | It's wrote in Swift 4, use all of the latest iOS technologies. It's also using the Redux pattern as a backend. So most of the state machine from GameplayKit is not used here. It havr its own state machine and events bus instead. 9 | 10 | So for the time being, Little Orion will be iOS only. Once it'll be good enough, I might port it to Unity. 11 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/reducers/AppReducer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppReducer.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | func AppReducer(action: Action, state: AppState?) -> AppState { 13 | return AppState( 14 | universeState: universeReducer(state: state?.universeState, action: action), 15 | playerState: playerReducer(state: state?.playerState, action: action), 16 | uiState: uiReducer(state: state?.uiState, action: action) 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/reducers/UniverseReducer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UniverseReducer.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | func universeReducer(state: UniverseState?, action: Action) -> UniverseState { 13 | var state = state ?? UniverseState() 14 | switch action { 15 | case let action as UniverseActions.CreateUnivserse: 16 | state.universe = Universe(size: action.size) 17 | default: 18 | break 19 | } 20 | return state 21 | } 22 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/helpers/Date.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Date.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 09/10/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Date { 12 | 13 | func numberOfDaysSince(date: Date) -> Int { 14 | let calendar = Calendar.current 15 | 16 | let fromDate = calendar.startOfDay(for: date) 17 | let toDate = calendar.startOfDay(for: self) 18 | 19 | let components = calendar.dateComponents([.day], from: fromDate, to: toDate) 20 | return components.day ?? 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Little Orion/UI/UIButton/BarButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarButton.swift 3 | // UI 4 | // 5 | // Created by Thomas Ricouard on 08/10/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @IBDesignable 12 | open class BarButton: UIButton { 13 | 14 | override open func awakeFromNib() { 15 | setup() 16 | } 17 | 18 | override open func prepareForInterfaceBuilder() { 19 | setup() 20 | } 21 | 22 | func setup() { 23 | layer.borderColor = UIColor.white.cgColor 24 | layer.borderWidth = 0.5 25 | layer.cornerRadius = 4 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/state/UIState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIState.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | import GameplayKit 12 | 13 | struct UIState: Equatable { 14 | 15 | var selectedEntity: UniverseEntity? 16 | var selectedSystem: SystemEntity? 17 | var selectedPlanet: PlanetEntity? 18 | var currentModal: Modal 19 | var currentScene: Scene 20 | 21 | var selectedNode: SKNode? 22 | } 23 | 24 | enum Modal { 25 | case none 26 | case entity 27 | case system 28 | 29 | } 30 | 31 | enum Scene { 32 | case universe 33 | case planet 34 | } 35 | 36 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ReSwift 11 | 12 | let store = Store(reducer: AppReducer, 13 | state: nil, 14 | middleware: [logMiddleware]) 15 | 16 | @UIApplicationMain 17 | class AppDelegate: UIResponder, UIApplicationDelegate { 18 | 19 | var window: UIWindow? 20 | 21 | 22 | internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 23 | return true 24 | } 25 | 26 | 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /Little Orion/OrionTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/BaseUI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseUI.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 25/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIView { 12 | public static func loadFromNib() -> T { 13 | let nib = UINib(nibName: String(describing: self), bundle: Bundle.main) 14 | return nib.instantiate(withOwner: self, options: nil)[0] as! T 15 | } 16 | } 17 | 18 | class BaseUI: UIView { 19 | 20 | override func didMoveToSuperview() { 21 | super.didMoveToSuperview() 22 | 23 | layer.borderWidth = 0.5 24 | layer.borderColor = UIColor.white.cgColor 25 | layer.cornerRadius = 5 26 | clipsToBounds = true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/selection menu/cells/SelectionMenuTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SelectionMenuTableViewCell.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 01/04/2018. 6 | // Copyright © 2018 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SelectionMenuTableViewCell: UITableViewCell { 12 | 13 | static let id = "SelectionMenuTableViewCell" 14 | 15 | @IBOutlet var menuLabel: UILabel! 16 | 17 | override func awakeFromNib() { 18 | super.awakeFromNib() 19 | // Initialization code 20 | } 21 | 22 | override func setSelected(_ selected: Bool, animated: Bool) { 23 | super.setSelected(selected, animated: animated) 24 | 25 | // Configure the view for the selected state 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/outliner/cells/OutlinerSystemTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OutlinerSystemTableViewCell.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 26/03/2018. 6 | // Copyright © 2018 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class OutlinerSystemTableViewCell: UITableViewCell { 12 | 13 | static let id = "OutlinerSystemTableViewCell" 14 | 15 | @IBOutlet var systemName: UILabel! 16 | @IBOutlet var systemDiscoveryProgress: UIProgressView! 17 | 18 | override func awakeFromNib() { 19 | super.awakeFromNib() 20 | } 21 | 22 | override func setSelected(_ selected: Bool, animated: Bool) { 23 | super.setSelected(selected, animated: animated) 24 | 25 | // Configure the view for the selected state 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/actions/UIActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIActions.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | import SpriteKit 12 | 13 | class UIActions { 14 | struct ShowSelectedSystemModal: Action { 15 | let system: SystemEntity 16 | } 17 | 18 | struct ShowSelectionModal: Action { 19 | let entity: UniverseEntity 20 | } 21 | 22 | struct ShowPlanetDetail: Action { 23 | let planet: PlanetEntity 24 | } 25 | 26 | struct ShowUniverseScene: Action { 27 | 28 | } 29 | 30 | struct DismissModal: Action { 31 | 32 | } 33 | 34 | struct SetSelectedNode: Action { 35 | let node: SKNode 36 | } 37 | 38 | struct RemoveSelectedNode: Action { } 39 | } 40 | -------------------------------------------------------------------------------- /Little Orion/UI/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/pop/Nation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Nation.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 24/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class Nation: GKEntity { 12 | 13 | private var pops: [Pop] 14 | 15 | //A nation must be created with at least one pop in it. 16 | init(pops: [Pop]) { 17 | self.pops = pops 18 | 19 | super.init() 20 | } 21 | 22 | required init?(coder aDecoder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | public func addPop(pop: Pop) { 27 | pops.append(pop) 28 | } 29 | 30 | public func removePop(pop: Pop) { 31 | if let index = pops.index(of: pop) { 32 | pops.remove(at: index) 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/Dimension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dimension.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 25/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Size: Equatable { 12 | var width: Int32 = 0 13 | var height: Int32 = 0; 14 | 15 | public init(width: Int32, height: Int32) { 16 | self.width = width 17 | self.height = height 18 | } 19 | } 20 | 21 | func ==(lhs: T, rhs: T) -> Bool { 22 | return lhs.width == rhs.width && 23 | rhs.height == lhs.height 24 | } 25 | 26 | class Location: Equatable { 27 | var x: Int32 = 0 28 | var y: Int32 = 0 29 | 30 | public init(x: Int32, y: Int32) { 31 | self.x = x 32 | self.y = y 33 | } 34 | } 35 | 36 | func ==(lhs: T, rhs: T) -> Bool { 37 | return lhs.x == rhs.x && 38 | rhs.y == lhs.y 39 | } 40 | -------------------------------------------------------------------------------- /Little Orion/OrionTests/ResourcesTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResourcesTest.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 24/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LittleOrion 11 | 12 | 13 | class ResourcesTest: XCTestCase { 14 | 15 | let test1result = "test 1 result" 16 | let test2result = "test 2 result" 17 | 18 | override func setUp() { 19 | super.setUp() 20 | } 21 | 22 | override func tearDown() { 23 | super.tearDown() 24 | } 25 | 26 | func testResourceLoader() { 27 | let plist = ResourcesLoader.loadTextResource(name: "testsText") 28 | if let plist = plist { 29 | XCTAssertEqual(plist["test1"], test1result) 30 | XCTAssertEqual(plist["test2"], test2result) 31 | } else { 32 | XCTFail("plist is nil") 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/player/components/PlayerSpriteComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlayerSpriteComponent.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 08/10/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import GameplayKit 11 | import SpriteKit 12 | 13 | class PlayerSpriteComponent: GKSKNodeComponent { 14 | 15 | override init() { 16 | let texture = SKTexture(image: #imageLiteral(resourceName: "Spaceship")) 17 | let node = SKShapeNode(rect: CGRect(x: 0, y: 0, width: UniverseSpriteComponent.nodeSize.width, 18 | height: UniverseSpriteComponent.nodeSize.height)) 19 | node.name = "Player node" 20 | node.fillTexture = texture 21 | node.fillColor = .white 22 | node.zPosition = 5 23 | super.init(node: node) 24 | } 25 | 26 | required init?(coder aDecoder: NSCoder) { 27 | fatalError("init(coder:) has not been implemented") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/resources/dimensions/universeDimensions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | node 6 | 7 | width 8 | 70 9 | height 10 | 70 11 | 12 | standard 13 | 14 | width 15 | 50 16 | height 17 | 50 18 | 19 | tiny 20 | 21 | width 22 | 10 23 | height 24 | 10 25 | 26 | small 27 | 28 | width 29 | 20 30 | height 31 | 20 32 | 33 | big 34 | 35 | width 36 | 100 37 | height 38 | 100 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/pop/Race.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Race.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class Race: GKEntity { 12 | 13 | enum Kind: String { 14 | case human, lizard, plantoid 15 | 16 | func description() -> String { 17 | return ResourcesLoader.loadTextResource(name: "raceText")![rawValue]! 18 | } 19 | } 20 | 21 | enum Force: String { 22 | case weak, average, strong 23 | 24 | func modifier() -> Float { 25 | return ResourcesLoader.loadModifierResource(name: "raceForceModifier")![rawValue]! 26 | } 27 | } 28 | 29 | let name: String 30 | let kind: Kind 31 | let force: Force 32 | 33 | init(name: String, kind: Kind, force: Force) { 34 | self.kind = kind 35 | self.force = force 36 | self.name = name 37 | super.init() 38 | } 39 | 40 | required init?(coder aDecoder: NSCoder) { 41 | fatalError("init(coder:) has not been implemented") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 0.1 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarHidden 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/state/PlayerState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlayerState.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | enum PlayerSpeed: TimeInterval { 13 | case slow = 1.5 14 | case normal = 1.0 15 | case fast = 0.5 16 | case faster = 0.2 17 | 18 | func nextValue() -> PlayerSpeed { 19 | switch self { 20 | case .slow: 21 | return .normal 22 | case .normal: 23 | return .fast 24 | case .fast: 25 | return .faster 26 | case .faster: 27 | return .slow 28 | } 29 | } 30 | 31 | func displayValue() -> String { 32 | switch self { 33 | case .slow: 34 | return "0.5" 35 | case .normal: 36 | return "1.0" 37 | case .fast: 38 | return "1.5" 39 | case .faster: 40 | return "2.0" 41 | } 42 | } 43 | } 44 | 45 | struct PlayerState: Equatable { 46 | var player = Player(name: "Player 1") 47 | var currentDate = Date() 48 | var dateTimer: Timer? 49 | var currentSpeed = PlayerSpeed.normal 50 | var isPlaying = false 51 | } 52 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/BottomBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BottomBar.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 22/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ReSwift 12 | import UI 13 | 14 | protocol BottomBarDelegate: class { 15 | func onCenterPlayerButton() 16 | func onMovePlayerButton() 17 | } 18 | 19 | class BottomBar: BaseUI, StoreSubscriber { 20 | 21 | @IBOutlet var planetNumber: UILabel! 22 | @IBOutlet var moveButton: BarButton! 23 | 24 | weak var delegate: BottomBarDelegate? 25 | 26 | override func didMoveToSuperview() { 27 | super.didMoveToSuperview() 28 | 29 | layer.cornerRadius = 0 30 | 31 | store.subscribe(self) { 32 | $0.select{ $0.playerState }.skipRepeats() 33 | } 34 | } 35 | 36 | func newState(state: PlayerState) { 37 | planetNumber.text = "Planets: \(state.player.discoveredPlanets.count)" 38 | moveButton.setTitle(state.player.isInMovement ? "Stop" : "Move", for: .normal) 39 | } 40 | 41 | @IBAction func onMeButton(_ sender: Any) { 42 | delegate?.onCenterPlayerButton() 43 | } 44 | 45 | @IBAction func onMoveButton(_ sender: Any) { 46 | delegate?.onMovePlayerButton() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Little Orion/OrionTests/RacesTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RacesTests.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 24/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LittleOrion 11 | 12 | class RacesTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testsDescription() { 25 | let race = Race(name: "race1", kind: .human, force: .weak) 26 | let race2 = Race(name: "race2", kind: .plantoid, force: .weak) 27 | let race3 = Race(name: "race3", kind: .lizard, force: .weak) 28 | 29 | XCTAssertNotNil(race.kind.description()) 30 | XCTAssertNotNil(race2.kind.description()) 31 | XCTAssertNotNil(race3.kind.description()) 32 | 33 | XCTAssertNotNil(race.force.modifier()) 34 | XCTAssertNotNil(race2.force.modifier()) 35 | XCTAssertNotNil(race3.force.modifier()) 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/player/PlayerResources.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlayerResource.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | enum PlayerResourceType: String { 13 | case energy, minerals, science 14 | } 15 | 16 | class PlayerResource: Equatable { 17 | 18 | let type: PlayerResourceType 19 | var value = 0 20 | var income: Int { 21 | get { 22 | //TODO: Random for now, will be calculated from player inhabited planets 23 | return Int(arc4random_uniform(10)) 24 | } 25 | } 26 | 27 | init(type: PlayerResourceType) { 28 | self.type = type 29 | } 30 | 31 | 32 | func update() { 33 | value += income 34 | } 35 | } 36 | 37 | func ==(lhs: PlayerResource, rhs: PlayerResource) -> Bool { 38 | return lhs.value == rhs.value && 39 | rhs.income == lhs.income 40 | } 41 | 42 | class PlayerResources: Equatable { 43 | var energy = PlayerResource(type: .energy) 44 | var minerals = PlayerResource(type: .minerals) 45 | var science = PlayerResource(type: .science) 46 | 47 | func update() { 48 | self.energy.update() 49 | self.minerals.update() 50 | self.science.update() 51 | } 52 | } 53 | 54 | func ==(lhs: PlayerResources, rhs: PlayerResources) -> Bool { 55 | return lhs.energy == rhs.energy && 56 | lhs.minerals == rhs.minerals && 57 | lhs.science == rhs.science 58 | } 59 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/player/Player.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Player.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 22/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameplayKit 11 | import ReSwift 12 | 13 | class Player: GKEntity, GKGameModelPlayer, StateType { 14 | let name: String 15 | 16 | public var playerId: Int { 17 | get { 18 | return name.hashValue 19 | } 20 | } 21 | 22 | var resources = PlayerResources() 23 | 24 | var discoveringEntities: [UniverseId: Int] = [:] 25 | var discoveredEntities: Set = [] 26 | var discoveringPlanets: [PlanetId: Int] = [:] 27 | var discoveredPlanets: Set = [] 28 | 29 | var spriteNode: SKNode { 30 | get { 31 | return component(ofType: PlayerSpriteComponent.self)!.node 32 | } 33 | } 34 | 35 | var position = CGPoint.zero { 36 | didSet { 37 | let movement = SKAction.move(to: position, duration: 1.0) 38 | spriteNode.run(movement) 39 | spriteNode.position = position 40 | } 41 | } 42 | 43 | var isInMovement: Bool { 44 | return component(ofType: PlayerMovementComponent.self) != nil 45 | } 46 | 47 | init(name: String) { 48 | self.name = name 49 | super.init() 50 | 51 | addComponent(PlayerSpriteComponent()) 52 | } 53 | 54 | required init?(coder aDecoder: NSCoder) { 55 | fatalError("init(coder:) has not been implemented") 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/viewControllers/GameViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameViewController.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SpriteKit 11 | import GameplayKit 12 | 13 | class MainViewController: UIViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | if let scene = GKScene(fileNamed: "UniverseScene") { 19 | if let sceneNode = scene.rootNode as! UniverseScene? { 20 | sceneNode.scaleMode = .aspectFill 21 | if let view = view as! SKView? { 22 | view.presentScene(sceneNode) 23 | 24 | view.ignoresSiblingOrder = true 25 | 26 | view.showsFPS = true 27 | view.showsNodeCount = true 28 | } 29 | } 30 | } 31 | } 32 | 33 | override var shouldAutorotate: Bool { 34 | return true 35 | } 36 | 37 | override var supportedInterfaceOrientations: UIInterfaceOrientationMask { 38 | if UIDevice.current.userInterfaceIdiom == .phone { 39 | return .allButUpsideDown 40 | } else { 41 | return .all 42 | } 43 | } 44 | 45 | override func didReceiveMemoryWarning() { 46 | super.didReceiveMemoryWarning() 47 | // Release any cached data, images, etc that aren't in use. 48 | } 49 | 50 | override var prefersStatusBarHidden: Bool { 51 | return true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/resources/modifiers/planetResourcesModifier.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Desert 6 | 7 | Food 8 | 1 9 | Mineral 10 | 3 11 | Energy 12 | 1 13 | Research 14 | 1 15 | 16 | Toxic 17 | 18 | Food 19 | 0 20 | Mineral 21 | 3 22 | Energy 23 | 1 24 | Research 25 | 0 26 | 27 | Frozen 28 | 29 | Food 30 | 1 31 | Mineral 32 | 1 33 | Energy 34 | 1 35 | Research 36 | 1 37 | 38 | Volcanic 39 | 40 | Food 41 | 0 42 | Mineral 43 | 3 44 | Energy 45 | 2 46 | Research 47 | 1 48 | 49 | Oceanic 50 | 51 | Food 52 | 3 53 | Mineral 54 | 1 55 | Energy 56 | 1 57 | Research 58 | 2 59 | 60 | Continental 61 | 62 | Food 63 | 2 64 | Mineral 65 | 2 66 | Energy 67 | 2 68 | Research 69 | 3 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/universe/SystemEntity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // System.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class SystemEntity: UniverseEntity { 12 | 13 | private var _planets = [PlanetEntity]() 14 | 15 | var planets: [PlanetEntity] { 16 | get { 17 | return _planets 18 | } 19 | } 20 | 21 | override var travelTimeDay: Int { 22 | return 5 23 | } 24 | 25 | var star = StarEntity(name: "Star") 26 | 27 | override var description: String { 28 | get { 29 | return "System: \(id.name), Planets: \(planetsCount())" 30 | } 31 | } 32 | 33 | override var extraInfo: String? { 34 | get { 35 | var text = "" 36 | for planet in planets { 37 | text += "\(planet.name): \(planet.kind.name()), " 38 | } 39 | return text 40 | } 41 | } 42 | 43 | public override init(location: Location) { 44 | super.init(location: location) 45 | 46 | makePlanets() 47 | } 48 | 49 | required init?(coder aDecoder: NSCoder) { 50 | fatalError("init(coder:) has not been implemented") 51 | } 52 | 53 | private func makePlanets() { 54 | let planetsCount = Int(arc4random_uniform(6)) 55 | for index in 0...planetsCount { 56 | let star = PlanetEntity(in: self, order: index) 57 | _planets.append(star) 58 | } 59 | } 60 | 61 | func planet(at: Int) -> PlanetEntity { 62 | return _planets[at] 63 | } 64 | 65 | func planetsCount() -> Int { 66 | return _planets.count 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/Modal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Modal.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import SpriteKit 12 | 13 | class ModalUI { 14 | 15 | fileprivate static var systemUIShown = false 16 | fileprivate static var selectionUIShown = false 17 | fileprivate static var _systemUI: SystemUI? 18 | fileprivate static var _selectionUI: SelectionMenu? 19 | 20 | static var systemUI: SystemUI! { 21 | if _systemUI == nil { 22 | _systemUI = SystemUI.loadFromNib() 23 | _systemUI!.isHidden = true 24 | } 25 | return _systemUI! 26 | } 27 | 28 | static var selectionUI: SelectionMenu! { 29 | if _selectionUI == nil { 30 | _selectionUI = SelectionMenu.loadFromNib() 31 | _selectionUI!.isHidden = true 32 | } 33 | return _selectionUI! 34 | } 35 | 36 | static func presentSystemUI(from: SKScene, delegate: SystemUiDelegate) { 37 | if (!systemUIShown) { 38 | systemUIShown = true 39 | from.view?.addSubview(systemUI) 40 | systemUI.delegate = delegate 41 | systemUI.show() 42 | } 43 | } 44 | 45 | static func dismissSystemUI() { 46 | systemUI.hide() 47 | systemUIShown = false 48 | } 49 | 50 | static func presentSelectionUI(from: SKScene) { 51 | if(!selectionUIShown) { 52 | selectionUIShown = true 53 | from.view?.addSubview(selectionUI) 54 | selectionUI.isHidden = false 55 | } 56 | } 57 | 58 | static func dismissSelectionUI() { 59 | selectionUI.isHidden = true 60 | selectionUIShown = false 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/reducers/UIReducer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIState.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | func uiReducer(state: UIState?, action: Action) -> UIState { 13 | var state = state ?? UIState(selectedEntity: nil, 14 | selectedSystem: nil, 15 | selectedPlanet: nil, 16 | currentModal: .none, 17 | currentScene: .universe, 18 | selectedNode: nil) 19 | switch action { 20 | case let action as UIActions.ShowSelectedSystemModal: 21 | state.selectedSystem = action.system 22 | state.currentModal = .system 23 | 24 | case let action as UIActions.ShowSelectionModal: 25 | state.selectedEntity = action.entity 26 | state.currentModal = .entity 27 | 28 | case let action as UIActions.ShowPlanetDetail: 29 | state.selectedPlanet = action.planet 30 | state.currentScene = .planet 31 | state.currentModal = .none 32 | 33 | case _ as UIActions.ShowUniverseScene: 34 | state.selectedPlanet = nil 35 | state.selectedSystem = nil 36 | state.currentScene = .universe 37 | state.currentModal = .none 38 | 39 | case _ as UIActions.DismissModal: 40 | state.currentModal = .none 41 | state.selectedSystem = nil 42 | state.selectedEntity = nil 43 | 44 | case let action as UIActions.SetSelectedNode: 45 | state.selectedNode = action.node 46 | 47 | case _ as UIActions.RemoveSelectedNode: 48 | state.selectedNode = nil 49 | 50 | default: 51 | break 52 | } 53 | return state 54 | } 55 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/bodies/StarEntity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Star.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class StarEntity: SystemBody { 12 | 13 | enum Kind: UInt32 { 14 | case nova, supernova, dwarf 15 | 16 | private static let _count: Kind.RawValue = { 17 | var maxValue: UInt32 = 0 18 | while let _ = Kind(rawValue: maxValue) { 19 | maxValue += 1 20 | } 21 | return maxValue 22 | }() 23 | 24 | static func randomKind() -> Kind { 25 | let rand = arc4random_uniform(_count) 26 | return Kind(rawValue: rand)! 27 | } 28 | 29 | func name() -> String { 30 | return ResourcesLoader.loadArrayTextResource(name: "starsText")![Int(rawValue)] 31 | } 32 | 33 | func imageName() -> String { 34 | return "Star" 35 | } 36 | func image() -> UIImage { 37 | return #imageLiteral(resourceName: "Star") 38 | } 39 | 40 | func textureFillColor() -> UIColor { 41 | switch self { 42 | case .nova: 43 | return UIColor(red: 5/255, green: 22/255, blue: 177/255, alpha: 1.0) 44 | case .dwarf: 45 | return UIColor(red: 248/255, green: 187/255, blue: 66/255, alpha: 1.0) 46 | case .supernova: 47 | return UIColor(red: 199/255, green: 20/255, blue: 21/255, alpha: 1.0) 48 | } 49 | } 50 | } 51 | 52 | let kind: Kind 53 | 54 | public override init(name: String) { 55 | kind = Kind.randomKind() 56 | super.init(name: name) 57 | } 58 | 59 | required init?(coder aDecoder: NSCoder) { 60 | fatalError("init(coder:) has not been implemented") 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/TopBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TopBar.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ReSwift 11 | 12 | class TopBar: BaseUI { 13 | 14 | @IBOutlet var dateLabel: UILabel! 15 | @IBOutlet var playButton: UIButton! 16 | @IBOutlet var speedButton: UIButton! 17 | 18 | @IBOutlet var energyIcon: UIImageView! 19 | @IBOutlet var energyLabel: UILabel! 20 | 21 | @IBOutlet var mineralIcon: UIImageView! 22 | @IBOutlet var mineralLabel: UILabel! 23 | 24 | @IBOutlet var scienceIcon: UIImageView! 25 | @IBOutlet var scienceLabel: UILabel! 26 | 27 | override func didMoveToSuperview() { 28 | super.didMoveToSuperview() 29 | 30 | layer.cornerRadius = 0 31 | 32 | store.subscribe(self) { 33 | $0.select{ $0.playerState }.skipRepeats() 34 | } 35 | } 36 | 37 | @IBAction func onPlayButton(_ sender: Any) { 38 | if store.state.playerState.isPlaying { 39 | store.dispatch(PlayerActions.PauseTimer()) 40 | } 41 | else { 42 | store.dispatch(PlayerActions.StartTimer()) 43 | } 44 | } 45 | 46 | @IBAction func onSpeedButton(_ sender: Any) { 47 | store.dispatch(PlayerActions.UpdateSpeed(speed: store.state.playerState.currentSpeed.nextValue())) 48 | } 49 | } 50 | 51 | extension TopBar: StoreSubscriber { 52 | func newState(state: PlayerState) { 53 | let dateFormatter = DateFormatter() 54 | dateFormatter.dateFormat = "dd/MM/yyyy" 55 | dateLabel.text = dateFormatter.string(from: state.currentDate) 56 | playButton.setTitle(state.isPlaying ? "||" : ">", for: .normal) 57 | speedButton.setTitle("x\(state.currentSpeed.displayValue())", for: .normal) 58 | energyLabel.text = "\(state.player.resources.energy.value)" 59 | mineralLabel.text = "\(state.player.resources.minerals.value)" 60 | scienceLabel.text = "\(state.player.resources.science.value)" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/selection menu/SelectionMenu.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SelectionMenu.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 01/04/2018. 6 | // Copyright © 2018 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import UI 11 | 12 | class SelectionMenu: BaseUI { 13 | enum MenuType: Int { 14 | case unknown 15 | 16 | func datasource() -> [String] { 17 | switch self { 18 | case .unknown: 19 | return ["Survey", "Cancel"] 20 | } 21 | } 22 | } 23 | 24 | @IBOutlet var tableView: UITableView! 25 | 26 | var menuType = MenuType.unknown 27 | 28 | override func awakeFromNib() { 29 | super.awakeFromNib() 30 | 31 | let nib = UINib(nibName: SelectionMenuTableViewCell.id, bundle: Bundle.main) 32 | tableView.register(nib, forCellReuseIdentifier: SelectionMenuTableViewCell.id) 33 | } 34 | 35 | override func didMoveToSuperview() { 36 | super.didMoveToSuperview() 37 | 38 | frame = CGRect(x: 0, y: 0, width: 300, height: 200) 39 | center = superview!.center 40 | } 41 | } 42 | 43 | extension SelectionMenu: UITableViewDelegate, UITableViewDataSource { 44 | func numberOfSections(in tableView: UITableView) -> Int { 45 | return 1 46 | } 47 | 48 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 49 | return menuType.datasource().count 50 | } 51 | 52 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 53 | let cell = tableView.dequeueReusableCell(withIdentifier: SelectionMenuTableViewCell.id, 54 | for: indexPath) as! SelectionMenuTableViewCell 55 | cell.menuLabel.text = menuType.datasource()[indexPath.row] 56 | return cell 57 | } 58 | 59 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 60 | tableView.deselectRow(at: indexPath, animated: true) 61 | if indexPath.row == 0, let entity = store.state.uiState.selectedEntity { 62 | store.dispatch(PlayerActions.startDiscoveryUniverseEntity(entity: entity.id)) 63 | } 64 | store.dispatch(UIActions.DismissModal()) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/helpers/ResourcesLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResourcesLoader.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 24/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class ResourcesLoader { 13 | 14 | static func loadDicResource(name: String) -> [String: AnyObject]? { 15 | if let path = Bundle.main.path(forResource: name, ofType: "plist"), 16 | let dic = NSDictionary(contentsOfFile: path) as? [String : AnyObject] { 17 | return dic 18 | } 19 | return nil 20 | } 21 | 22 | static func loadTextResource(name: String) -> [String : String]? { 23 | if let path = Bundle.main.path(forResource: name, ofType: "plist"), 24 | let dic = NSDictionary(contentsOfFile: path) as? [String : String] { 25 | return dic 26 | } 27 | return nil 28 | } 29 | 30 | static func loadArrayTextResource(name: String) -> [String]? { 31 | if let path = Bundle.main.path(forResource: name, ofType: "plist"), 32 | let dic = NSArray(contentsOfFile: path) as? [String] { 33 | return dic 34 | } 35 | return nil 36 | } 37 | 38 | static func loadModifierResource(name: String) -> [String : Float]? { 39 | if let path = Bundle.main.path(forResource: name, ofType: "plist"), 40 | let dic = NSDictionary(contentsOfFile: path) as? [String : Float] { 41 | return dic 42 | } 43 | return nil 44 | } 45 | 46 | static func loadDimensionResource(name: String, dimensionName: String) -> Size? { 47 | if let path = Bundle.main.path(forResource: name, ofType: "plist"), 48 | let dic = NSDictionary(contentsOfFile: path) { 49 | if let sizeDic = dic[dimensionName] as? [String: Int], 50 | let width = sizeDic["width"], 51 | let height = sizeDic["height"] { 52 | return Size(width: Int32(width), height: Int32(height)) 53 | } 54 | } 55 | return nil 56 | } 57 | 58 | static func loadPlanetResource(name: String) -> [String: [String: Int]]? { 59 | if let path = Bundle.main.path(forResource: name, ofType: "plist"), 60 | let dic = NSDictionary(contentsOfFile: path) as? [String: [String: Int]] { 61 | return dic 62 | } 63 | return nil 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/player/components/PlayerMovementComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlayerMovementComponent.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 09/10/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import GameplayKit 11 | import ReSwift 12 | 13 | class PlayerMovementComponent: GKComponent { 14 | 15 | let startDate: Date 16 | let startLocation: Location 17 | let endLocation: Location 18 | 19 | var travelPath: [GKGraphNode] = [] 20 | var previousDate: Date 21 | 22 | init(startDate: Date, from: Location, to: Location) { 23 | self.startDate = startDate 24 | self.startLocation = from 25 | self.endLocation = to 26 | self.previousDate = startDate 27 | super.init() 28 | } 29 | 30 | required init?(coder aDecoder: NSCoder) { 31 | fatalError("init(coder:) has not been implemented") 32 | } 33 | 34 | override func didAddToEntity() { 35 | super.didAddToEntity() 36 | 37 | if let universe = store.state.universeState.universe { 38 | if let startNode = universe.nodeAt(location: startLocation), 39 | let endNode = universe.nodeAt(location: endLocation) { 40 | for node in startNode.findPath(to: endNode) { 41 | if let node = node as? UniverseNode { 42 | for _ in 0.. PlayerState { 13 | var state = state ?? PlayerState() 14 | 15 | switch action { 16 | case _ as PlayerActions.Initialize: 17 | let gridNodes = store.state.universeState.universe!.grid.nodes! 18 | let randomNodeIndex = arc4random_uniform(UInt32(gridNodes.count)) 19 | if let node = gridNodes[Int(randomNodeIndex)] as? UniverseNode { 20 | state.player.discoveredEntities.insert(node.entity.id) 21 | state.player.position = Universe.grideNodePositionToMapPosition(gridNode: node) 22 | } 23 | case let action as PlayerActions.StartTimer: 24 | state.dateTimer = action.timer 25 | state.isPlaying = true 26 | case let action as PlayerActions.UpdateSpeed: 27 | state.currentSpeed = action.speed 28 | case let action as PlayerActions.UpdateTimer: 29 | state.dateTimer = action.timer 30 | state.currentDate = Calendar.current.date(byAdding: .day, value: 1, to: state.currentDate)! 31 | state.isPlaying = true 32 | 33 | //Player operation 34 | if let universe = store.state.universeState.universe { 35 | let mapcCopy = state.player.discoveringEntities 36 | mapcCopy.forEach { (params) in 37 | let (id, progress) = params 38 | let entity = universe.entityAt(location: id.location) 39 | if progress == entity.dayToDiscover { 40 | state.player.discoveringEntities.removeValue(forKey: id) 41 | state.player.discoveredEntities.insert(id) 42 | } else { 43 | state.player.discoveringEntities[id] = progress + 1 44 | } 45 | } 46 | } 47 | 48 | case _ as PlayerActions.UpdateTimerMonth: 49 | state.player.resources.update() 50 | case _ as PlayerActions.PauseTimer: 51 | state.dateTimer?.invalidate() 52 | state.dateTimer = nil 53 | state.isPlaying = false 54 | case let action as PlayerActions.MoveToPosition: 55 | state.player.addComponent(action.movement) 56 | case _ as PlayerActions.StopMovement: 57 | state.player.removeComponent(ofType: PlayerMovementComponent.self) 58 | case let action as PlayerActions.UpdatePosition: 59 | state.player.position = action.position 60 | case let action as PlayerActions.startDiscoveryUniverseEntity: 61 | state.player.discoveringEntities[action.entity] = 0 62 | default: 63 | break 64 | } 65 | return state 66 | } 67 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/universe/components/UniverseSpriteComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UniverseSpriteComponent.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 25/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class UniverseSpriteComponent: GKSKNodeComponent { 12 | 13 | static let size = ResourcesLoader.loadDimensionResource(name: "universeDimensions", dimensionName: "node")! 14 | static let nodeSize = CGSize(width: Int(UniverseSpriteComponent.size.width), height: Int(UniverseSpriteComponent.size.height)) 15 | 16 | static public func component(with entity: UniverseEntity) -> UniverseSpriteComponent { 17 | var component: UniverseSpriteComponent 18 | let node = SKShapeNode(rect: CGRect(x: 0, y: 0, width: nodeSize.width, height: nodeSize.height)) 19 | node.lineWidth = 0.50 20 | node.strokeColor = UIColor.init(white: 1.0, alpha: 0.5) 21 | node.fillColor = node.undiscovedColor 22 | if let _ = entity as? SystemEntity { 23 | node.name = "System node" 24 | } else { 25 | node.name = "Empty node" 26 | } 27 | component = UniverseSpriteComponent(node: node) 28 | return component 29 | 30 | } 31 | 32 | override func update(deltaTime seconds: TimeInterval) { 33 | if let universeEntity = entity as? UniverseEntity, let node = node as? SKShapeNode { 34 | let discovered = universeEntity.discovered 35 | if let systemEntity = universeEntity as? SystemEntity, discovered { 36 | if node.fillTexture == nil { 37 | let texture = SKTexture(imageNamed: systemEntity.star.kind.imageName()) 38 | node.fillTexture = texture 39 | } 40 | node.fillColor = systemEntity.star.kind.textureFillColor() 41 | node.strokeColor = .red 42 | node.glowWidth = 3 43 | } else { 44 | node.fillColor = discovered ? .clear : node.undiscovedColor 45 | node.glowWidth = discovered ? 2 : 0 46 | node.strokeColor = UIColor.init(white: 1.0, alpha: 0.5) 47 | } 48 | 49 | if let dayProgress = store.state.playerState.player.discoveringEntities[universeEntity.id] { 50 | let progress = Float(dayProgress) / Float(universeEntity.dayToDiscover) 51 | node.strokeColor = UIColor.green.withAlphaComponent(CGFloat(progress)) 52 | } 53 | 54 | if node == store.state.uiState.selectedNode { 55 | node.glowWidth = 5 56 | } 57 | 58 | if let movement = store.state.playerState.player.component(ofType: PlayerMovementComponent.self) { 59 | // TODO: Highlight node for player movement 60 | } 61 | } 62 | } 63 | 64 | } 65 | 66 | extension SKShapeNode { 67 | 68 | var undiscovedColor: UIColor { 69 | return UIColor.gray.withAlphaComponent(0.3) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/flux/actions/PlayerActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlayerActions.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/01/2017. 6 | // Copyright © 2017 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReSwift 11 | 12 | class PlayerActions { 13 | struct Initialize: Action {} 14 | 15 | struct StartTimer: Action { 16 | var timer: Timer! 17 | var currentDate: Date! 18 | 19 | init() { 20 | self.currentDate = store.state.playerState.currentDate 21 | let speed = store.state.playerState.currentSpeed 22 | var copy = self 23 | self.timer = Timer.scheduledTimer(withTimeInterval: speed.rawValue, repeats: true, block: { (timer) in 24 | if store.state.playerState.isPlaying { 25 | store.dispatch(UpdateTimer(timer: timer)) 26 | copy.currentDate = store.state.playerState.currentDate 27 | if Calendar.current.isDate(copy.currentDate, equalTo: copy.endOfMonth(), toGranularity: .day) { 28 | store.dispatch(UpdateTimerMonth(timer: timer)) 29 | } 30 | } 31 | }) 32 | } 33 | 34 | func startOfMonth() -> Date { 35 | return Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], 36 | from: Calendar.current.startOfDay(for: 37 | currentDate)))! 38 | } 39 | 40 | func endOfMonth() -> Date { 41 | return Calendar.current.date(byAdding: DateComponents(month: 1, day: -1), to: self.startOfMonth())! 42 | } 43 | } 44 | 45 | struct UpdateSpeed: Action { 46 | let speed: PlayerSpeed 47 | 48 | init(speed: PlayerSpeed) { 49 | self.speed = speed 50 | 51 | // Hacky workaround to wait for the init to be done so the state is up to date when restarting the timer. 52 | // Will do better later. 53 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { 54 | store.dispatch(PauseTimer()) 55 | store.dispatch(StartTimer()) 56 | } 57 | } 58 | } 59 | 60 | struct UpdateTimer: Action { 61 | let timer: Timer 62 | 63 | init(timer: Timer) { 64 | self.timer = timer 65 | } 66 | } 67 | 68 | struct UpdateTimerMonth: Action { 69 | let timer: Timer 70 | 71 | init(timer: Timer) { 72 | self.timer = timer 73 | } 74 | } 75 | 76 | struct MoveToPosition: Action { 77 | let movement: PlayerMovementComponent 78 | } 79 | 80 | struct UpdatePosition: Action { 81 | let position: CGPoint 82 | } 83 | 84 | struct startDiscoveryUniverseEntity: Action { 85 | let entity: UniverseId 86 | } 87 | 88 | struct StopMovement: Action {} 89 | 90 | struct PauseTimer: Action { 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/viewControllers/PlanetViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlanetViewController.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 29/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SceneKit 11 | import ReSwift 12 | 13 | class PlanetViewController: UIViewController { 14 | 15 | let planet: PlanetEntity 16 | 17 | var mainScene: SCNScene! = nil 18 | var mainSceneView: SCNView! = nil 19 | 20 | init(){ 21 | planet = store.state.uiState.selectedPlanet! 22 | super.init(nibName: nil, bundle: nil) 23 | 24 | } 25 | 26 | required init?(coder aDecoder: NSCoder) { 27 | fatalError("init(coder:) has not been implemented") 28 | } 29 | 30 | override func viewDidLoad() { 31 | super.viewDidLoad() 32 | 33 | store.subscribe(self) { 34 | $0.select{ $0.uiState }.skipRepeats() 35 | } 36 | 37 | setupScene() 38 | setupCloseButton() 39 | } 40 | } 41 | 42 | // MARK: - State 43 | extension PlanetViewController: StoreSubscriber { 44 | func newState(state: UIState) { 45 | if state.currentScene != .planet { 46 | self.dismiss(animated: true, completion: nil) 47 | } 48 | } 49 | } 50 | 51 | // MARK: - Action 52 | extension PlanetViewController { 53 | 54 | @objc func onClose() { 55 | store.dispatch(UIActions.ShowUniverseScene()) 56 | } 57 | } 58 | 59 | // MARK: - Setup 60 | extension PlanetViewController { 61 | 62 | func setupCloseButton() { 63 | let button = UIButton(type: .custom) 64 | button.setTitle("Close", for: .normal) 65 | button.setTitleColor(UIColor.white, for: .normal) 66 | button.frame = CGRect(x: view.frame.size.width - 70, y: 15.0, width: 60, height: 30) 67 | button.addTarget(self, action: #selector(onClose), for: .touchUpInside) 68 | view.addSubview(button) 69 | } 70 | 71 | func setupScene() { 72 | 73 | mainSceneView = SCNView(frame: view.bounds) 74 | view.addSubview(mainSceneView) 75 | 76 | mainScene = SCNScene() 77 | mainScene.background.contents = planet.planet3D.skybox 78 | 79 | setupLight() 80 | setupCamera() 81 | 82 | mainSceneView.scene = mainScene 83 | 84 | mainScene.rootNode.addChildNode(SCNNode(geometry: planet.planet3D.sphere)) 85 | } 86 | 87 | func setupLight() { 88 | let lightNode = SCNNode() 89 | lightNode.light = SCNLight() 90 | lightNode.light?.type = .ambient 91 | lightNode.light?.color = UIColor(white: 0.37, alpha: 1.0) 92 | lightNode.position = SCNVector3Make(0, 50, 50) 93 | 94 | mainScene.rootNode.addChildNode(lightNode) 95 | 96 | 97 | mainScene.rootNode.addChildNode(planet.planet3D.light) 98 | } 99 | 100 | func setupCamera() { 101 | mainSceneView.allowsCameraControl = true 102 | 103 | let cameraNode = SCNNode() 104 | cameraNode.camera = SCNCamera() 105 | cameraNode.position = SCNVector3Make(0, 0, 20) 106 | 107 | mainScene.rootNode.addChildNode(cameraNode) 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/selection menu/cells/SelectionMenuTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/SystemUI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SystemUI.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 25/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ReSwift 11 | 12 | class StarCell: UITableViewCell { 13 | static let id = "starCell" 14 | 15 | @IBOutlet var starImageView: UIImageView! 16 | @IBOutlet var starTitleLabel: UILabel! 17 | @IBOutlet var kindTitleLabel: UILabel! 18 | 19 | public var planet: PlanetEntity? { 20 | didSet { 21 | starTitleLabel.text = "\(planet!.name) (\(planet!.kind.name()))" 22 | let radius = String(format: "%.0f", planet!.radius) 23 | kindTitleLabel.text = "Score: \(planet!.resourceScore) | Radius: \(radius) Km" 24 | starImageView.image = planet!.kind.image() 25 | starImageView.transform = CGAffineTransform(scaleX: planet!.scale, y: planet!.scale) 26 | } 27 | } 28 | } 29 | 30 | protocol SystemUiDelegate { 31 | func systemUISelectedPlanet(planet: PlanetEntity) 32 | } 33 | 34 | class SystemUI: BaseUI, UITableViewDelegate, UITableViewDataSource, StoreSubscriber { 35 | 36 | @IBOutlet var titleLabel: UILabel! 37 | @IBOutlet var starName: UILabel! 38 | @IBOutlet var starImageView: UIImageView! 39 | @IBOutlet var tableView: UITableView! 40 | 41 | var delegate: SystemUiDelegate? 42 | 43 | public var system: SystemEntity? { 44 | didSet { 45 | if let system = system { 46 | titleLabel.text = system.description 47 | starName.text = "Star: \(system.star.kind.name())" 48 | starImageView.image = system.star.kind.image() 49 | tableView.reloadData() 50 | } 51 | } 52 | } 53 | 54 | public func show() { 55 | system = store.state.uiState.selectedSystem 56 | store.subscribe(self) { 57 | $0.select{ $0.uiState }.skipRepeats() 58 | } 59 | isHidden = false 60 | alpha = 0 61 | layer.transform = CATransform3DMakeScale(0.2, 0.2, 0.2) 62 | UIView.animate(withDuration: 0.50, 63 | delay: 0, 64 | usingSpringWithDamping: 0.8, 65 | initialSpringVelocity: 15, 66 | options: .curveEaseInOut, animations: { 67 | self.alpha = 1 68 | self.layer.transform = CATransform3DMakeScale(1.0, 1.0, 1.0) 69 | }, completion: nil) 70 | } 71 | 72 | public func hide() { 73 | store.unsubscribe(self) 74 | UIView.animate(withDuration: 0.30, animations: { 75 | self.alpha = 0 76 | self.layer.transform = CATransform3DMakeScale(0.2, 0.2, 0.2) 77 | }, completion: {(success) in 78 | self.isHidden = true 79 | }) 80 | } 81 | 82 | override func didMoveToSuperview() { 83 | super.didMoveToSuperview() 84 | 85 | frame = CGRect(x: 0, y: 0, width: 300, height: 400) 86 | center = superview!.center 87 | 88 | tableView.register(UINib(nibName: "StarCell", bundle: Bundle.main), 89 | forCellReuseIdentifier: StarCell.id) 90 | tableView.rowHeight = 60 91 | } 92 | 93 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 94 | if let system = system { 95 | return system.planetsCount() 96 | } 97 | return 0 98 | } 99 | 100 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 101 | let cell = tableView.dequeueReusableCell(withIdentifier: StarCell.id, for: indexPath) as! StarCell 102 | cell.planet = system!.planet(at: indexPath.row) 103 | return cell 104 | } 105 | 106 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 107 | tableView.deselectRow(at: indexPath, animated: true) 108 | if let delegate = delegate { 109 | delegate.systemUISelectedPlanet(planet: system!.planet(at: indexPath.row)) 110 | } 111 | } 112 | 113 | func newState(state: UIState) { 114 | if system != state.selectedSystem { 115 | system = state.selectedSystem 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/outliner/Outliner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Outliner.swift 3 | // LittleOrion 4 | // 5 | // Created by Thomas Ricouard on 26/03/2018. 6 | // Copyright © 2018 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ReSwift 11 | 12 | protocol OutlinerDelegate: class { 13 | func outlinerDidChangeExpanded(outliner: Outliner, expanded: Bool) 14 | func outlinerDidSelectSystem(outliner: Outliner, system: UniverseId) 15 | } 16 | 17 | class Outliner: BaseUI { 18 | 19 | @IBOutlet var expandButton: UIButton! 20 | @IBOutlet var tableView: UITableView! 21 | 22 | var researchingSystems: [[UniverseId: Int]] = [] { 23 | didSet { 24 | if researchingSystems != oldValue { 25 | tableView.reloadData() 26 | } 27 | } 28 | } 29 | var discoveredSystems: [UniverseId] = [] { 30 | didSet { 31 | if discoveredSystems != oldValue { 32 | tableView.reloadData() 33 | } 34 | } 35 | } 36 | 37 | weak var delegate: OutlinerDelegate? 38 | 39 | let sections = ["Researching", "Systems", "Planets"] 40 | 41 | var expanded = false { 42 | didSet { 43 | delegate?.outlinerDidChangeExpanded(outliner: self, expanded: expanded) 44 | } 45 | } 46 | 47 | override func didMoveToSuperview() { 48 | super.didMoveToSuperview() 49 | 50 | tableView.register(UINib(nibName: OutlinerSystemTableViewCell.id, bundle: Bundle.main), 51 | forCellReuseIdentifier: OutlinerSystemTableViewCell.id) 52 | tableView.backgroundColor = .clear 53 | 54 | store.subscribe(self) { 55 | $0.select{ $0.playerState }.skipRepeats() 56 | } 57 | } 58 | 59 | @IBAction func onExpandButton(_ sender: Any) { 60 | expanded = !expanded 61 | } 62 | } 63 | 64 | extension Outliner: StoreSubscriber { 65 | func newState(state: PlayerState) { 66 | researchingSystems = state.player.discoveringEntities.compactMap({ [$0: $1] }) 67 | discoveredSystems = state.player.discoveredEntities.filter({ store.state.universeState.universe!.entityAt(location: $0.location) is SystemEntity }) 68 | } 69 | } 70 | 71 | extension Outliner: UITableViewDelegate, UITableViewDataSource { 72 | func numberOfSections(in tableView: UITableView) -> Int { 73 | return sections.count 74 | } 75 | 76 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 77 | if section == 0 { 78 | return researchingSystems.count 79 | } 80 | else if section == 1 { 81 | return discoveredSystems.count 82 | } 83 | return 0 84 | } 85 | 86 | func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 87 | return sections[section] 88 | } 89 | 90 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 91 | return 44 92 | } 93 | 94 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 95 | if let cell = tableView.dequeueReusableCell(withIdentifier: OutlinerSystemTableViewCell.id) as? OutlinerSystemTableViewCell { 96 | if indexPath.section == 0 { 97 | let system = researchingSystems[indexPath.row] 98 | cell.systemName.text = system.first!.key.name 99 | cell.systemDiscoveryProgress.isHidden = false 100 | let progress = system.first!.value 101 | cell.systemDiscoveryProgress.progress = Float(progress) / Float(UniverseEntity.dayToDisover) 102 | } else if indexPath.section == 1 { 103 | cell.systemName.text = discoveredSystems[indexPath.row].name 104 | cell.systemDiscoveryProgress.isHidden = true 105 | } 106 | return cell 107 | } 108 | return UITableViewCell(frame: CGRect.zero) 109 | } 110 | 111 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 112 | if indexPath.section == 0 { 113 | let system = researchingSystems[indexPath.row] 114 | delegate?.outlinerDidSelectSystem(outliner: self, system: system.first!.key) 115 | } else if indexPath.section == 1 { 116 | let system = discoveredSystems[indexPath.row] 117 | delegate?.outlinerDidSelectSystem(outliner: self, system: system) 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/outliner/cells/OutlinerSystemTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/selection menu/SelectionMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/StarCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/universe/UniverseEntity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Universe.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | 11 | class UniverseRules { 12 | 13 | private static let dic = ResourcesLoader.loadDicResource(name: "universeRules")! 14 | 15 | static let systemSpawnProbability: UInt32 = dic["systemSpwawnProbability"] as! UInt32 16 | static let basePlanetsRadius: CGFloat = dic["basePlanetsRadius"] as! CGFloat 17 | static let superPlanetSpwawnProbability: UInt32 = dic["superPlanetSpwawnProbability"] as! UInt32 18 | static let superPlanetScale: CGFloat = dic["superPlanetScale"] as! CGFloat 19 | static let planetMaxSpace: Int = dic["planetMaxSpace"] as! Int 20 | 21 | } 22 | 23 | class UniverseNode: GKGridGraphNode { 24 | var entity: UniverseEntity! 25 | } 26 | 27 | struct UniverseId: Equatable, Hashable { 28 | let location: Location 29 | var name: String { 30 | get { 31 | return "Node x:\(location.x) y:\(location.y)" 32 | } 33 | } 34 | var hashValue: Int { 35 | get { 36 | return name.hashValue 37 | } 38 | } 39 | 40 | init(location: Location) { 41 | self.location = location 42 | } 43 | } 44 | 45 | class UniverseEntity: GKEntity, Travelable, Discoverable { 46 | 47 | var id: UniverseId 48 | static let dayToDisover = 10 49 | 50 | var spriteNode: SKNode { 51 | get { 52 | return (component(ofType: UniverseSpriteComponent.self)?.node)! 53 | } 54 | } 55 | 56 | var travelTimeDay: Int { 57 | return 0 58 | } 59 | 60 | var discovered: Bool { 61 | return store.state.playerState.player.discoveredEntities.contains(id) 62 | } 63 | 64 | var dayToDiscover: Int { 65 | return UniverseEntity.dayToDisover 66 | } 67 | 68 | override var description: String { 69 | get { 70 | return "Default Universe Entity" 71 | } 72 | } 73 | 74 | var extraInfo: String? { 75 | get { 76 | return nil 77 | } 78 | } 79 | 80 | public init(location: Location) { 81 | self.id = UniverseId(location: location) 82 | super.init() 83 | addComponent(UniverseSpriteComponent.component(with: self)) 84 | } 85 | 86 | required init?(coder aDecoder: NSCoder) { 87 | fatalError("init(coder:) has not been implemented") 88 | } 89 | 90 | } 91 | 92 | class Universe: GKEntity { 93 | 94 | let size: Size 95 | let grid: GKGridGraph 96 | 97 | enum UniverseSize: String { 98 | case tiny, small, standard, big 99 | 100 | func size() -> Size { 101 | return ResourcesLoader.loadDimensionResource(name: "universeDimensions", dimensionName: rawValue)! 102 | } 103 | } 104 | 105 | public init(size: UniverseSize) { 106 | self.size = size.size() 107 | self.grid = GKGridGraph(fromGridStartingAt: int2(0, 0), 108 | width: self.size.width, 109 | height: self.size.height, 110 | diagonalsAllowed: true, nodeClass: UniverseNode.self) 111 | super.init() 112 | 113 | generate() 114 | } 115 | 116 | required init?(coder aDecoder: NSCoder) { 117 | fatalError("init(coder:) has not been implemented") 118 | } 119 | 120 | private func generate() { 121 | for node in grid.nodes! { 122 | if let node = node as? UniverseNode { 123 | let location = Location(x: node.gridPosition.x, y: node.gridPosition.y) 124 | if arc4random_uniform(UniverseRules.systemSpawnProbability) == 1 { 125 | node.entity = SystemEntity(location: location) 126 | } else { 127 | node.entity = EmptyEntity(location: location) 128 | } 129 | } 130 | } 131 | 132 | for node in grid.nodes! { 133 | if let node = node as? UniverseNode { 134 | let neighboors = node.connectedNodes 135 | for neighboor in neighboors { 136 | if let neighboor = neighboor as? UniverseNode { 137 | if let _ = neighboor.entity as? SystemEntity, let _ = node.entity as? SystemEntity { 138 | let location = Location(x: node.gridPosition.x, y: node.gridPosition.y) 139 | neighboor.entity = EmptyEntity(location: location) 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | 147 | public func entityAt(location: Location) -> UniverseEntity { 148 | return grid.node(atGridPosition: int2(location.x, location.y))!.entity! 149 | } 150 | 151 | public func nodeAt(location: Location) -> UniverseNode? { 152 | return grid.node(atGridPosition: int2(location.x, location.y)) 153 | } 154 | 155 | public static func grideNodePositionToMapPosition(gridNode: UniverseNode) -> CGPoint { 156 | let size = UniverseSpriteComponent.nodeSize 157 | let position = CGPoint(x: CGFloat(CGFloat(gridNode.gridPosition.x) * size.width), 158 | y: CGFloat(CGFloat(gridNode.gridPosition.y) * size.height)) 159 | return position 160 | } 161 | 162 | public static func mapNodePositionToGridPosition(mapNode: SKNode) -> Location { 163 | let size = UniverseSpriteComponent.nodeSize 164 | let gridPosition = Location(x: Int32(Int32(mapNode.position.x) / Int32(size.width)), 165 | y: Int32(Int32(mapNode.position.y) / Int32(size.height))) 166 | return gridPosition 167 | } 168 | 169 | override func update(deltaTime seconds: TimeInterval) { 170 | super.update(deltaTime: seconds) 171 | 172 | for case let node as UniverseNode in grid.nodes! { 173 | node.entity.components.forEach({ $0.update(deltaTime: seconds) }) 174 | } 175 | } 176 | 177 | } 178 | 179 | func ==(lhs: Universe, rhs: Universe) -> Bool { 180 | return lhs.size == rhs.size && 181 | lhs.grid == rhs.grid 182 | } 183 | 184 | 185 | func ==(lhs: Universe?, rhs: Universe?) -> Bool { 186 | return false 187 | } 188 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/outliner/Outliner.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/BottomBar.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 32 | 41 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/SystemUI.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/models/space/bodies/PlanetEntity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Planet.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 25/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import GameplayKit 10 | import SceneKit 11 | 12 | struct PlanetId: Equatable, Hashable { 13 | let systemId: UniverseId 14 | let index: Int 15 | 16 | var hashValue: Int { 17 | get { 18 | return systemId.hashValue * index.hashValue 19 | } 20 | } 21 | 22 | init(systemId: UniverseId, index: Int) { 23 | self.systemId = systemId 24 | self.index = index 25 | } 26 | } 27 | 28 | //MARK: - Planet 29 | class PlanetEntity: SystemBody, Discoverable { 30 | 31 | static let planetRessourceModifier = ResourcesLoader.loadPlanetResource(name: "planetResourcesModifier")! 32 | static let planetNames = ResourcesLoader.loadArrayTextResource(name: "planetsText")! 33 | 34 | enum Kind: UInt32 { 35 | case desert, oceanic, toxic, continental, frozen, volcanic 36 | 37 | private static let _count: Kind.RawValue = { 38 | var maxValue: UInt32 = 0 39 | while let _ = Kind(rawValue: maxValue) { 40 | maxValue += 1 41 | } 42 | return maxValue 43 | }() 44 | 45 | static func randomKind() -> Kind { 46 | let rand = arc4random_uniform(_count) 47 | return Kind(rawValue: rand)! 48 | } 49 | 50 | func name() -> String { 51 | return planetNames[Int(rawValue)] 52 | } 53 | 54 | func image() -> UIImage { 55 | return UIImage(named: ResourcesLoader.loadArrayTextResource(name: "planetsText")![Int(rawValue)])! 56 | } 57 | 58 | func ressources() -> [String: Int] { 59 | return planetRessourceModifier[name()]! 60 | } 61 | 62 | } 63 | 64 | var discovered: Bool { 65 | return store.state.playerState.player.discoveredPlanets.contains(id) 66 | } 67 | 68 | var dayToDiscover: Int { 69 | return 200 70 | } 71 | 72 | let id: PlanetId 73 | let kind: Kind 74 | let scale: CGFloat 75 | var planet3D: Planet3D! = nil 76 | 77 | //resource 78 | let food: Food 79 | let energy: Energy 80 | let mineral: Mineral 81 | let reseach: Research 82 | 83 | var resourceScore: Int { 84 | get { 85 | return food.abundance.rawValue + 86 | energy.abundance.rawValue + 87 | mineral.abundance.rawValue + 88 | reseach.abundance.rawValue 89 | } 90 | } 91 | 92 | //The radius, in KM of the planet. 93 | var radius: CGFloat { 94 | get { 95 | return UniverseRules.basePlanetsRadius * scale 96 | } 97 | } 98 | 99 | //How many space are buildable on this planet. 100 | var space: Int { 101 | get { 102 | let divider = (UniverseRules.basePlanetsRadius * UniverseRules.superPlanetScale) / CGFloat(UniverseRules.planetMaxSpace) 103 | return Int(radius / divider) 104 | } 105 | } 106 | 107 | 108 | //A planet may or may not have inhabitants. 109 | private var inhabitants: [Pop]? 110 | 111 | //The parent system of the planet. 112 | let system: SystemEntity 113 | 114 | public init(in system: SystemEntity, order: Int) { 115 | id = PlanetId(systemId: system.id, index: order) 116 | self.system = system 117 | kind = Kind.randomKind() 118 | var tmpScale = CGFloat((arc4random_uniform(600) + 400)) / 1000 119 | if tmpScale > 0.9 && arc4random_uniform(UniverseRules.superPlanetSpwawnProbability) == 1 { 120 | //1 out of X chance to generate a super planet if scale is already big. 121 | tmpScale = UniverseRules.superPlanetScale 122 | } 123 | scale = tmpScale 124 | food = Food(abundance: PlanetResource.Abundance(rawValue: kind.ressources()["Food"]!)!) 125 | mineral = Mineral(abundance: PlanetResource.Abundance(rawValue: kind.ressources()["Mineral"]!)!) 126 | energy = Energy(abundance: PlanetResource.Abundance(rawValue: kind.ressources()["Energy"]!)!) 127 | reseach = Research(abundance: PlanetResource.Abundance(rawValue: kind.ressources()["Research"]!)!) 128 | 129 | super.init(name: "Planet \(order)") 130 | 131 | planet3D = Planet3D(planet: self) 132 | } 133 | 134 | required init?(coder aDecoder: NSCoder) { 135 | fatalError("init(coder:) has not been implemented") 136 | } 137 | 138 | func inhabitantsCount() -> Int { 139 | if let inhabitants = inhabitants { 140 | return inhabitants.count 141 | } 142 | return 0 143 | } 144 | 145 | func addInhabitants(pop: Pop) { 146 | if inhabitants == nil { 147 | inhabitants = [Pop]() 148 | } 149 | inhabitants?.append(pop) 150 | } 151 | } 152 | 153 | //MARK: - 3D 154 | class Planet3D { 155 | 156 | var skybox: [UIImage] { 157 | get { 158 | return [#imageLiteral(resourceName: "Skybox_PositiveX"), 159 | #imageLiteral(resourceName: "Skybox_NegativeX"), 160 | #imageLiteral(resourceName: "Skybox_PositiveY"), 161 | #imageLiteral(resourceName: "Skybox_NegativeY"), 162 | #imageLiteral(resourceName: "Skybox_PositiveZ"), 163 | #imageLiteral(resourceName: "Skybox_NegativeZ")] 164 | } 165 | } 166 | 167 | var sphere: SCNSphere { 168 | get { 169 | let sphere = SCNSphere(radius: 5.0) 170 | let textureName = planet.kind.name() + "Texture" 171 | let material = SCNMaterial() 172 | material.diffuse.contents = UIImage(named: textureName) 173 | material.specular.contents = planet.system.star.kind.textureFillColor() 174 | material.shininess = 0.8 175 | sphere.materials = [material] 176 | return sphere 177 | } 178 | } 179 | 180 | var light: SCNNode { 181 | get { 182 | let omniLightNode = SCNNode() 183 | omniLightNode.light = SCNLight() 184 | omniLightNode.light?.color = planet.system.star.kind.textureFillColor() 185 | omniLightNode.light?.type = .omni 186 | omniLightNode.position = SCNVector3Make(0, 40, 40) 187 | return omniLightNode 188 | } 189 | } 190 | 191 | var planet: PlanetEntity! = nil 192 | 193 | init(planet: PlanetEntity) { 194 | self.planet = planet 195 | } 196 | } 197 | 198 | //MARK: - Resources 199 | class PlanetResource { 200 | 201 | var name: String { 202 | get { 203 | return "" 204 | } 205 | } 206 | 207 | var description: String { 208 | get { 209 | return "" 210 | } 211 | } 212 | 213 | let abundance: Abundance 214 | 215 | enum Abundance: Int { 216 | case none, low, average, plenty, enormous 217 | 218 | func abundancyDescription() -> String { 219 | return "Coming soon" 220 | } 221 | } 222 | 223 | init(abundance: Abundance) { 224 | let randomness = arc4random_uniform(3) 225 | if randomness == 1 && abundance.rawValue > 0 { 226 | self.abundance = Abundance(rawValue: abundance.rawValue - 1)! 227 | } 228 | else if randomness == 2 && abundance.rawValue < 4 { 229 | self.abundance = Abundance(rawValue: abundance.rawValue + 1)! 230 | } 231 | else { 232 | self.abundance = abundance 233 | } 234 | } 235 | } 236 | 237 | class Food: PlanetResource { 238 | 239 | override var name: String { 240 | get { 241 | return "Food" 242 | } 243 | } 244 | 245 | override var description: String { 246 | get { 247 | return "The foods available on the planet" 248 | } 249 | } 250 | } 251 | 252 | 253 | class Mineral: PlanetResource { 254 | 255 | override var name: String { 256 | get { 257 | return "Mineral" 258 | } 259 | } 260 | 261 | override var description: String { 262 | get { 263 | return "The minerals available on the planet" 264 | } 265 | } 266 | } 267 | 268 | class Energy: PlanetResource { 269 | 270 | override var name: String { 271 | get { 272 | return "Energy" 273 | } 274 | } 275 | 276 | override var description: String { 277 | get { 278 | return "The energy available on the planet" 279 | } 280 | } 281 | } 282 | 283 | class Research: PlanetResource { 284 | 285 | override var name: String { 286 | get { 287 | return "Science" 288 | } 289 | } 290 | 291 | override var description: String { 292 | get { 293 | return "The research (for science) available on the planet" 294 | } 295 | } 296 | } 297 | 298 | 299 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/scenes/UniverseScene.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameScene.swift 3 | // Little Orion 4 | // 5 | // Created by Thomas Ricouard on 21/11/2016. 6 | // Copyright © 2016 Thomas Ricouard. All rights reserved. 7 | // 8 | 9 | import SpriteKit 10 | import GameplayKit 11 | import ReSwift 12 | 13 | class UniverseScene: SKScene { 14 | 15 | var lastUpdateTime : TimeInterval = 0 16 | var universe: Universe? { 17 | didSet { 18 | if let universe = universe { 19 | setupUniverse(universe: universe) 20 | } 21 | } 22 | } 23 | 24 | let topBar: TopBar = TopBar.loadFromNib() 25 | let bottomBar: BottomBar = BottomBar.loadFromNib() 26 | let outliner: Outliner = Outliner.loadFromNib() 27 | 28 | var universeSubscriber: UniverseSubscriber? 29 | var uiSubscriber: UISubscriber? 30 | var playerSubscriber: PlayerSubcriber? 31 | 32 | var loaded = false 33 | var universeLoaded = false 34 | var dismissiveInteraction = false 35 | 36 | var startX: CGFloat = 0.0 37 | var startY: CGFloat = 0.0 38 | 39 | var mapNode = SKNode() 40 | var mapMoved = false 41 | var mapNewPosition: CGPoint? 42 | var mapNewScale: CGFloat? 43 | var inZoomGesture = false 44 | 45 | override func sceneDidLoad() { 46 | 47 | view?.isMultipleTouchEnabled = true 48 | backgroundColor = UIColor.black 49 | 50 | if (!loaded) { 51 | 52 | universeSubscriber = UniverseSubscriber(scene: self) 53 | uiSubscriber = UISubscriber(scene: self) 54 | playerSubscriber = PlayerSubcriber(scene: self) 55 | 56 | store.subscribe(universeSubscriber!) { 57 | $0.select{ $0.universeState }.skipRepeats() 58 | } 59 | 60 | store.subscribe(uiSubscriber!) { 61 | $0.select{ $0.uiState }.skipRepeats() 62 | } 63 | 64 | store.subscribe(playerSubscriber!) { 65 | $0.select{ $0.playerState }.skipRepeats() 66 | } 67 | 68 | lastUpdateTime = 0 69 | 70 | store.dispatch(UniverseActions.CreateUnivserse(size: .standard)) 71 | store.dispatch(PlayerActions.Initialize()) 72 | store.dispatch(PlayerActions.StartTimer()) 73 | 74 | onCenterPlayerButton() 75 | 76 | bottomBar.delegate = self 77 | outliner.delegate = self 78 | } 79 | 80 | loaded = true 81 | } 82 | 83 | func setupUniverse(universe: Universe) { 84 | if !universeLoaded { 85 | universeLoaded = true 86 | for node in universe.grid.nodes! { 87 | if let node = node as? UniverseNode { 88 | let spriteNode = node.entity.spriteNode 89 | spriteNode.position = Universe.grideNodePositionToMapPosition(gridNode: node) 90 | if spriteNode.parent == nil { 91 | mapNode.addChild(spriteNode) 92 | } 93 | } 94 | } 95 | addChild(mapNode) 96 | 97 | generateStarField() 98 | } 99 | } 100 | 101 | override func didMove(to view: SKView) { 102 | let pinch = UIPinchGestureRecognizer(target: self, action: #selector(self.onPinchGesture(pinch:))) 103 | self.view?.addGestureRecognizer(pinch) 104 | 105 | self.view?.addSubview(topBar) 106 | topBar.frame = CGRect(x: -2, y: -1, width: self.view!.frame.size.width + 4, height: 80) 107 | 108 | self.view?.addSubview(bottomBar) 109 | bottomBar.frame = CGRect(x: -2, y: self.view!.frame.size.height - 49, 110 | width: self.view!.frame.size.width + 4, height: 50) 111 | 112 | self.view?.addSubview(outliner) 113 | outliner.frame = CGRect(x: -130, y: 90, width: 150, height: self.view!.frame.size.height - 180) 114 | } 115 | 116 | 117 | func generateStarField() { 118 | var emitterNode = starfieldEmitter(color: SKColor.lightGray, starSpeedY: 50, starsPerSecond: 1, starScaleFactor: 0.2) 119 | emitterNode.zPosition = -10 120 | addChild(emitterNode) 121 | 122 | emitterNode = starfieldEmitter(color: SKColor.gray, starSpeedY: 30, starsPerSecond: 2, starScaleFactor: 0.1) 123 | emitterNode.zPosition = -11 124 | addChild(emitterNode) 125 | 126 | emitterNode = starfieldEmitter(color: SKColor.darkGray, starSpeedY: 15, starsPerSecond: 4, starScaleFactor: 0.05) 127 | emitterNode.zPosition = -12 128 | addChild(emitterNode) 129 | } 130 | 131 | func starfieldEmitter(color: SKColor, starSpeedY: CGFloat, starsPerSecond: CGFloat, starScaleFactor: CGFloat) -> SKEmitterNode { 132 | 133 | let lifetime = frame.size.height * UIScreen.main.scale / starSpeedY 134 | 135 | let emitterNode = SKEmitterNode() 136 | emitterNode.particleTexture = SKTexture(imageNamed: "StarParticle") 137 | emitterNode.particleBirthRate = starsPerSecond 138 | emitterNode.particleColor = color 139 | emitterNode.particleSpeed = starSpeedY * -1 140 | emitterNode.particleScale = starScaleFactor 141 | emitterNode.particleColorBlendFactor = 1 142 | emitterNode.particleLifetime = lifetime 143 | 144 | emitterNode.position = CGPoint(x: 0, y: frame.size.height) 145 | emitterNode.particlePositionRange = CGVector(dx: frame.size.width, dy: 0) 146 | 147 | emitterNode.advanceSimulationTime(TimeInterval(lifetime)) 148 | 149 | return emitterNode 150 | } 151 | 152 | override func update(_ currentTime: TimeInterval) { 153 | 154 | if mapNewPosition != nil { 155 | mapNode.position = mapNewPosition! 156 | } 157 | if mapNewScale != nil { 158 | mapNode.setScale(mapNewScale!) 159 | } 160 | 161 | mapNewPosition = nil 162 | mapNewScale = nil 163 | 164 | universe?.update(deltaTime: currentTime) 165 | } 166 | 167 | } 168 | 169 | //MARK: - State 170 | class UniverseSubscriber: StoreSubscriber { 171 | weak var scene: UniverseScene? 172 | 173 | init(scene: UniverseScene) { 174 | self.scene = scene 175 | } 176 | 177 | func newState(state: UniverseState) { 178 | scene?.updateUniverse(state: state) 179 | } 180 | } 181 | 182 | class UISubscriber: StoreSubscriber { 183 | 184 | weak var scene: UniverseScene? 185 | 186 | init(scene: UniverseScene) { 187 | self.scene = scene 188 | } 189 | 190 | 191 | func newState(state: UIState) { 192 | scene?.updateModal(state: state) 193 | scene?.updateScene(state: state) 194 | } 195 | } 196 | 197 | class PlayerSubcriber: StoreSubscriber { 198 | weak var scene: UniverseScene? 199 | 200 | init(scene: UniverseScene) { 201 | self.scene = scene 202 | } 203 | 204 | func newState(state: PlayerState) { 205 | scene?.updatePlayer(state: state) 206 | } 207 | } 208 | 209 | extension UniverseScene { 210 | func updateUniverse(state: UniverseState) { 211 | if let universe = state.universe { 212 | self.universe = universe 213 | } 214 | } 215 | 216 | func updateScene(state: UIState) { 217 | switch state.currentScene { 218 | case .universe: 219 | break 220 | case .planet: 221 | let planetController = PlanetViewController() 222 | view?.window?.rootViewController?.present(planetController, animated: true, completion: nil) 223 | break 224 | } 225 | } 226 | 227 | func updateModal(state: UIState) { 228 | switch state.currentModal { 229 | case .none: 230 | ModalUI.dismissSystemUI() 231 | ModalUI.dismissSelectionUI() 232 | case .system: 233 | ModalUI.presentSystemUI(from: self, delegate: self) 234 | case .entity: 235 | ModalUI.presentSelectionUI(from: self) 236 | } 237 | } 238 | 239 | func updatePlayer(state: PlayerState) { 240 | if state.player.spriteNode.parent == nil { 241 | mapNode.addChild(state.player.spriteNode) 242 | } 243 | } 244 | } 245 | 246 | //MARK: - Nodes 247 | extension UniverseScene { 248 | func systemAt(_ touches: Set, with event: UIEvent?) -> SystemEntity? { 249 | let node = nodeAt(touches, with: event) 250 | if let entity = node?.entity as? SystemEntity { 251 | return entity 252 | } 253 | return nil 254 | } 255 | 256 | func nodeAt(_ touches: Set, with event: UIEvent?) -> SKNode? { 257 | return nodes(at: (touches.first?.location(in: self))!).first 258 | } 259 | 260 | func gridNodeAt(_ touches: Set, with event: UIEvent?) -> UniverseNode? { 261 | if let node = nodeAt(touches, with: event) { 262 | return gridNodeRelativeTo(node: node) 263 | } 264 | return nil 265 | } 266 | 267 | func gridNodeRelativeTo(node: SKNode) -> UniverseNode? { 268 | let entity = universe?.nodeAt(location: Universe.mapNodePositionToGridPosition(mapNode: node)) 269 | return entity 270 | } 271 | } 272 | 273 | //MARK: - UI 274 | extension UniverseScene: SystemUiDelegate { 275 | func systemUISelectedPlanet(planet: PlanetEntity) { 276 | store.dispatch(UIActions.ShowPlanetDetail(planet: planet)) 277 | } 278 | } 279 | 280 | //MARK: - BottomBar delegate 281 | extension UniverseScene: BottomBarDelegate { 282 | func onCenterPlayerButton() { 283 | let playerPosition = store.state.playerState.player.spriteNode.position 284 | mapNewPosition = CGPoint(x: -playerPosition.x, y: -playerPosition.y) 285 | } 286 | 287 | func onMovePlayerButton() { 288 | if store.state.playerState.player.isInMovement { 289 | store.dispatch(PlayerActions.StopMovement()) 290 | } else if let node = store.state.uiState.selectedNode { 291 | if let originalGridNode = gridNodeRelativeTo(node: store.state.playerState.player.spriteNode), 292 | let newGridPosition = gridNodeRelativeTo(node: node) { 293 | let paths = originalGridNode.findPath(to: newGridPosition) 294 | for universeNode in paths { 295 | if let universeNode = universeNode as? UniverseNode, 296 | let shapeNode = universeNode.entity.spriteNode as? SKShapeNode { 297 | //TODO: Hightlight travel path 298 | } 299 | } 300 | 301 | let fromLocation = Universe.mapNodePositionToGridPosition(mapNode: store.state.playerState.player.spriteNode) 302 | let toLocation = Universe.mapNodePositionToGridPosition(mapNode: node) 303 | let movement = PlayerMovementComponent(startDate: store.state.playerState.currentDate, 304 | from: fromLocation, 305 | to: toLocation) 306 | store.dispatch(PlayerActions.MoveToPosition(movement: movement)) 307 | } 308 | } 309 | } 310 | } 311 | 312 | //MARK: - OutlinerDelegate 313 | extension UniverseScene: OutlinerDelegate { 314 | func outlinerDidChangeExpanded(outliner: Outliner, expanded: Bool) { 315 | var frame = outliner.frame 316 | frame.origin.x = expanded ? 0 : -outliner.bounds.size.width + 20 317 | UIView.animate(withDuration: 0.20) { 318 | self.outliner.frame = frame 319 | } 320 | } 321 | 322 | func outlinerDidSelectSystem(outliner: Outliner, system: UniverseId) { 323 | if let system = universe!.entityAt(location: system.location) as? SystemEntity { 324 | store.dispatch(UIActions.ShowSelectedSystemModal(system: system)) 325 | } 326 | } 327 | } 328 | 329 | //MARK: - Touch 330 | extension UniverseScene { 331 | 332 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 333 | store.dispatch(UIActions.RemoveSelectedNode()) 334 | 335 | if (touches.count == 1) { 336 | let position = touches.first!.location(in: self) 337 | 338 | startX = position.x 339 | startY = position.y 340 | } 341 | 342 | if store.state.uiState.currentModal != .none { 343 | store.dispatch(UIActions.DismissModal()) 344 | dismissiveInteraction = true 345 | } 346 | } 347 | 348 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 349 | if (touches.count == 1 && !inZoomGesture) { 350 | let position = touches.first!.location(in: self) 351 | let currentMapPosition = mapNode.position 352 | 353 | let delX = position.x - startX 354 | let delY = position.y - startY 355 | 356 | //Will be updated in the update method 357 | mapNewPosition = CGPoint(x: currentMapPosition.x + delX , y: currentMapPosition.y + delY) 358 | 359 | startX = position.x 360 | startY = position.y 361 | 362 | if (abs(delX) >= 5 || abs(delY) >= 5) { 363 | mapMoved = true 364 | store.dispatch(UIActions.RemoveSelectedNode()) 365 | } 366 | } 367 | } 368 | 369 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 370 | if !mapMoved && !dismissiveInteraction { 371 | if let node = nodeAt(touches, with: event) as? SKShapeNode { 372 | store.dispatch(UIActions.SetSelectedNode(node: node)) 373 | } 374 | 375 | if let system = systemAt(touches, with: event), system.discovered { 376 | store.dispatch(UIActions.ShowSelectedSystemModal(system: system)) 377 | } 378 | 379 | if let universeNode = gridNodeAt(touches, with: event), !universeNode.entity.discovered { 380 | store.dispatch(UIActions.ShowSelectionModal(entity: universeNode.entity)) 381 | } 382 | 383 | } 384 | 385 | dismissiveInteraction = false 386 | mapMoved = false 387 | } 388 | 389 | @objc func onPinchGesture(pinch: UIPinchGestureRecognizer) { 390 | 391 | if pinch.state == .began { 392 | inZoomGesture = true 393 | } else if pinch.state == .ended { 394 | inZoomGesture = false 395 | } 396 | 397 | var anchorPoint = pinch.location(in: pinch.view) 398 | anchorPoint = self.convertPoint(fromView: anchorPoint) 399 | let mapAnchorPoint = mapNode.convert(anchorPoint, from: self) 400 | 401 | let newScale = mapNode.xScale * pinch.scale 402 | 403 | if (newScale >= 0.7 && newScale <= 3) { 404 | mapNewScale = newScale 405 | 406 | let mapSceneAnchorPoint = self.convert(mapAnchorPoint, from: mapNode) 407 | let translationOfAnchorInScene = (x: anchorPoint.x - mapSceneAnchorPoint.x, y: anchorPoint.y - mapSceneAnchorPoint.y) 408 | 409 | mapNewPosition = CGPoint(x: mapNode.position.x + translationOfAnchorInScene.x, y: mapNode.position.y + translationOfAnchorInScene.y) 410 | } 411 | 412 | pinch.scale = 1.0 413 | } 414 | } 415 | 416 | -------------------------------------------------------------------------------- /Little Orion/Little Orion/ui/TopBar.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 33 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | --------------------------------------------------------------------------------