├── tinyRPG ├── World │ ├── Terrain.sks │ ├── StateMachine.swift │ └── MapGen.swift ├── Support │ ├── GameScene.sks │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── beach.imageset │ │ │ ├── beach.png │ │ │ └── Contents.json │ │ ├── grass.imageset │ │ │ ├── grass.png │ │ │ └── Contents.json │ │ ├── icon.imageset │ │ │ ├── icon.png │ │ │ └── Contents.json │ │ ├── ocean.imageset │ │ │ ├── ocean.png │ │ │ └── Contents.json │ │ ├── snow.imageset │ │ │ ├── snow.png │ │ │ └── Contents.json │ │ ├── taiga.imageset │ │ │ ├── taiga.png │ │ │ └── Contents.json │ │ ├── water.imageset │ │ │ ├── water.png │ │ │ └── Contents.json │ │ ├── desert.imageset │ │ │ ├── desert.png │ │ │ └── Contents.json │ │ ├── forest.imageset │ │ │ ├── forest.png │ │ │ └── Contents.json │ │ ├── blank.imageset │ │ │ ├── highlight.png │ │ │ └── Contents.json │ │ ├── mountain.imageset │ │ │ ├── mountain.png │ │ │ └── Contents.json │ │ ├── hero.imageset │ │ │ ├── hero-idle-front.png │ │ │ └── Contents.json │ │ ├── rainForest.imageset │ │ │ ├── rainForest.png │ │ │ └── Contents.json │ │ ├── mountainSnow.imageset │ │ │ ├── mountainSnow.png │ │ │ └── Contents.json │ │ ├── mountainForest.imageset │ │ │ ├── mountainForest.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Extensions.swift │ ├── Info.plist │ ├── GameData.plist │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── AppDelegate.swift ├── MyPlayground.playground │ ├── contents.xcplayground │ ├── Contents.swift │ └── timeline.xctimeline ├── Interface │ ├── TileActions.swift │ ├── ActionMenu.swift │ └── StatMenu.swift ├── Items │ ├── AttackMove.swift │ ├── Armor.swift │ └── Weapon.swift ├── Character │ ├── CharacterComponents │ │ ├── HealthComponent.swift │ │ ├── MagicComponent.swift │ │ ├── SpriteComponent.swift │ │ ├── ExperienceComponent.swift │ │ ├── InventoryComponent.swift │ │ └── MovementComponent.swift │ └── Character.swift ├── GameViewController.swift └── GameScene.swift ├── tinyRPG.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── loganroberts.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── project.pbxproj ├── README.md └── azure-pipelines.yml /tinyRPG/World/Terrain.sks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/World/Terrain.sks -------------------------------------------------------------------------------- /tinyRPG/Support/GameScene.sks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/GameScene.sks -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/beach.imageset/beach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/beach.imageset/beach.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/grass.imageset/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/grass.imageset/grass.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/icon.imageset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/icon.imageset/icon.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/ocean.imageset/ocean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/ocean.imageset/ocean.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/snow.imageset/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/snow.imageset/snow.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/taiga.imageset/taiga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/taiga.imageset/taiga.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/water.imageset/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/water.imageset/water.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/desert.imageset/desert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/desert.imageset/desert.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/forest.imageset/forest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/forest.imageset/forest.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/blank.imageset/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/blank.imageset/highlight.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/mountain.imageset/mountain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/mountain.imageset/mountain.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/hero.imageset/hero-idle-front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/hero.imageset/hero-idle-front.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/rainForest.imageset/rainForest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/rainForest.imageset/rainForest.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/mountainSnow.imageset/mountainSnow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/mountainSnow.imageset/mountainSnow.png -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/mountainForest.imageset/mountainForest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loganroberts/tinyRPG/HEAD/tinyRPG/Support/Assets.xcassets/mountainForest.imageset/mountainForest.png -------------------------------------------------------------------------------- /tinyRPG.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tinyRPG/MyPlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tinyRPG 2 | Swift 5 based turn based RPG game using GameplayKit and SpriteKit. WIP 3 | 4 | Self-lead learning project. Procedural terrain generation based on 5 | perlin noise for height and a separate source for moisture resulting 6 | in a diverse biome set on an infinetly large map. 7 | 8 | -------------------------------------------------------------------------------- /tinyRPG/Interface/TileActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TileActions.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/18/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SpriteKit 11 | import GameplayKit 12 | 13 | class TileActions: SKNode { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /tinyRPG.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/beach.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "beach.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/grass.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "grass.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/ocean.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ocean.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/snow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "snow.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/taiga.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "taiga.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/water.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "water.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/blank.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "highlight.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/desert.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "desert.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/forest.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "forest.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/hero.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "hero-idle-front.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/mountain.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "mountain.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/rainForest.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "rainForest.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/mountainSnow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "mountainSnow.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 | } -------------------------------------------------------------------------------- /tinyRPG/Support/Assets.xcassets/mountainForest.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "mountainForest.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 | } -------------------------------------------------------------------------------- /tinyRPG.xcodeproj/xcuserdata/loganroberts.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | tinyRPG.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # Build, test, and archive an Xcode workspace on macOS. 3 | # Add steps that install certificates, test, sign, and distribute an app, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/xcode 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'macOS-10.13' 11 | 12 | steps: 13 | - task: Xcode@5 14 | inputs: 15 | actions: 'build' 16 | scheme: '' 17 | sdk: 'iphoneos' 18 | configuration: 'Release' 19 | xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' 20 | xcodeVersion: 'default' # Options: 8, 9, 10, default, specifyPath 21 | -------------------------------------------------------------------------------- /tinyRPG/Items/AttackMove.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AttackMove.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/12/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SpriteKit 11 | 12 | class AttackMove { 13 | var name: String 14 | var damage: Int 15 | var criticalChance: Int 16 | var points: Int 17 | 18 | init(data: Dictionary) { 19 | self.name = data["Name"] as! String 20 | self.damage = data["Damage"] as! Int 21 | self.criticalChance = data["CriticalChance"] as! Int 22 | self.points = data["Points"] as! Int 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tinyRPG/Character/CharacterComponents/HealthComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HealthComponent.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/12/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameplayKit 11 | 12 | class HealthComponent: GKComponent { 13 | var owner: Character 14 | 15 | var max = 10 16 | var current = 10 17 | var min = 0 18 | 19 | init(owner: Character) { 20 | self.owner = owner 21 | super.init() 22 | } 23 | 24 | required init?(coder aDecoder: NSCoder) { 25 | fatalError("init(coder:) has not been implemented") 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /tinyRPG/Character/CharacterComponents/MagicComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MagicComponent.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/14/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameplayKit 11 | import SpriteKit 12 | 13 | class MagicComponent: GKComponent { 14 | var owner: Character 15 | 16 | var max = 10 17 | var current = 10 18 | var min = 0 19 | 20 | init(owner: Character) { 21 | self.owner = owner 22 | super.init() 23 | } 24 | 25 | required init?(coder aDecoder: NSCoder) { 26 | fatalError("init(coder:) has not been implemented") 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /tinyRPG/MyPlayground.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import GameplayKit 3 | import SpriteKit 4 | 5 | 6 | let biomeNoise = GKNoise(GKVoronoiNoiseSource(frequency: 3, displacement: 1, distanceEnabled: false, seed: 2222)) 7 | let biomeMap = GKNoiseMap(biomeNoise, size: vector2(1.0, 1.0), origin: vector2(0, 0), sampleCount: vector2(1000, 1000), seamless: false) 8 | let bTexture = SKTexture(noiseMap: biomeMap) 9 | 10 | 11 | 12 | let riverNoise = GKNoise(GKRidgedNoiseSource(frequency: 6.0, octaveCount: 2, lacunarity: 5, seed: 1234)) 13 | let riverMap = GKNoiseMap(riverNoise, size: vector2(1.0, 1.0), origin: vector2(0, 0), sampleCount: vector2(1000, 1000), seamless: false) 14 | let rTexture = SKTexture(noiseMap: riverMap) 15 | -------------------------------------------------------------------------------- /tinyRPG/Support/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/8/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UIGestureRecognizer { 13 | func cancel() { 14 | isEnabled = false 15 | isEnabled = true 16 | } 17 | } 18 | 19 | 20 | func getDefaults(name: String) -> Dictionary { 21 | var dictionary: [String: Any] = [:] 22 | if let url = Bundle.main.url(forResource: name, withExtension: "plist") { 23 | do { 24 | let data = try Data(contentsOf: url) 25 | dictionary = try PropertyListSerialization.propertyList(from: data, options: [], format: nil) as! [String : Any] 26 | } catch { 27 | print("No Plist Found") 28 | } 29 | } 30 | return dictionary 31 | } 32 | -------------------------------------------------------------------------------- /tinyRPG/Character/CharacterComponents/SpriteComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SpriteComponent.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/8/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SpriteKit 11 | import GameplayKit 12 | 13 | class SpriteComponent: GKComponent { 14 | let node: SKSpriteNode 15 | 16 | init(texture: SKTexture) { 17 | node = SKSpriteNode(texture: texture, color: .white, size: texture.size()) 18 | super.init() 19 | 20 | node.position = CGPoint(x: 0, y: 0) 21 | node.scale(to: CGSize(width: 100, height: 100)) 22 | node.zPosition = 1 23 | node.name = "PlayerSprite" 24 | } 25 | 26 | required init?(coder aDecoder: NSCoder) { 27 | fatalError("init(coder:) has not been implemented") 28 | } 29 | 30 | override func update(deltaTime seconds: TimeInterval) { 31 | //update func goes here 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tinyRPG/World/StateMachine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StateMachine.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/12/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameplayKit 11 | 12 | class PlayerTurn: GKState { 13 | //gets the scene the state is attached to 14 | let game: GameScene 15 | let player: Character 16 | 17 | init(game: GameScene, player: Character) { 18 | self.game = game 19 | self.player = player 20 | } 21 | 22 | override func didEnter(from previousState: GKState?) { 23 | //reset player movepoints after ending a turn 24 | player.movement.movementPoints = player.movement.maxMovementPoints 25 | let moves = player.movement.getRange(from: player.movement.currentLocation) 26 | player.movement.highlightMoves(moves: moves) 27 | game.addChild(player.movement.movesMap) 28 | } 29 | } 30 | 31 | class GameTurn: GKState { 32 | 33 | } 34 | -------------------------------------------------------------------------------- /tinyRPG/Items/Armor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Armor.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/12/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SpriteKit 11 | 12 | class Armor { 13 | enum ArmorSlot: String { 14 | case head = "Head" 15 | case body = "Body" 16 | case hands = "Hands" 17 | case feet = "Feet" 18 | } 19 | 20 | var name: String 21 | var slot: ArmorSlot 22 | var defense: Int 23 | var speed: Int 24 | var weight: Int 25 | var value: Int 26 | var sellable: Bool 27 | 28 | init(data: Dictionary) { 29 | self.name = data["Name"] as! String 30 | self.slot = ArmorSlot.init(rawValue: data["ArmorSlot"] as! String)! 31 | self.defense = data["Defense"] as! Int 32 | self.speed = data["Speed"] as! Int 33 | self.weight = data["Weight"] as! Int 34 | self.value = data["Value"] as! Int 35 | self.sellable = data["Sellable"] as! Bool 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tinyRPG/Items/Weapon.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Weapon.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/12/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SpriteKit 11 | 12 | class Weapon { 13 | enum WeaponType: String { 14 | case melee = "Melee" 15 | case ranged = "Ranged" 16 | case magic = "Magic" 17 | } 18 | 19 | var name: String 20 | var weaponType: WeaponType 21 | var accuracy: Int 22 | var damage: Int 23 | var weight: Int 24 | var value: Int 25 | var sellable: Bool 26 | 27 | init(data: Dictionary) { 28 | self.name = data["Name"] as! String 29 | self.accuracy = data["Accuracy"] as! Int 30 | self.damage = data["Damage"] as! Int 31 | self.weight = data["Weight"] as! Int 32 | self.value = data["Value"] as! Int 33 | self.sellable = data["Sellable"] as! Bool 34 | self.weaponType = WeaponType.init(rawValue: data["WeaponType"] as! String)! 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tinyRPG/Character/Character.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Character.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/7/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameplayKit 11 | import SpriteKit 12 | 13 | 14 | class Character: GKEntity { 15 | 16 | //add conveienceProperty for world 17 | var worldMap: MapGen 18 | //Visual image of the player. very basic 19 | let sprite: SpriteComponent 20 | //movement functions and data for the player 21 | let movement: MovementComponent 22 | //experience system for leveling 23 | lazy var experience = ExperienceSystem(owner: self) 24 | // health system for damage 25 | lazy var health = HealthComponent(owner: self) 26 | //magic system for spells 27 | lazy var magic = MagicComponent(owner: self) 28 | //inventory for items and weapons 29 | lazy var inventory = InventoryComponent(owner: self) 30 | 31 | init(texture: SKTexture, map: MapGen) { 32 | self.worldMap = map 33 | self.sprite = SpriteComponent(texture: texture) 34 | self.movement = MovementComponent(map: worldMap) 35 | super.init() 36 | 37 | addComponent(magic) 38 | addComponent(health) 39 | addComponent(experience) 40 | addComponent(movement) 41 | addComponent(sprite) 42 | addComponent(inventory) 43 | } 44 | 45 | required init?(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | override func update(deltaTime seconds: TimeInterval) { 50 | //update func goes here 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tinyRPG/Support/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 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 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /tinyRPG/Support/GameData.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Armor 6 | 7 | Clothes 8 | 9 | Name 10 | Clothes 11 | ArmorSlot 12 | Body 13 | Defense 14 | 1 15 | Speed 16 | 2 17 | Weight 18 | 0 19 | Value 20 | 0 21 | Sellable 22 | 23 | 24 | 25 | Weapons 26 | 27 | Hands 28 | 29 | Name 30 | Hands 31 | WeaponType 32 | Melee 33 | Accuracy 34 | 100 35 | Move 36 | Punch 37 | Damage 38 | 1 39 | Weight 40 | 0 41 | Value 42 | 0 43 | Sellable 44 | 45 | 46 | Stick 47 | 48 | Name 49 | Stick 50 | WeaponType 51 | Melee 52 | Accuracy 53 | 100 54 | Move 55 | Punch 56 | Damage 57 | 1 58 | Weight 59 | 0 60 | Value 61 | 0 62 | Sellable 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /tinyRPG/Support/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 | -------------------------------------------------------------------------------- /tinyRPG/Support/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 | -------------------------------------------------------------------------------- /tinyRPG/Interface/ActionMenu.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActionMenu.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/14/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SpriteKit 11 | import GameplayKit 12 | 13 | class ActionMenu: SKNode { 14 | 15 | let background = SKSpriteNode(color: .black, size: CGSize(width: 420, height: 420)) 16 | 17 | let moveButton = SKSpriteNode(color: .darkGray, size: CGSize(width: 160, height: 160)) 18 | let endTurnButton = SKSpriteNode(color: .darkGray, size: CGSize(width: 160, height: 160)) 19 | let tileActionButton = SKSpriteNode(color: .darkGray, size: CGSize(width: 160, height: 160)) 20 | let inventoryButton = SKSpriteNode(color: .darkGray, size: CGSize(width: 160, height: 160)) 21 | 22 | init(name: String) { 23 | super.init() 24 | self.name = name 25 | 26 | moveButton.name = "MoveButton" 27 | moveButton.position = CGPoint(x: -100, y: 100) 28 | 29 | endTurnButton.name = "EndTurn" 30 | endTurnButton.position = CGPoint(x: -100, y: -100) 31 | 32 | tileActionButton.name = "TileActoin" 33 | tileActionButton.position = CGPoint(x: 100, y: 100) 34 | 35 | inventoryButton.name = "Inventory" 36 | inventoryButton.position = CGPoint(x: 100, y: -100) 37 | 38 | background.alpha = 0.75 39 | 40 | addChild(background) 41 | addChild(endTurnButton) 42 | addChild(tileActionButton) 43 | addChild(moveButton) 44 | addChild(inventoryButton) 45 | } 46 | 47 | required init?(coder aDecoder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /tinyRPG/Character/CharacterComponents/ExperienceComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExperienceComponent.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/12/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameplayKit 11 | 12 | class ExperienceSystem: GKComponent { 13 | var owner: Character 14 | var killCount = 0 15 | 16 | var level = 1 17 | var baseXP = 10 18 | var total = 0.0 19 | 20 | var netXP: Double { 21 | let _a = xpNeeded - total 22 | let _b = (_a*100).rounded()/100 23 | return _b 24 | } 25 | 26 | var dropXP: Double { 27 | let _xp = Double(baseXP * level) / 7 28 | return _xp 29 | } 30 | 31 | var xpNeeded: Double { 32 | let _a: Double = Double(nextLevel) 33 | let _b: Double = pow(_a, 3.0) 34 | let _c: Double = _b * 4.0 35 | return _c / 7 36 | } 37 | 38 | var nextLevel: Int { 39 | return level + 1 40 | } 41 | 42 | init(owner: Character) { 43 | self.owner = owner 44 | super.init() 45 | } 46 | 47 | required init?(coder aDecoder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | func combatComplete(xpDrop: Double) { 52 | total += xpDrop 53 | killCount += 1 54 | levelUpCheck() 55 | } 56 | 57 | func levelUpCheck() { 58 | guard total >= xpNeeded else { 59 | print("You need \(netXP) XP to get to level \(nextLevel)") 60 | return 61 | } 62 | level += 1 63 | print("You leveled up! You are now level \(level)!!") 64 | print("You need \(xpNeeded) XP to get to level \(nextLevel)") 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /tinyRPG/GameViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameViewController.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/7/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SpriteKit 11 | import GameplayKit 12 | 13 | class GameViewController: UIViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | // Load 'GameScene.sks' as a GKScene. This provides gameplay related content 19 | // including entities and graphs. 20 | if let scene = GKScene(fileNamed: "GameScene") { 21 | 22 | // Get the SKScene from the loaded GKScene 23 | if let sceneNode = scene.rootNode as! GameScene? { 24 | 25 | // Copy gameplay related content over to the scene 26 | sceneNode.entities = scene.entities 27 | sceneNode.graphs = scene.graphs 28 | 29 | // Set the scale mode to scale to fit the window 30 | sceneNode.scaleMode = .aspectFill 31 | 32 | // Present the scene 33 | if let view = self.view as! SKView? { 34 | view.presentScene(sceneNode) 35 | 36 | view.ignoresSiblingOrder = true 37 | 38 | view.showsFPS = true 39 | view.showsNodeCount = true 40 | } 41 | } 42 | } 43 | } 44 | 45 | override var shouldAutorotate: Bool { 46 | return true 47 | } 48 | 49 | override var supportedInterfaceOrientations: UIInterfaceOrientationMask { 50 | if UIDevice.current.userInterfaceIdiom == .phone { 51 | return .allButUpsideDown 52 | } else { 53 | return .all 54 | } 55 | } 56 | 57 | override var prefersStatusBarHidden: Bool { 58 | return true 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tinyRPG/Support/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" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /tinyRPG/Support/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/7/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /tinyRPG/Character/CharacterComponents/InventoryComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InventoryComponent.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/12/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameplayKit 11 | import SpriteKit 12 | 13 | class InventoryComponent: GKComponent { 14 | var owner: Character 15 | 16 | var weaponBag: [String: Weapon] = [:] 17 | var armorBag: [String: Armor] = [:] 18 | 19 | var weaponSlot: Weapon? = nil 20 | 21 | var headSlot: Armor? = nil 22 | var bodySlot: Armor? = nil 23 | var feetSlot: Armor? = nil 24 | var handsSlot: Armor? = nil 25 | 26 | var gold = 0 27 | var wood = 0 28 | var stone = 0 29 | var food = 0 30 | 31 | init(owner: Character) { 32 | self.owner = owner 33 | super.init() 34 | } 35 | 36 | required init?(coder aDecoder: NSCoder) { 37 | fatalError("init(coder:) has not been implemented") 38 | } 39 | 40 | func addWeapon(weapon: Weapon) { 41 | guard weaponBag[weapon.name] == nil else { 42 | print("You have one of those already!") 43 | return 44 | } 45 | weaponBag[weapon.name] = weapon 46 | } 47 | 48 | func removeWeapon(weapon: Weapon) { 49 | guard weapon.sellable == true else { 50 | print("You can't get rid of that!") 51 | return 52 | } 53 | weaponBag[weapon.name] = nil 54 | } 55 | 56 | func addArmor(armor: Armor) { 57 | guard armorBag[armor.name] == nil else { 58 | print("You have one of those already!") 59 | return 60 | } 61 | armorBag[armor.name] = armor 62 | } 63 | 64 | func removeArmor(armor: Armor) { 65 | guard armor.sellable == true else { 66 | print("You can't get rid of that!") 67 | return 68 | } 69 | armorBag[armor.name] = nil 70 | } 71 | 72 | func canAffordArmor(armor: Armor) -> Bool { 73 | guard gold >= armor.value else { 74 | return false 75 | } 76 | return true 77 | } 78 | 79 | func canAffordWeapon(weapon: Weapon) -> Bool { 80 | guard gold >= weapon.value else { 81 | return false 82 | } 83 | return true 84 | } 85 | 86 | func equipWeapon(weapon: Weapon) { 87 | weaponSlot = weaponBag[weapon.name] 88 | } 89 | 90 | func deEquipWeapon(weapon: Weapon) { 91 | weaponSlot = nil 92 | } 93 | 94 | func equipArmor(armor: Armor) { 95 | switch armor.slot { 96 | case .body: 97 | bodySlot = armorBag[armor.name] 98 | case .head: 99 | headSlot = armorBag[armor.name] 100 | case .feet: 101 | feetSlot = armorBag[armor.name] 102 | case .hands: 103 | handsSlot = armorBag[armor.name] 104 | } 105 | } 106 | 107 | func deEquipArmor(armor: Armor) { 108 | switch armor.slot { 109 | case .body: 110 | bodySlot = nil 111 | case .head: 112 | headSlot = nil 113 | case .feet: 114 | feetSlot = nil 115 | case .hands: 116 | handsSlot = nil 117 | } 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /tinyRPG/MyPlayground.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /tinyRPG/Interface/StatMenu.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatMenu.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/14/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SpriteKit 11 | import GameplayKit 12 | 13 | class StatMenu: SKNode { 14 | 15 | //setup stat menu things 16 | let background = SKSpriteNode(color: .black, size: CGSize(width: 620, height: 150)) 17 | 18 | var food = 0 19 | var foodDisplay: SKLabelNode 20 | 21 | var wood = 0 22 | var woodDisplay: SKLabelNode 23 | 24 | var stone = 0 25 | var stoneDisplay: SKLabelNode 26 | 27 | var gold = 0 28 | var goldDisplay: SKLabelNode 29 | 30 | var currentHealth = 100 31 | var maxHealth = 100 32 | var healthBar: SKSpriteNode 33 | var healthBackground: SKSpriteNode 34 | 35 | var currentMagic = 100 36 | var maxMagic = 100 37 | var magicBar: SKSpriteNode 38 | var magicBackground: SKSpriteNode 39 | 40 | init(name: String) { 41 | self.foodDisplay = SKLabelNode(text: "Food: \(food)") 42 | self.woodDisplay = SKLabelNode(text: "Wood: \(wood)") 43 | self.stoneDisplay = SKLabelNode(text: "Stone: \(stone)") 44 | self.goldDisplay = SKLabelNode(text: "Gold: \(gold)") 45 | 46 | //set bars and backgrounds to feed from current/max stats 47 | self.healthBar = SKSpriteNode(color: .red, size: CGSize(width: currentHealth, height: 20)) 48 | self.healthBackground = SKSpriteNode(color: .darkGray, size: CGSize(width: maxHealth, height: 16)) 49 | self.magicBar = SKSpriteNode(color: .blue, size: CGSize(width: currentMagic, height: 20)) 50 | self.magicBackground = SKSpriteNode(color: .darkGray, size: CGSize(width: maxMagic, height: 16)) 51 | 52 | super.init() 53 | self.name = name 54 | 55 | //positioning 56 | foodDisplay.position = CGPoint(x: -230, y: -50) 57 | woodDisplay.position = CGPoint(x: -80, y: -50) 58 | stoneDisplay.position = CGPoint(x: 80, y: -50) 59 | goldDisplay.position = CGPoint(x: 220, y: -50) 60 | 61 | //anchorpoint changes to allow for filling, depleting 62 | healthBar.position = CGPoint(x: -280, y: 10) 63 | healthBar.anchorPoint = CGPoint(x: 0.0, y: 0.5) 64 | healthBackground.anchorPoint = CGPoint(x: 0.0, y: 0.5) 65 | healthBackground.position = CGPoint(x: -280, y: 10) 66 | healthBackground.alpha = 0.45 67 | 68 | magicBar.position = CGPoint(x: 275, y: 10) 69 | magicBar.anchorPoint = CGPoint(x: 1.0, y: 0.5) 70 | magicBackground.anchorPoint = CGPoint(x: 1.0, y: 0.5) 71 | magicBackground.position = CGPoint(x: 275, y: 10) 72 | magicBackground.alpha = 0.45 73 | 74 | addChild(background) 75 | 76 | addChild(healthBackground) 77 | addChild(healthBar) 78 | addChild(magicBackground) 79 | addChild(magicBar) 80 | 81 | 82 | addChild(foodDisplay) 83 | addChild(woodDisplay) 84 | addChild(stoneDisplay) 85 | addChild(goldDisplay) 86 | } 87 | 88 | required init?(coder aDecoder: NSCoder) { 89 | fatalError("init(coder:) has not been implemented") 90 | } 91 | 92 | //Called during update loop and changes values based on new info 93 | func update(character: Character) { 94 | gold = character.inventory.gold 95 | food = character.inventory.food 96 | wood = character.inventory.wood 97 | stone = character.inventory.stone 98 | 99 | foodDisplay.text = "Food: \(food)" 100 | goldDisplay.text = "Gold: \(gold)" 101 | woodDisplay.text = "Wood: \(wood)" 102 | stoneDisplay.text = "Stone: \(stone)" 103 | 104 | maxHealth = character.health.max 105 | currentHealth = character.health.current 106 | currentMagic = character.magic.current 107 | 108 | maxMagic = character.magic.max 109 | healthBackground.size = CGSize(width: maxHealth, height: 16) 110 | healthBar.size = CGSize(width: currentHealth, height: 20) 111 | magicBackground.size = CGSize(width: maxMagic, height: 16) 112 | magicBar.size = CGSize(width: currentMagic, height: 20) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /tinyRPG/GameScene.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameScene.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/7/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import SpriteKit 10 | import GameplayKit 11 | 12 | class GameScene: SKScene { 13 | 14 | //Basic Scene setup 15 | var entities = [GKEntity]() 16 | var graphs = [String : GKGraph]() 17 | var cam: SKCameraNode? 18 | 19 | // min size = C:64 R: 64 20 | let map = MapGen(columns: 64, rows: 64) 21 | 22 | var previousCameraPoint = CGPoint.zero 23 | 24 | let panGesture = UIPanGestureRecognizer() 25 | 26 | var gameState: GKStateMachine! 27 | 28 | let gameData = getDefaults(name: "GameData") 29 | //Helper character for testing. DO NOT REFERENCE 30 | lazy var character = Character(texture: SKTexture(imageNamed: "hero"), map: map) 31 | 32 | let statMenu = StatMenu(name: "Stats") 33 | let actionMenu = ActionMenu(name: "Actions") 34 | 35 | override func sceneDidLoad() { 36 | //setup game state 37 | gameState = GKStateMachine(states: [PlayerTurn(game: self, player: character), GameTurn()]) 38 | gameState.enter(PlayerTurn.self) 39 | 40 | entities.append(character) 41 | 42 | addChild(map.tileMap) 43 | character.sprite.node.zPosition = 999 44 | addChild(character.sprite.node) 45 | 46 | } 47 | 48 | //Sets up gestures and camera in scene 49 | override func didMove(to view: SKView) { 50 | //pan around the map 51 | panGesture.addTarget(self, action: #selector(panGestureAction(_:))) 52 | view.addGestureRecognizer(panGesture) 53 | 54 | 55 | //setup camera 56 | cam = SKCameraNode() 57 | self.camera = cam 58 | self.addChild(cam!) 59 | 60 | //menus 61 | statMenu.position = CGPoint(x: 0, y: 620) 62 | cam?.addChild(statMenu) 63 | 64 | actionMenu.zPosition = 1000 65 | actionMenu.isHidden = true 66 | 67 | cam?.addChild(actionMenu) 68 | 69 | //set player to middle of current tile on map 70 | let playerPosition = character.movement.getOffsetLocation(point: character.sprite.node.position) 71 | character.sprite.node.position = map.tileMap.centerOfTile(atColumn: playerPosition.0, row: playerPosition.1) 72 | character.movement.currentLocation = playerPosition 73 | 74 | //sets camera to focus on player 75 | cam!.position = character.sprite.node.position 76 | 77 | } 78 | 79 | func showMovesMap(point: CGPoint) { 80 | //setups up the initial moves map - will move once a menu button is set for "move" action 81 | let playerPosition = character.movement.getOffsetLocation(point: point) 82 | let moves = character.movement.getRange(from: playerPosition) 83 | character.movement.highlightMoves(moves: moves) 84 | addChild(character.movement.movesMap) 85 | } 86 | 87 | //Allows for panning around the map 88 | @objc func panGestureAction(_ sender: UIPanGestureRecognizer) { 89 | guard let camera = self.camera else { 90 | return 91 | } 92 | // If the movement just began, save the first camera position 93 | if sender.state == .began { 94 | previousCameraPoint = self.camera!.position 95 | } 96 | // Perform the translation 97 | let translation = sender.translation(in: self.view) 98 | let newPosition = CGPoint( 99 | x: previousCameraPoint.x + translation.x * -1, 100 | y: previousCameraPoint.y + translation.y 101 | ) 102 | camera.position = newPosition 103 | } 104 | 105 | 106 | func touchDown(atPoint pos : CGPoint) { 107 | 108 | } 109 | 110 | func touchMoved(toPoint pos : CGPoint) { 111 | 112 | } 113 | 114 | func touchUp(atPoint pos : CGPoint) { 115 | let destination = character.movement.moveTo(point: pos) 116 | let moveToTile = SKAction.move(to: destination, duration: 0.25) 117 | if character.movement.moved == true { 118 | cam?.run(moveToTile) 119 | character.sprite.node.run(moveToTile) 120 | showMovesMap(point: destination) 121 | character.movement.moved = false 122 | } 123 | } 124 | 125 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 126 | 127 | 128 | for t in touches { 129 | self.touchDown(atPoint: t.location(in: self)) 130 | } 131 | } 132 | 133 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 134 | for t in touches { 135 | //detect force touch 136 | let maxForce = t.maximumPossibleForce 137 | let force = t.force 138 | let normalizedForce = force / maxForce 139 | 140 | let location = t.location(in: self) 141 | let node = self.atPoint(location) 142 | 143 | if normalizedForce >= 0.75 && node.name == "PlayerSprite" { 144 | actionMenu.isHidden = false 145 | } 146 | 147 | self.touchMoved(toPoint: t.location(in: self)) 148 | 149 | } 150 | } 151 | 152 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 153 | 154 | let location = touches.first!.location(in: self) 155 | let node = self.atPoint(location) 156 | 157 | if node.parent is ActionMenu { 158 | switch node.name { 159 | case "MoveButton": 160 | showMovesMap(point: character.sprite.node.position) 161 | actionMenu.isHidden = true 162 | case "EndTurn": 163 | gameState.enter(GameTurn.self) 164 | actionMenu.isHidden = true 165 | case "TileAction": 166 | print("Tile Action Button Pushed") 167 | actionMenu.isHidden = true 168 | case "Inventory": 169 | print("Inventory Button Pushed") 170 | actionMenu.isHidden = true 171 | default: 172 | print(node.name ?? "NO Name") 173 | } 174 | } else { 175 | if actionMenu.isHidden { 176 | self.touchUp(atPoint: location) 177 | } 178 | actionMenu.isHidden = true 179 | } 180 | 181 | } 182 | 183 | override func touchesCancelled(_ touches: Set, with event: UIEvent?) { 184 | for t in touches { self.touchUp(atPoint: t.location(in: self)) } 185 | } 186 | 187 | 188 | override func update(_ currentTime: TimeInterval) { 189 | if gameState.currentState is GameTurn { 190 | gameState.enter(PlayerTurn.self) 191 | } 192 | 193 | //If moving happened, add the new tileMap to the scene and set the camera position and end the pan gesture 194 | if map.updateMap(point: camera?.position ?? CGPoint(x: 0.0, y: 0.0), zoom: 1.0) == true { 195 | self.addChild(map.tileMap) 196 | camera?.position = map.getTileCenter(point: CGPoint(x: 0.0, y: 0.0), inMap: map.tileMap) 197 | panGesture.cancel() 198 | } 199 | 200 | statMenu.update(character: character) 201 | 202 | } 203 | 204 | } 205 | -------------------------------------------------------------------------------- /tinyRPG/Character/CharacterComponents/MovementComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MovementComponent.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 2/28/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SpriteKit 11 | import GameplayKit 12 | 13 | class MovementComponent: GKComponent { 14 | 15 | var movesMap = SKNode() 16 | var moved = false 17 | var range = 2 18 | var maxMovementPoints = 2 19 | var movementPoints = 2 20 | 21 | var directions = [(1, -1, 0), (1, 0, -1), (0, 1, -1), 22 | (-1, 1, 0), (-1, 0, 1), (0, -1, 1)] 23 | 24 | var diagonals = [(2, -1, -1), (1, 1, -2), (-1, 2, -1), 25 | (-2, 1, 1), (-1, -1, 2), (1, -2, 1)] 26 | 27 | var map: MapGen 28 | var validTiles = [(Int, Int)]() 29 | 30 | var currentLocation = (0, 0) 31 | 32 | lazy var currentTile = map.tileMap.tileDefinition(atColumn: currentLocation.0, row: currentLocation.1) 33 | 34 | init(map: MapGen) { 35 | self.map = map 36 | super.init() 37 | } 38 | 39 | required init?(coder aDecoder: NSCoder) { 40 | fatalError("init(coder:) has not been implemented") 41 | } 42 | 43 | 44 | func moveTo(point: CGPoint) -> CGPoint { 45 | 46 | let column = map.tileMap.tileColumnIndex(fromPosition: point) 47 | let row = map.tileMap.tileRowIndex(fromPosition: point) 48 | let tile = (column, row) 49 | 50 | //sets up a path from origin to the new location 51 | let currentCube = offsetToCube(column: currentLocation.0, row: currentLocation.1) 52 | let futureCube = offsetToCube(column: tile.0, row: tile.1) 53 | let path = getPath(from: currentCube, to: futureCube) 54 | 55 | //checks the cost for each step between origin and new location 56 | var totalCost = 0 57 | for each in path { 58 | if each != currentCube { 59 | //incriments the totalCost for all new tiles 60 | let loc = cubeToOffset(cube: each) 61 | let tileDef = map.tileMap.tileDefinition(atColumn: loc.0, row: loc.1) 62 | let cost = tileDef?.userData?.value(forKey: "cost") as! Int 63 | totalCost += cost 64 | } 65 | } 66 | 67 | var destination = map.tileMap.centerOfTile(atColumn: currentLocation.0, row: currentLocation.1) 68 | 69 | if validTiles.contains(where: { $0 == tile }) && totalCost <= movementPoints { 70 | destination = map.tileMap.centerOfTile(atColumn: column, row: row) 71 | moved = true 72 | currentLocation = (column, row) 73 | } 74 | movementPoints -= totalCost 75 | return destination 76 | } 77 | 78 | 79 | ///////Supporting Functions 80 | 81 | func getOffsetLocation(point: CGPoint) -> (Int, Int) { 82 | let column = map.tileMap.tileColumnIndex(fromPosition: point) 83 | let row = map.tileMap.tileRowIndex(fromPosition: point) 84 | 85 | return (column, row) 86 | } 87 | 88 | func offsetToCube(column: Int, row: Int) -> (Int, Int, Int){ 89 | let x = (column - (row - (row&1)) / 2) 90 | let z = row 91 | let y = (-x - z) 92 | 93 | return(x, y, z) 94 | } 95 | 96 | func cubeToOffset(cube: (Int, Int, Int)) -> (Int, Int) { 97 | let column = cube.0 + (cube.2 - (cube.2&1)) / 2 98 | let row = cube.2 99 | return (column, row) 100 | } 101 | 102 | func cubeAdd(cubeA: (Int, Int, Int), cubeB: (Int, Int, Int)) -> (Int, Int, Int) { 103 | let result = ((cubeA.0 + cubeB.0), (cubeA.1 + cubeB.1), (cubeA.2 + cubeB.2)) 104 | return result 105 | } 106 | 107 | func cubeSubtract(cubeA: (Int, Int, Int), cubeB: (Int, Int, Int)) -> (Int, Int, Int) { 108 | let result = ((cubeA.0 - cubeB.0), (cubeA.1 - cubeB.1), (cubeA.2 - cubeB.2)) 109 | return result 110 | } 111 | 112 | func cubeRound(cube: (Double, Double, Double)) -> (Int, Int, Int) { 113 | var xi = round(cube.0) 114 | var yi = round(cube.1) 115 | var zi = round(cube.2) 116 | 117 | let xDiff = abs(xi - cube.0) 118 | let yDiff = abs(yi - cube.1) 119 | let zDiff = abs(zi - cube.2) 120 | 121 | if xDiff > yDiff && xDiff > zDiff { 122 | xi = (-yi - zi) 123 | } else if yDiff > zDiff { 124 | yi = (-xi - zi) 125 | } else { 126 | zi = (-xi - yi) 127 | } 128 | 129 | return (Int(xi), Int(yi), Int(zi)) 130 | } 131 | 132 | func cubeNudge(cube: (Int, Int, Int)) -> (Double, Double, Double) { 133 | let result = (Double(cube.0) + 0.000001, Double(cube.1) + 0.000001, Double(cube.2) - 0.000002) 134 | return result 135 | } 136 | 137 | func getNeighbors(location: (Int, Int)) -> [(Int, Int, Int)] { 138 | let cubeLocation = offsetToCube(column: location.0, row: location.1) 139 | var neighbors = [(Int, Int, Int)]() 140 | 141 | for direction in directions { 142 | let result = cubeAdd(cubeA: cubeLocation, cubeB: direction) 143 | neighbors.append(result) 144 | } 145 | 146 | return neighbors 147 | } 148 | 149 | func getDistance(cubeA: (Int, Int, Int), cubeB: (Int, Int, Int)) -> Int { 150 | 151 | let x = abs(cubeA.0 - cubeB.0) 152 | let y = abs(cubeA.1 - cubeB.1) 153 | let z = abs(cubeA.2 - cubeB.2) 154 | 155 | let distance = max(x, y, z) 156 | 157 | return distance 158 | 159 | } 160 | 161 | //Linear Interpolation 162 | func lerp(a: (Double, Double, Double), b: (Double, Double, Double), t: Double) -> (Double, Double, Double) { 163 | let x = a.0 * (1.0 - t) + (b.0 * t) 164 | let y = a.1 * (1.0 - t) + (b.1 * t) 165 | let z = a.2 * (1.0 - t) + (b.2 * t) 166 | 167 | return (x, y, z) 168 | } 169 | 170 | func getPath(from: (Int, Int, Int), to: (Int, Int, Int)) -> [(Int, Int, Int)] { 171 | let d = getDistance(cubeA: from, cubeB: to) 172 | 173 | let aNudge = cubeNudge(cube: from) 174 | let bNudge = cubeNudge(cube: to) 175 | let step = 1.0 / max(Double(d), 1.0) 176 | 177 | var results = [(Int, Int, Int)]() 178 | 179 | let path1 = 000 180 | 181 | for i in 0...d { 182 | let t = step * Double(i) 183 | let lerpedCube = lerp(a: aNudge, b: bNudge, t: t) 184 | let result = cubeRound(cube: lerpedCube) 185 | results.append(result) 186 | } 187 | 188 | return results 189 | } 190 | 191 | func getRange(from: (Int, Int)) -> [(Int, Int)] { 192 | let origin = offsetToCube(column: from.0, row: from.1) 193 | var visited = [origin] 194 | var fringes = [[(origin)]] 195 | 196 | var validTiles = [(Int, Int)]() 197 | 198 | for k in 1...range { 199 | let emptyA = [(Int, Int, Int)]() 200 | fringes.append(emptyA) 201 | for tile in fringes[k - 1] { 202 | let neighbors = getNeighbors(location: cubeToOffset(cube: tile)) 203 | for neighbor in neighbors { 204 | if visited.contains(where: { $0 == neighbor }) { 205 | } else { 206 | visited.append(neighbor) 207 | fringes[k].append(neighbor) 208 | } 209 | } 210 | } 211 | 212 | for (index, member) in visited.enumerated() { 213 | if member == origin { 214 | visited.remove(at: index) 215 | } else { 216 | validTiles.append(cubeToOffset(cube: member)) 217 | } 218 | } 219 | } 220 | 221 | let results = filterMovementCost(origin: offsetToCube(column: from.0, row: from.1), range: validTiles) 222 | 223 | 224 | return results 225 | } 226 | 227 | func filterMovementCost(origin: (Int, Int, Int), range: [(Int, Int)]) -> [(Int, Int)] { 228 | var validMoves = [(Int, Int, Int)]() 229 | var validCoordinates = [(Int, Int)]() 230 | 231 | for each in range { 232 | let path = getPath(from: origin, to: offsetToCube(column: each.0, row: each.1)) 233 | var pathCost = 0 234 | for step in path { 235 | if step != origin { 236 | let tile = map.tileMap.tileDefinition(atColumn: cubeToOffset(cube: step).0, row: cubeToOffset(cube: step).1) 237 | let cost = tile?.userData?.value(forKey: "cost") as? Int ?? 5 238 | pathCost += cost 239 | if pathCost <= movementPoints { 240 | if !validMoves.contains(where: { $0 == step }) { 241 | validMoves.append(step) 242 | } 243 | } 244 | } 245 | } 246 | } 247 | for each in validMoves { 248 | validCoordinates.append(cubeToOffset(cube: each)) 249 | } 250 | validTiles = validCoordinates 251 | return validCoordinates 252 | } 253 | 254 | func highlightMoves(moves: [(Int, Int)]) { 255 | clearMoveMap() 256 | let movesMapNode = SKTileMapNode(tileSet: map.tileSet!, columns: map.columns, rows: map.rows, tileSize: CGSize(width: 125, height: 144)) 257 | movesMapNode.zPosition = 2 258 | movesMapNode.name = "movesMapNode" 259 | for move in moves { 260 | movesMapNode.setTileGroup(map.tileSet!.tileGroups.first( where: { $0.name == "blank"}), forColumn: move.0, row: move.1) 261 | } 262 | movesMap.addChild(movesMapNode) 263 | } 264 | 265 | func clearMoveMap() { 266 | movesMap.childNode(withName: "movesMapNode")?.removeFromParent() 267 | movesMap.removeFromParent() 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /tinyRPG/World/MapGen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MapGen.swift 3 | // tinyRPG 4 | // 5 | // Created by Logan Roberts on 3/7/19. 6 | // Copyright © 2019 Logan Roberts. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameplayKit 11 | import SpriteKit 12 | 13 | class MapGen { 14 | //List of valid biomes for tile Data 15 | enum Biome { 16 | case Ocean 17 | case Beach 18 | case Grassland 19 | case Forest 20 | case Rainforest 21 | case Desert 22 | case Mountain 23 | case Taiga 24 | case MountainSnow 25 | case MountainForest 26 | case Snow 27 | case Blank 28 | case River 29 | } 30 | 31 | 32 | //Noise Setup. One for height(and temperature) and one for moisture 33 | let moistureNoise = GKNoise(GKPerlinNoiseSource( 34 | frequency: 2, 35 | octaveCount: 8, 36 | persistence: 0.8, 37 | lacunarity: 1.5, 38 | seed: Int32(arc4random_uniform(5000 - 1)))) 39 | 40 | let heightNoise = GKNoise(GKPerlinNoiseSource( 41 | frequency: 2, 42 | octaveCount: 8, 43 | persistence: 0.8, 44 | lacunarity: 1.5, 45 | seed: Int32(arc4random_uniform(5000 - 1)))) 46 | 47 | var tileSet = SKTileSet(named: "Terrain") 48 | 49 | // tileMap setup 50 | var tileMap: SKTileMapNode 51 | var columns: Int 52 | var rows: Int 53 | 54 | var currentTileIndex = (0, 0) 55 | 56 | init(columns: Int, rows: Int) { 57 | 58 | self.columns = columns 59 | self.rows = rows 60 | 61 | self.tileMap = SKTileMapNode(tileSet: tileSet!, columns: columns, rows: rows, tileSize: CGSize(width: 125, height: 144)) 62 | 63 | heightNoise.clamp(lowerBound: -0.1, upperBound: 1.0) 64 | heightNoise.raiseToPower(4) 65 | 66 | self.tileMap = createMap(columns: columns, rows: rows) 67 | 68 | } 69 | 70 | /* 71 | Creates an updated map aftermovement by using the utility function to adjust noisemaps. 72 | If no movement, does nothing. Returns bool back to the GameScene for use in the Update() 73 | function. 74 | */ 75 | 76 | func isRiver() -> Bool { 77 | let num = arc4random_uniform(5000-1) 78 | guard num > 4900 else { 79 | return false 80 | } 81 | return true 82 | } 83 | 84 | func updateMap(point: CGPoint, zoom: CGFloat) -> Bool { 85 | var modified = false 86 | 87 | currentTileIndex = getOffsetLocation(point: point, inMap: tileMap) 88 | 89 | let mapOffsetCenter = (tileMap.numberOfColumns / 2, tileMap.numberOfRows / 2 - 1) 90 | let movedTiles = (currentTileIndex.0 - mapOffsetCenter.0, currentTileIndex.1 - mapOffsetCenter.1) 91 | 92 | //set zoom level for tile offsets 93 | let xBorder = Int(round(zoom) * 4) 94 | let yBorder = Int(round(zoom) * 7) 95 | 96 | //check if camera.position.x is in bounds 97 | switch currentTileIndex.0 { 98 | case .. (Int, Int) { 139 | let column = inMap.tileColumnIndex(fromPosition: point) 140 | let row = inMap.tileRowIndex(fromPosition: point) 141 | return (column, row) 142 | } 143 | 144 | //Gets the center tile on screen in point (for passing back to the camera.position) 145 | func getTileCenter(point: CGPoint, inMap: SKTileMapNode) -> CGPoint { 146 | let offset = getOffsetLocation(point: point, inMap: inMap) 147 | let centerPoint = tileMap.centerOfTile(atColumn: offset.0, row: offset.1) 148 | return centerPoint 149 | } 150 | 151 | /* 152 | Map generation function. Sets the noiseMaps from the preset noiseSources. 153 | Creates a TileMap and then iterates to create biome data by comparing the HeightMap to the Moisture Map 154 | Calls the setBiome helper function to get the results 155 | */ 156 | func createMap(columns: Int, rows: Int) -> SKTileMapNode { 157 | let elevationMap = GKNoiseMap(heightNoise) 158 | let moistureMap = GKNoiseMap(moistureNoise) 159 | 160 | let map = SKTileMapNode(tileSet: tileSet!, columns: columns, rows: rows, tileSize: CGSize(width: 125, height: 144)) 161 | 162 | for column in 0 ..< columns { 163 | for row in 0 ..< rows { 164 | let location = vector2(Int32(row), Int32(column)) 165 | let tileBiome = setBiome(location: location, e: elevationMap, m: moistureMap) 166 | 167 | switch tileBiome { 168 | case .Ocean: 169 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "ocean"}), forColumn: column, row: row) 170 | case .Beach: 171 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "beach"}), forColumn: column, row: row) 172 | case .Grassland: 173 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "grass"}), forColumn: column, row: row) 174 | case .Forest: 175 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "forest"}), forColumn: column, row: row) 176 | case .Rainforest: 177 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "rainForest"}), forColumn: column, row: row) 178 | case .Desert: 179 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "desert"}), forColumn: column, row: row) 180 | case .Mountain: 181 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "mountain"}), forColumn: column, row: row) 182 | case .MountainSnow: 183 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "mountainSnow"}), forColumn: column, row: row) 184 | case .MountainForest: 185 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "mountainForest"}), forColumn: column, row: row) 186 | case .River: 187 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "water"}), forColumn: column, row: row) 188 | case .Snow: 189 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "snow"}), forColumn: column, row: row) 190 | case .Taiga: 191 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "taiga"}), forColumn: column, row: row) 192 | case .Blank: 193 | map.setTileGroup(map.tileSet.tileGroups.first( where: { $0.name == "blank"}), forColumn: column, row: row) 194 | } 195 | 196 | } 197 | } 198 | let newMap = generateRiverSource(dryMap: map) 199 | return newMap 200 | } 201 | 202 | // Get the elevation and compare against a moisture map for biome generation and return the Biome for tilemap creation 203 | func setBiome(location: simd_int2, e: GKNoiseMap, m: GKNoiseMap) -> Biome { 204 | let eV = e.value(at: location) 205 | let mV = m.value(at: location) 206 | var biome: Biome = .Blank 207 | 208 | //Check for Ocean/Beach 209 | guard eV > -0.5 else { 210 | if eV > -0.51 { 211 | biome = .Beach 212 | } else { 213 | biome = .Ocean 214 | } 215 | return biome 216 | } 217 | 218 | if eV > -0.5 && eV < -0.25 { 219 | switch mV { 220 | case -1.0 ... -0.75: 221 | biome = .Desert 222 | case -0.75 ... -0.5: 223 | biome = .Grassland 224 | case -0.5 ... 0.25: 225 | biome = .Forest 226 | case 0.25 ... 1.0: 227 | if isRiver() { 228 | biome = .River 229 | } else { 230 | biome = .Rainforest 231 | } 232 | default: 233 | print("Tropical Biome outside range") 234 | biome = .Blank 235 | } 236 | return biome 237 | } 238 | 239 | if eV > -0.25 && eV < 0.25 { 240 | switch mV { 241 | case -1.0 ... -0.5: 242 | biome = .Desert 243 | case -0.5 ... 0.0: 244 | biome = .Grassland 245 | case 0.0 ... 1.0: 246 | if isRiver() { 247 | biome = .River 248 | } else { 249 | biome = .Forest 250 | } 251 | default: 252 | print("Temperate Biome outside range") 253 | biome = .Blank 254 | } 255 | return biome 256 | } 257 | 258 | if eV > 0.25 && eV < 0.5 { 259 | switch mV { 260 | case -1.0 ... -0.25: 261 | biome = .Desert 262 | case -0.25 ... 0.25: 263 | biome = .Taiga 264 | case 0.25 ... 1.0: 265 | biome = .Snow 266 | default: 267 | print("Arctic Biome outside range") 268 | biome = .Blank 269 | } 270 | return biome 271 | } 272 | 273 | if eV > 0.5 && eV <= 1.0 { 274 | switch mV { 275 | case -1.0 ... -0.25: 276 | biome = .Mountain 277 | case -0.25 ... 0.25: 278 | if isRiver() { 279 | biome = .River 280 | } else { 281 | biome = .MountainForest 282 | } 283 | case 0.25 ... 1.0: 284 | biome = .MountainSnow 285 | default: 286 | print("Mountain Biome outside range") 287 | biome = .Blank 288 | } 289 | return biome 290 | } 291 | 292 | return biome 293 | } 294 | 295 | func generateRiverSource(dryMap: SKTileMapNode) -> SKTileMapNode { 296 | let map = dryMap 297 | var rivers = [(Int, Int)]() 298 | 299 | 300 | //creates the sources and then adds to the array of points 301 | for column in 0...map.numberOfColumns { 302 | for row in 0...map.numberOfRows { 303 | let tile = map.tileDefinition(atColumn: column, row: row) 304 | if ((tile?.userData?.value(forKey: "river")) != nil) { 305 | rivers.append((column, row)) 306 | } 307 | 308 | } 309 | } 310 | 311 | var index = 0 312 | 313 | for (i, each) in rivers.enumerated() { 314 | 315 | 316 | } 317 | 318 | 319 | return map 320 | } 321 | 322 | } 323 | -------------------------------------------------------------------------------- /tinyRPG.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C8147477223300EB00FCE476 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8147476223300EB00FCE476 /* Extensions.swift */; }; 11 | C814747B223314E200FCE476 /* MovementComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C814747A223314E200FCE476 /* MovementComponent.swift */; }; 12 | C83167B22231582100584C0B /* Character.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83167B12231582100584C0B /* Character.swift */; }; 13 | C83167B52231583B00584C0B /* MapGen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83167B42231583B00584C0B /* MapGen.swift */; }; 14 | C83167BA2232CEEB00584C0B /* SpriteComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83167B92232CEEB00584C0B /* SpriteComponent.swift */; }; 15 | C874AA7B2238277200FA152F /* StateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = C874AA7A2238277200FA152F /* StateMachine.swift */; }; 16 | C874AA7E2238439A00FA152F /* Weapon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C874AA7D2238439A00FA152F /* Weapon.swift */; }; 17 | C874AA80223843BD00FA152F /* Armor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C874AA7F223843BD00FA152F /* Armor.swift */; }; 18 | C874AA82223843CB00FA152F /* AttackMove.swift in Sources */ = {isa = PBXBuildFile; fileRef = C874AA81223843CB00FA152F /* AttackMove.swift */; }; 19 | C874AA842238441000FA152F /* ExperienceComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C874AA832238441000FA152F /* ExperienceComponent.swift */; }; 20 | C874AA862238445A00FA152F /* HealthComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C874AA852238445A00FA152F /* HealthComponent.swift */; }; 21 | C874AA88223848B600FA152F /* InventoryComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C874AA87223848B600FA152F /* InventoryComponent.swift */; }; 22 | C87F7DB8223157420055E617 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C87F7DB7223157420055E617 /* AppDelegate.swift */; }; 23 | C87F7DBA223157420055E617 /* GameScene.sks in Resources */ = {isa = PBXBuildFile; fileRef = C87F7DB9223157420055E617 /* GameScene.sks */; }; 24 | C87F7DBE223157420055E617 /* GameScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = C87F7DBD223157420055E617 /* GameScene.swift */; }; 25 | C87F7DC0223157420055E617 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C87F7DBF223157420055E617 /* GameViewController.swift */; }; 26 | C87F7DC3223157420055E617 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C87F7DC1223157420055E617 /* Main.storyboard */; }; 27 | C87F7DC5223157440055E617 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C87F7DC4223157440055E617 /* Assets.xcassets */; }; 28 | C87F7DC8223157440055E617 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C87F7DC6223157440055E617 /* LaunchScreen.storyboard */; }; 29 | C8857791223935DD0092CAF5 /* Terrain.sks in Resources */ = {isa = PBXBuildFile; fileRef = C885778F223935DD0092CAF5 /* Terrain.sks */; }; 30 | C885779622393FCC0092CAF5 /* GameData.plist in Resources */ = {isa = PBXBuildFile; fileRef = C885779522393FCC0092CAF5 /* GameData.plist */; }; 31 | C8CD774B224014EA00227751 /* TileActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8CD774A224014EA00227751 /* TileActions.swift */; }; 32 | C8F9F7A9223A9D610059FB1C /* StatMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F9F7A8223A9D610059FB1C /* StatMenu.swift */; }; 33 | C8FA71C5223AB378003E063F /* MagicComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FA71C4223AB378003E063F /* MagicComponent.swift */; }; 34 | C8FA71C7223AB6C0003E063F /* ActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FA71C6223AB6C0003E063F /* ActionMenu.swift */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | C8147476223300EB00FCE476 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 39 | C814747A223314E200FCE476 /* MovementComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovementComponent.swift; sourceTree = ""; }; 40 | C83167B12231582100584C0B /* Character.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Character.swift; sourceTree = ""; }; 41 | C83167B42231583B00584C0B /* MapGen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapGen.swift; sourceTree = ""; }; 42 | C83167B7223159A500584C0B /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 43 | C83167B92232CEEB00584C0B /* SpriteComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpriteComponent.swift; sourceTree = ""; }; 44 | C874AA7A2238277200FA152F /* StateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateMachine.swift; sourceTree = ""; }; 45 | C874AA7D2238439A00FA152F /* Weapon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weapon.swift; sourceTree = ""; }; 46 | C874AA7F223843BD00FA152F /* Armor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Armor.swift; sourceTree = ""; }; 47 | C874AA81223843CB00FA152F /* AttackMove.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttackMove.swift; sourceTree = ""; }; 48 | C874AA832238441000FA152F /* ExperienceComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperienceComponent.swift; sourceTree = ""; }; 49 | C874AA852238445A00FA152F /* HealthComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthComponent.swift; sourceTree = ""; }; 50 | C874AA87223848B600FA152F /* InventoryComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InventoryComponent.swift; sourceTree = ""; }; 51 | C87F7DB4223157420055E617 /* tinyRPG.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tinyRPG.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | C87F7DB7223157420055E617 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 53 | C87F7DB9223157420055E617 /* GameScene.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = GameScene.sks; sourceTree = ""; }; 54 | C87F7DBD223157420055E617 /* GameScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameScene.swift; sourceTree = ""; }; 55 | C87F7DBF223157420055E617 /* GameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; 56 | C87F7DC2223157420055E617 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 57 | C87F7DC4223157440055E617 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 58 | C87F7DC7223157440055E617 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 59 | C87F7DC9223157440055E617 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | C885778F223935DD0092CAF5 /* Terrain.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Terrain.sks; sourceTree = ""; }; 61 | C885779522393FCC0092CAF5 /* GameData.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = GameData.plist; sourceTree = ""; }; 62 | C8CD774A224014EA00227751 /* TileActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileActions.swift; sourceTree = ""; }; 63 | C8F9F7A8223A9D610059FB1C /* StatMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatMenu.swift; sourceTree = ""; }; 64 | C8FA71C4223AB378003E063F /* MagicComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicComponent.swift; sourceTree = ""; }; 65 | C8FA71C6223AB6C0003E063F /* ActionMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionMenu.swift; sourceTree = ""; }; 66 | /* End PBXFileReference section */ 67 | 68 | /* Begin PBXFrameworksBuildPhase section */ 69 | C87F7DB1223157420055E617 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | C83167B32231582600584C0B /* Character */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | C83167B12231582100584C0B /* Character.swift */, 83 | C83167B82232CEDE00584C0B /* CharacterComponents */, 84 | ); 85 | path = Character; 86 | sourceTree = ""; 87 | }; 88 | C83167B62231583E00584C0B /* World */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | C874AA7A2238277200FA152F /* StateMachine.swift */, 92 | C83167B42231583B00584C0B /* MapGen.swift */, 93 | C885778F223935DD0092CAF5 /* Terrain.sks */, 94 | ); 95 | path = World; 96 | sourceTree = ""; 97 | }; 98 | C83167B82232CEDE00584C0B /* CharacterComponents */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | C83167B92232CEEB00584C0B /* SpriteComponent.swift */, 102 | C814747A223314E200FCE476 /* MovementComponent.swift */, 103 | C874AA832238441000FA152F /* ExperienceComponent.swift */, 104 | C874AA852238445A00FA152F /* HealthComponent.swift */, 105 | C8FA71C4223AB378003E063F /* MagicComponent.swift */, 106 | C874AA87223848B600FA152F /* InventoryComponent.swift */, 107 | ); 108 | path = CharacterComponents; 109 | sourceTree = ""; 110 | }; 111 | C874AA792238275A00FA152F /* Interface */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | C8F9F7A8223A9D610059FB1C /* StatMenu.swift */, 115 | C8FA71C6223AB6C0003E063F /* ActionMenu.swift */, 116 | C8CD774A224014EA00227751 /* TileActions.swift */, 117 | ); 118 | path = Interface; 119 | sourceTree = ""; 120 | }; 121 | C874AA7C2238435200FA152F /* Items */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | C874AA7D2238439A00FA152F /* Weapon.swift */, 125 | C874AA7F223843BD00FA152F /* Armor.swift */, 126 | C874AA81223843CB00FA152F /* AttackMove.swift */, 127 | ); 128 | path = Items; 129 | sourceTree = ""; 130 | }; 131 | C87F7DAB223157420055E617 = { 132 | isa = PBXGroup; 133 | children = ( 134 | C87F7DB6223157420055E617 /* tinyRPG */, 135 | C87F7DB5223157420055E617 /* Products */, 136 | ); 137 | sourceTree = ""; 138 | }; 139 | C87F7DB5223157420055E617 /* Products */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | C87F7DB4223157420055E617 /* tinyRPG.app */, 143 | ); 144 | name = Products; 145 | sourceTree = ""; 146 | }; 147 | C87F7DB6223157420055E617 /* tinyRPG */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | C83167B7223159A500584C0B /* MyPlayground.playground */, 151 | C87F7DBF223157420055E617 /* GameViewController.swift */, 152 | C87F7DBD223157420055E617 /* GameScene.swift */, 153 | C874AA792238275A00FA152F /* Interface */, 154 | C83167B32231582600584C0B /* Character */, 155 | C874AA7C2238435200FA152F /* Items */, 156 | C83167B62231583E00584C0B /* World */, 157 | C87F7DD12231578C0055E617 /* Support */, 158 | ); 159 | path = tinyRPG; 160 | sourceTree = ""; 161 | }; 162 | C87F7DD12231578C0055E617 /* Support */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | C87F7DB9223157420055E617 /* GameScene.sks */, 166 | C8147476223300EB00FCE476 /* Extensions.swift */, 167 | C87F7DB7223157420055E617 /* AppDelegate.swift */, 168 | C87F7DC4223157440055E617 /* Assets.xcassets */, 169 | C87F7DC1223157420055E617 /* Main.storyboard */, 170 | C87F7DC6223157440055E617 /* LaunchScreen.storyboard */, 171 | C87F7DC9223157440055E617 /* Info.plist */, 172 | C885779522393FCC0092CAF5 /* GameData.plist */, 173 | ); 174 | path = Support; 175 | sourceTree = ""; 176 | }; 177 | /* End PBXGroup section */ 178 | 179 | /* Begin PBXNativeTarget section */ 180 | C87F7DB3223157420055E617 /* tinyRPG */ = { 181 | isa = PBXNativeTarget; 182 | buildConfigurationList = C87F7DCC223157440055E617 /* Build configuration list for PBXNativeTarget "tinyRPG" */; 183 | buildPhases = ( 184 | C87F7DB0223157420055E617 /* Sources */, 185 | C87F7DB1223157420055E617 /* Frameworks */, 186 | C87F7DB2223157420055E617 /* Resources */, 187 | ); 188 | buildRules = ( 189 | ); 190 | dependencies = ( 191 | ); 192 | name = tinyRPG; 193 | productName = tinyRPG; 194 | productReference = C87F7DB4223157420055E617 /* tinyRPG.app */; 195 | productType = "com.apple.product-type.application"; 196 | }; 197 | /* End PBXNativeTarget section */ 198 | 199 | /* Begin PBXProject section */ 200 | C87F7DAC223157420055E617 /* Project object */ = { 201 | isa = PBXProject; 202 | attributes = { 203 | LastSwiftUpdateCheck = 1020; 204 | LastUpgradeCheck = 1020; 205 | ORGANIZATIONNAME = "Logan Roberts"; 206 | TargetAttributes = { 207 | C87F7DB3223157420055E617 = { 208 | CreatedOnToolsVersion = 10.2; 209 | }; 210 | }; 211 | }; 212 | buildConfigurationList = C87F7DAF223157420055E617 /* Build configuration list for PBXProject "tinyRPG" */; 213 | compatibilityVersion = "Xcode 9.3"; 214 | developmentRegion = en; 215 | hasScannedForEncodings = 0; 216 | knownRegions = ( 217 | en, 218 | Base, 219 | ); 220 | mainGroup = C87F7DAB223157420055E617; 221 | productRefGroup = C87F7DB5223157420055E617 /* Products */; 222 | projectDirPath = ""; 223 | projectRoot = ""; 224 | targets = ( 225 | C87F7DB3223157420055E617 /* tinyRPG */, 226 | ); 227 | }; 228 | /* End PBXProject section */ 229 | 230 | /* Begin PBXResourcesBuildPhase section */ 231 | C87F7DB2223157420055E617 /* Resources */ = { 232 | isa = PBXResourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | C885779622393FCC0092CAF5 /* GameData.plist in Resources */, 236 | C87F7DC3223157420055E617 /* Main.storyboard in Resources */, 237 | C87F7DBA223157420055E617 /* GameScene.sks in Resources */, 238 | C87F7DC5223157440055E617 /* Assets.xcassets in Resources */, 239 | C87F7DC8223157440055E617 /* LaunchScreen.storyboard in Resources */, 240 | C8857791223935DD0092CAF5 /* Terrain.sks in Resources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXResourcesBuildPhase section */ 245 | 246 | /* Begin PBXSourcesBuildPhase section */ 247 | C87F7DB0223157420055E617 /* Sources */ = { 248 | isa = PBXSourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | C8FA71C7223AB6C0003E063F /* ActionMenu.swift in Sources */, 252 | C874AA88223848B600FA152F /* InventoryComponent.swift in Sources */, 253 | C814747B223314E200FCE476 /* MovementComponent.swift in Sources */, 254 | C87F7DBE223157420055E617 /* GameScene.swift in Sources */, 255 | C83167B52231583B00584C0B /* MapGen.swift in Sources */, 256 | C8CD774B224014EA00227751 /* TileActions.swift in Sources */, 257 | C87F7DC0223157420055E617 /* GameViewController.swift in Sources */, 258 | C874AA7E2238439A00FA152F /* Weapon.swift in Sources */, 259 | C87F7DB8223157420055E617 /* AppDelegate.swift in Sources */, 260 | C874AA842238441000FA152F /* ExperienceComponent.swift in Sources */, 261 | C874AA7B2238277200FA152F /* StateMachine.swift in Sources */, 262 | C874AA862238445A00FA152F /* HealthComponent.swift in Sources */, 263 | C83167BA2232CEEB00584C0B /* SpriteComponent.swift in Sources */, 264 | C874AA82223843CB00FA152F /* AttackMove.swift in Sources */, 265 | C8F9F7A9223A9D610059FB1C /* StatMenu.swift in Sources */, 266 | C83167B22231582100584C0B /* Character.swift in Sources */, 267 | C874AA80223843BD00FA152F /* Armor.swift in Sources */, 268 | C8147477223300EB00FCE476 /* Extensions.swift in Sources */, 269 | C8FA71C5223AB378003E063F /* MagicComponent.swift in Sources */, 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | /* End PBXSourcesBuildPhase section */ 274 | 275 | /* Begin PBXVariantGroup section */ 276 | C87F7DC1223157420055E617 /* Main.storyboard */ = { 277 | isa = PBXVariantGroup; 278 | children = ( 279 | C87F7DC2223157420055E617 /* Base */, 280 | ); 281 | name = Main.storyboard; 282 | sourceTree = ""; 283 | }; 284 | C87F7DC6223157440055E617 /* LaunchScreen.storyboard */ = { 285 | isa = PBXVariantGroup; 286 | children = ( 287 | C87F7DC7223157440055E617 /* Base */, 288 | ); 289 | name = LaunchScreen.storyboard; 290 | sourceTree = ""; 291 | }; 292 | /* End PBXVariantGroup section */ 293 | 294 | /* Begin XCBuildConfiguration section */ 295 | C87F7DCA223157440055E617 /* Debug */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | ALWAYS_SEARCH_USER_PATHS = NO; 299 | CLANG_ANALYZER_NONNULL = YES; 300 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 301 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 302 | CLANG_CXX_LIBRARY = "libc++"; 303 | CLANG_ENABLE_MODULES = YES; 304 | CLANG_ENABLE_OBJC_ARC = YES; 305 | CLANG_ENABLE_OBJC_WEAK = YES; 306 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 307 | CLANG_WARN_BOOL_CONVERSION = YES; 308 | CLANG_WARN_COMMA = YES; 309 | CLANG_WARN_CONSTANT_CONVERSION = YES; 310 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 311 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 312 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 313 | CLANG_WARN_EMPTY_BODY = YES; 314 | CLANG_WARN_ENUM_CONVERSION = YES; 315 | CLANG_WARN_INFINITE_RECURSION = YES; 316 | CLANG_WARN_INT_CONVERSION = YES; 317 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 318 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 319 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 320 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 321 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 322 | CLANG_WARN_STRICT_PROTOTYPES = YES; 323 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 324 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 325 | CLANG_WARN_UNREACHABLE_CODE = YES; 326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 327 | CODE_SIGN_IDENTITY = "iPhone Developer"; 328 | COPY_PHASE_STRIP = NO; 329 | DEBUG_INFORMATION_FORMAT = dwarf; 330 | ENABLE_STRICT_OBJC_MSGSEND = YES; 331 | ENABLE_TESTABILITY = YES; 332 | GCC_C_LANGUAGE_STANDARD = gnu11; 333 | GCC_DYNAMIC_NO_PIC = NO; 334 | GCC_NO_COMMON_BLOCKS = YES; 335 | GCC_OPTIMIZATION_LEVEL = 0; 336 | GCC_PREPROCESSOR_DEFINITIONS = ( 337 | "DEBUG=1", 338 | "$(inherited)", 339 | ); 340 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 341 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 342 | GCC_WARN_UNDECLARED_SELECTOR = YES; 343 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 344 | GCC_WARN_UNUSED_FUNCTION = YES; 345 | GCC_WARN_UNUSED_VARIABLE = YES; 346 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 347 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 348 | MTL_FAST_MATH = YES; 349 | ONLY_ACTIVE_ARCH = YES; 350 | SDKROOT = iphoneos; 351 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 352 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 353 | }; 354 | name = Debug; 355 | }; 356 | C87F7DCB223157440055E617 /* Release */ = { 357 | isa = XCBuildConfiguration; 358 | buildSettings = { 359 | ALWAYS_SEARCH_USER_PATHS = NO; 360 | CLANG_ANALYZER_NONNULL = YES; 361 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 363 | CLANG_CXX_LIBRARY = "libc++"; 364 | CLANG_ENABLE_MODULES = YES; 365 | CLANG_ENABLE_OBJC_ARC = YES; 366 | CLANG_ENABLE_OBJC_WEAK = YES; 367 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 368 | CLANG_WARN_BOOL_CONVERSION = YES; 369 | CLANG_WARN_COMMA = YES; 370 | CLANG_WARN_CONSTANT_CONVERSION = YES; 371 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 372 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 373 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 374 | CLANG_WARN_EMPTY_BODY = YES; 375 | CLANG_WARN_ENUM_CONVERSION = YES; 376 | CLANG_WARN_INFINITE_RECURSION = YES; 377 | CLANG_WARN_INT_CONVERSION = YES; 378 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 380 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 381 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 382 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 383 | CLANG_WARN_STRICT_PROTOTYPES = YES; 384 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 385 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 386 | CLANG_WARN_UNREACHABLE_CODE = YES; 387 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 388 | CODE_SIGN_IDENTITY = "iPhone Developer"; 389 | COPY_PHASE_STRIP = NO; 390 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 391 | ENABLE_NS_ASSERTIONS = NO; 392 | ENABLE_STRICT_OBJC_MSGSEND = YES; 393 | GCC_C_LANGUAGE_STANDARD = gnu11; 394 | GCC_NO_COMMON_BLOCKS = YES; 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 402 | MTL_ENABLE_DEBUG_INFO = NO; 403 | MTL_FAST_MATH = YES; 404 | SDKROOT = iphoneos; 405 | SWIFT_COMPILATION_MODE = wholemodule; 406 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 407 | VALIDATE_PRODUCT = YES; 408 | }; 409 | name = Release; 410 | }; 411 | C87F7DCD223157440055E617 /* Debug */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 415 | CODE_SIGN_STYLE = Automatic; 416 | DEVELOPMENT_TEAM = 4CJPA6ZPGD; 417 | INFOPLIST_FILE = tinyRPG/Support/Info.plist; 418 | LD_RUNPATH_SEARCH_PATHS = ( 419 | "$(inherited)", 420 | "@executable_path/Frameworks", 421 | ); 422 | PRODUCT_BUNDLE_IDENTIFIER = loganroberts.tinyRPG; 423 | PRODUCT_NAME = "$(TARGET_NAME)"; 424 | SWIFT_VERSION = 5.0; 425 | TARGETED_DEVICE_FAMILY = "1,2"; 426 | }; 427 | name = Debug; 428 | }; 429 | C87F7DCE223157440055E617 /* Release */ = { 430 | isa = XCBuildConfiguration; 431 | buildSettings = { 432 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 433 | CODE_SIGN_STYLE = Automatic; 434 | DEVELOPMENT_TEAM = 4CJPA6ZPGD; 435 | INFOPLIST_FILE = tinyRPG/Support/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = ( 437 | "$(inherited)", 438 | "@executable_path/Frameworks", 439 | ); 440 | PRODUCT_BUNDLE_IDENTIFIER = loganroberts.tinyRPG; 441 | PRODUCT_NAME = "$(TARGET_NAME)"; 442 | SWIFT_VERSION = 5.0; 443 | TARGETED_DEVICE_FAMILY = "1,2"; 444 | }; 445 | name = Release; 446 | }; 447 | /* End XCBuildConfiguration section */ 448 | 449 | /* Begin XCConfigurationList section */ 450 | C87F7DAF223157420055E617 /* Build configuration list for PBXProject "tinyRPG" */ = { 451 | isa = XCConfigurationList; 452 | buildConfigurations = ( 453 | C87F7DCA223157440055E617 /* Debug */, 454 | C87F7DCB223157440055E617 /* Release */, 455 | ); 456 | defaultConfigurationIsVisible = 0; 457 | defaultConfigurationName = Release; 458 | }; 459 | C87F7DCC223157440055E617 /* Build configuration list for PBXNativeTarget "tinyRPG" */ = { 460 | isa = XCConfigurationList; 461 | buildConfigurations = ( 462 | C87F7DCD223157440055E617 /* Debug */, 463 | C87F7DCE223157440055E617 /* Release */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | }; 470 | rootObject = C87F7DAC223157420055E617 /* Project object */; 471 | } 472 | --------------------------------------------------------------------------------