diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index bc1bab99..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml new file mode 100644 index 00000000..e54efdd2 --- /dev/null +++ b/.github/workflows/ios.yml @@ -0,0 +1,54 @@ +name: iOS Starter Workflow + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + name: Xcode Build & Simulator Test + runs-on: macos-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 # v3 is deprecated by github + - name: Set Default Scheme + run: | + cd TowerForge + scheme_list=$(xcodebuild -list -json | tr -d "\n") + default=$(echo $scheme_list | ruby -e "require 'json'; puts JSON.parse(STDIN.gets)['project']['targets'][0]") + echo $default | cat >default + echo Using default scheme: $default + - name: Build + env: + scheme: ${{ 'default' }} + platform: ${{ 'iOS Simulator' }} + run: | + cd TowerForge + # xcrun xctrace returns via stderr, not the expected stdout (see https://developer.apple.com/forums/thread/663959) + # device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"` + device=$(xcrun simctl list devices | grep -oE 'iPad (Air|Pro \([0-9.]*-inch\)|mini) \([0-9]+(?:st|nd|rd|th) generation\)' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//") + # device=`xcrun simctl list devices 2>&1 | grep -oE 'iPad.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"` + if [ $scheme = default ]; then scheme=$(cat default); fi + if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi + file_to_build=`echo $file_to_build | awk '{$1=$1;print}'` + xcodebuild build-for-testing -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "platform=$platform,name=$device" + - name: Test + env: + scheme: ${{ 'default' }} + platform: ${{ 'iOS Simulator' }} + run: | + cd TowerForge + # xcrun xctrace returns via stderr, not the expected stdout (see https://developer.apple.com/forums/thread/663959) + # device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"` + # device=`xcrun simctl list devices 2>&1 | grep -oE 'iPad.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"` + device=$(xcrun simctl list devices | grep -oE 'iPad (Air|Pro \([0-9.]*-inch\)|mini) \([0-9]+(?:st|nd|rd|th) generation\)' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//") + if [ $scheme = default ]; then scheme=$(cat default); fi + if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi + file_to_build=`echo $file_to_build | awk '{$1=$1;print}'` + xcodebuild test-without-building -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "platform=$platform,name=$device" + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f6458314 --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +####### Global gitignore ####### + +# From https://github.com/github/gitignore/blob/master/Swift.gitignore +# +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +.DS_Store + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output + diff --git a/TowerForge/.swiftlint.yml b/TowerForge/.swiftlint.yml new file mode 100644 index 00000000..c1058632 --- /dev/null +++ b/TowerForge/.swiftlint.yml @@ -0,0 +1,88 @@ +excluded: + - Pods + +opt_in_rules: + - anyobject_protocol + - array_init + - attributes + - closure_body_length + - closure_end_indentation + - closure_spacing + - collection_alignment + - conditional_returns_on_newline + - contains_over_filter_count + - contains_over_filter_is_empty + - contains_over_first_not_nil + - contains_over_range_nil_comparison + - empty_collection_literal + - empty_count + - empty_string + - empty_xctest_method + - expiring_todo + - explicit_init + # - explicit_self moved to analyzer_rules section + - fallthrough + - fatal_error_message + - file_name + - first_where + - flatmap_over_map_reduce + - identical_operands + - implicit_return + - joined_default_parameter + - last_where + - legacy_multiple + - legacy_random + - lower_acl_than_parent + - modifier_order + - nimble_operator + - no_extension_access_modifier + - nslocalizedstring_key + - nslocalizedstring_require_bundle + - number_separator + - object_literal + - operator_usage_whitespace + - overridden_super_call + - override_in_extension + - pattern_matching_keywords + - private_action + - private_outlet + - prohibited_super_call + - quick_discouraged_call + - quick_discouraged_focused_test + - quick_discouraged_pending_test + - reduce_into + - redundant_nil_coalescing + - redundant_type_annotation + - required_enum_case + - single_test_class + - sorted_first_last + - static_operator + - strong_iboutlet + - switch_case_on_newline + - toggle_bool + - unavailable_function + - unneeded_parentheses_in_closure_argument + - unowned_variable_capture + - untyped_error_in_catch + # - unused_declaration moved to analyzer_rules section + # - unused_import moved to analyzer_rules section + - vertical_parameter_alignment_on_call + - xct_specific_matcher + - yoda_condition + +analyzer_rules: + - explicit_self + - unused_declaration + - unused_import + +disabled_rules: + - attributes + - identifier_name + - multiple_closures_with_trailing_closure # for e.g. SwiftUI buttons + - todo + - type_name + - function_default_parameter_at_end # disabled because it makes code less extensible by requiring unnecessary refactoring. + +line_length: + warning: 120 + error: 150 diff --git a/TowerForge/TowerForceTestPlan.xctestplan b/TowerForge/TowerForceTestPlan.xctestplan new file mode 100644 index 00000000..ccb4d819 --- /dev/null +++ b/TowerForge/TowerForceTestPlan.xctestplan @@ -0,0 +1,32 @@ +{ + "configurations" : [ + { + "id" : "7B4B9C82-9166-4790-89DB-195C4DBD2C39", + "name" : "Configuration 1", + "options" : { + + } + } + ], + "defaultOptions" : { + + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:TowerForge.xcodeproj", + "identifier" : "52DF5FBC2BA32B2600135367", + "name" : "TowerForgeTests" + } + }, + { + "enabled" : false, + "target" : { + "containerPath" : "container:TowerForge.xcodeproj", + "identifier" : "52DF5FC62BA32B2600135367", + "name" : "TowerForgeUITests" + } + } + ], + "version" : 1 +} diff --git a/TowerForge/TowerForge.xcodeproj/project.pbxproj b/TowerForge/TowerForge.xcodeproj/project.pbxproj index 7d860def..4de82c76 100644 --- a/TowerForge/TowerForge.xcodeproj/project.pbxproj +++ b/TowerForge/TowerForge.xcodeproj/project.pbxproj @@ -130,6 +130,7 @@ 52DF5FF82BA35D2B00135367 /* MovableComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovableComponent.swift; sourceTree = ""; }; 52DF5FFA2BA3601400135367 /* HealthComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthComponent.swift; sourceTree = ""; }; 52DF5FFE2BA3656500135367 /* ShootingComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShootingComponent.swift; sourceTree = ""; }; + BABB7C052BA9A41000D54DAE /* TowerForceTestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = TowerForceTestPlan.xctestplan; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -236,6 +237,7 @@ 52DF5F9B2BA32B2200135367 = { isa = PBXGroup; children = ( + BABB7C052BA9A41000D54DAE /* TowerForceTestPlan.xctestplan */, 52DF5FA62BA32B2300135367 /* TowerForge */, 52DF5FC02BA32B2600135367 /* TowerForgeTests */, 52DF5FCA2BA32B2600135367 /* TowerForgeUITests */, @@ -351,10 +353,10 @@ isa = PBXNativeTarget; buildConfigurationList = 52DF5FD12BA32B2600135367 /* Build configuration list for PBXNativeTarget "TowerForge" */; buildPhases = ( + 3C9955B22BA4AE6900D33FA5 /* ShellScript */, 52DF5FA02BA32B2200135367 /* Sources */, 52DF5FA12BA32B2200135367 /* Frameworks */, 52DF5FA22BA32B2200135367 /* Resources */, - 3C9955B22BA4AE6900D33FA5 /* ShellScript */, ); buildRules = ( ); @@ -476,7 +478,8 @@ /* Begin PBXShellScriptBuildPhase section */ 3C9955B22BA4AE6900D33FA5 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; + alwaysOutOfDate = 1; + buildActionMask = 12; files = ( ); inputFileListPaths = ( @@ -489,7 +492,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + shellScript = "# Conditional for swiftlint installation on Apple Silicon MacBooks\nif [[ \"$(uname -m)\" == arm64 ]]; then\n export PATH=\"/opt/homebrew/bin:$PATH\"\nfi\n\nif which swiftlint > /dev/null; then\n swiftlint --fix && swiftlint # Comment this line to disable auto-fixing of issues\n #swiftlint # then uncomment this line\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -632,7 +635,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -647,7 +650,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.2; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -695,7 +698,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -704,7 +707,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.2; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -721,15 +724,17 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U3Y75HAMMQ; + DEVELOPMENT_TEAM = ""; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UIRequiresFullScreen = YES; INFOPLIST_KEY_UIStatusBarHidden = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -754,15 +759,17 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U3Y75HAMMQ; + DEVELOPMENT_TEAM = ""; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UIRequiresFullScreen = YES; INFOPLIST_KEY_UIStatusBarHidden = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -787,15 +794,19 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U3Y75HAMMQ; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.2; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.nus.TowerForgeTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TowerForge.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/TowerForge"; }; name = Debug; @@ -807,15 +818,19 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U3Y75HAMMQ; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.2; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.nus.TowerForgeTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TowerForge.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/TowerForge"; }; name = Release; @@ -826,14 +841,19 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U3Y75HAMMQ; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.nus.TowerForgeUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 2; TEST_TARGET_NAME = TowerForge; }; name = Debug; @@ -844,14 +864,19 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U3Y75HAMMQ; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.nus.TowerForgeUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 2; TEST_TARGET_NAME = TowerForge; }; name = Release; diff --git a/TowerForge/TowerForge.xcodeproj/xcshareddata/xcschemes/TowerForge.xcscheme b/TowerForge/TowerForge.xcodeproj/xcshareddata/xcschemes/TowerForge.xcscheme new file mode 100644 index 00000000..54b937ea --- /dev/null +++ b/TowerForge/TowerForge.xcodeproj/xcshareddata/xcschemes/TowerForge.xcscheme @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TowerForge/TowerForge/AppDelegate.swift b/TowerForge/TowerForge/AppDelegate.swift index 23828dc7..f2d40a29 100644 --- a/TowerForge/TowerForge/AppDelegate.swift +++ b/TowerForge/TowerForge/AppDelegate.swift @@ -15,7 +15,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. - return true + true } func applicationWillResignActive(_ application: UIApplication) { diff --git a/TowerForge/TowerForge/GameScene.swift b/TowerForge/TowerForge/GameScene.swift index e598a58f..212f9a2c 100644 --- a/TowerForge/TowerForge/GameScene.swift +++ b/TowerForge/TowerForge/GameScene.swift @@ -9,21 +9,27 @@ import SpriteKit import GameplayKit class GameScene: SKScene { - + private var lastUpdatedTimeInterval = TimeInterval(0) private var entityManager: EntityManager? override func didMove(to view: SKView) { entityManager = EntityManager() - guard var entityManager = entityManager else { + guard let entityManager = entityManager else { return } let meleeUnit = MeleeUnit(position: CGPoint(x: 0, y: 100), - entityManager: entityManager, attackRate: 1.0, velocity: CGVector(dx: 10.0, dy: 0.0), team: Team(player: .ownPlayer)) + entityManager: entityManager, attackRate: 1.0, + velocity: CGVector(dx: 10.0, dy: 0.0), + team: Team(player: .ownPlayer)) + let soldierUnit = SoldierUnit(position: CGPoint(x: 0, y: 50), entityManager: entityManager, attackRate: 1.0, - velocity: CGVector(dx: 10.0, dy: 0.0), team: Team(player: .ownPlayer)) - let arrowTower = ArrowTower(position: CGPoint(x:0, y: 100), entityManager: entityManager) + velocity: CGVector(dx: 10.0, dy: 0.0), + team: Team(player: .ownPlayer)) + + let arrowTower = ArrowTower(position: CGPoint(x: 0, y: 100), entityManager: entityManager) + entityManager.add(meleeUnit) entityManager.add(soldierUnit) entityManager.add(arrowTower) diff --git a/TowerForge/TowerForge/GameViewController.swift b/TowerForge/TowerForge/GameViewController.swift index 4c613620..7b48c891 100644 --- a/TowerForge/TowerForge/GameViewController.swift +++ b/TowerForge/TowerForge/GameViewController.swift @@ -38,6 +38,6 @@ class GameViewController: UIViewController { } override var prefersStatusBarHidden: Bool { - return true + true } } diff --git a/TowerForge/TowerForge/LevelManager/Components/AiComponent.swift b/TowerForge/TowerForge/LevelManager/Components/AiComponent.swift index 6d667cbc..8c8b14e8 100644 --- a/TowerForge/TowerForge/LevelManager/Components/AiComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/AiComponent.swift @@ -21,7 +21,7 @@ class AiComponent: TFComponent { self.chosenUnit = UnitType.possibleUnits.randomElement() ?? .melee super.init() } - + override func update(deltaTime: TimeInterval) { guard let homeComponent = entity?.component(ofType: HomeComponent.self) else { return diff --git a/TowerForge/TowerForge/LevelManager/Components/BaseComponents/MovableComponent.swift b/TowerForge/TowerForge/LevelManager/Components/BaseComponents/MovableComponent.swift index 3a24db1c..9a3696a6 100644 --- a/TowerForge/TowerForge/LevelManager/Components/BaseComponents/MovableComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/BaseComponents/MovableComponent.swift @@ -9,8 +9,8 @@ import Foundation import CoreGraphics class MovableComponent: TFComponent { - public var velocity: CGVector - public var position: CGPoint + var velocity: CGVector + var position: CGPoint init(position: CGPoint, velocity: CGVector = .zero) { self.velocity = velocity @@ -25,9 +25,11 @@ class MovableComponent: TFComponent { let playerComponent = entity.component(ofType: PlayerComponent.self) else { return } + let directionVelocity = playerComponent.player.getDirectionVelocity() let finalX = positionComponent.position.x + (velocity.dx * CGFloat(deltaTime) * directionVelocity.dx) let finalY = positionComponent.position.y + (velocity.dy * CGFloat(deltaTime) * directionVelocity.dy) + positionComponent.changeTo(to: CGPoint(x: finalX, y: finalY)) spriteComponent.node.position = positionComponent.position print(spriteComponent.node.position) diff --git a/TowerForge/TowerForge/LevelManager/Components/BaseComponents/PositionComponent.swift b/TowerForge/TowerForge/LevelManager/Components/BaseComponents/PositionComponent.swift index 521cb0cc..9681bf84 100644 --- a/TowerForge/TowerForge/LevelManager/Components/BaseComponents/PositionComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/BaseComponents/PositionComponent.swift @@ -10,10 +10,12 @@ import CoreGraphics class PositionComponent: TFComponent { var position: CGPoint + init(position: CGPoint) { self.position = position super.init() } + func changeTo(to position: CGPoint) { guard let entity = entity, let spriteComponent = entity.component(ofType: SpriteComponent.self) else { return diff --git a/TowerForge/TowerForge/LevelManager/Components/BaseComponents/SpriteComponent.swift b/TowerForge/TowerForge/LevelManager/Components/BaseComponents/SpriteComponent.swift index 880e1904..143447f2 100644 --- a/TowerForge/TowerForge/LevelManager/Components/BaseComponents/SpriteComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/BaseComponents/SpriteComponent.swift @@ -8,7 +8,7 @@ import Foundation class SpriteComponent: TFComponent { - public var node: TFAnimatableNode + var node: TFAnimatableNode init(textureNames: [String], height: CGFloat, width: CGFloat, position: CGPoint, animatableKey: String) { let textures = TFTextures(textureNames: textureNames, textureAtlasName: "Sprites") diff --git a/TowerForge/TowerForge/LevelManager/Components/GameComponents/CostComponent.swift b/TowerForge/TowerForge/LevelManager/Components/GameComponents/CostComponent.swift index aa7e361a..aa61a6a6 100644 --- a/TowerForge/TowerForge/LevelManager/Components/GameComponents/CostComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/GameComponents/CostComponent.swift @@ -8,7 +8,7 @@ import Foundation class CostComponent: TFComponent { - public var cost: CGFloat + var cost: CGFloat init(cost: CGFloat) { self.cost = cost } diff --git a/TowerForge/TowerForge/LevelManager/Components/GameComponents/DamageComponent.swift b/TowerForge/TowerForge/LevelManager/Components/GameComponents/DamageComponent.swift index 5bfa77ca..7009d179 100644 --- a/TowerForge/TowerForge/LevelManager/Components/GameComponents/DamageComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/GameComponents/DamageComponent.swift @@ -14,7 +14,8 @@ class DamageComponent: TFComponent { private var lastAttackTime = TimeInterval(0) private let entityManager: EntityManager private let temporary: Bool - public let attackPower: CGFloat + let attackPower: CGFloat + init(attackRate: TimeInterval, attackPower: CGFloat, temporary: Bool, entityManager: EntityManager) { self.attackRate = attackRate self.attackPower = attackPower @@ -22,16 +23,16 @@ class DamageComponent: TFComponent { self.temporary = temporary super.init() } - + override func update(deltaTime: TimeInterval) { super.update(deltaTime: deltaTime) - + // Required components for the current Melee guard let entity = entity, let spriteComponent = entity.component(ofType: SpriteComponent.self) else { return } - + // Loop opposite team's entities for entity in entityManager.entities { guard let playerComponent = entity.component(ofType: PlayerComponent.self) else { @@ -47,16 +48,18 @@ class DamageComponent: TFComponent { } // Check collision with opposite team sprite component - if(oppositeSpriteComponent.node.calculateAccumulatedFrame().intersects(spriteComponent.node.calculateAccumulatedFrame())) { - + if oppositeSpriteComponent.node + .calculateAccumulatedFrame().intersects( + spriteComponent.node.calculateAccumulatedFrame()) { + // Check if can attack - if(CACurrentMediaTime() - lastAttackTime > attackRate) { + if CACurrentMediaTime() - lastAttackTime > attackRate { lastAttackTime = CACurrentMediaTime() oppositeHealthComponent.decreaseHealth(amount: attackPower) } - + } - + // If only used once, then remove from entity if temporary { entityManager.removeEntity(with: entity.id) diff --git a/TowerForge/TowerForge/LevelManager/Components/GameComponents/HealthComponent.swift b/TowerForge/TowerForge/LevelManager/Components/GameComponents/HealthComponent.swift index 19027be8..76880f53 100644 --- a/TowerForge/TowerForge/LevelManager/Components/GameComponents/HealthComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/GameComponents/HealthComponent.swift @@ -8,8 +8,8 @@ import Foundation class HealthComponent: TFComponent { - public var currentHealth: CGFloat - public var maxHealth: CGFloat + var currentHealth: CGFloat + var maxHealth: CGFloat private let entityManager: EntityManager init(maxHealth: CGFloat, entityManager: EntityManager) { @@ -18,7 +18,7 @@ class HealthComponent: TFComponent { self.entityManager = entityManager super.init() } - + override func update(deltaTime: TimeInterval) { if self.currentHealth <= 0 { guard let entity = entity, diff --git a/TowerForge/TowerForge/LevelManager/Components/GameComponents/ShootingComponent.swift b/TowerForge/TowerForge/LevelManager/Components/GameComponents/ShootingComponent.swift index 6fc0a670..a3440b98 100644 --- a/TowerForge/TowerForge/LevelManager/Components/GameComponents/ShootingComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/GameComponents/ShootingComponent.swift @@ -13,7 +13,7 @@ class ShootingComponent: TFComponent { var range: CGFloat private var lastShotTime = TimeInterval(0) private let entityManager: EntityManager - public let attackPower: CGFloat + let attackPower: CGFloat init(fireRate: TimeInterval, range: CGFloat, entityManager: EntityManager, attackPower: CGFloat) { self.fireRate = fireRate @@ -25,14 +25,14 @@ class ShootingComponent: TFComponent { override func update(deltaTime: TimeInterval) { super.update(deltaTime: deltaTime) - + // Required components for the current Melee guard let entity = entity, let spriteComponent = entity.component(ofType: SpriteComponent.self), let positionComponent = entity.component(ofType: PositionComponent.self) else { return } - + // Loop opposite team's entities for entity in entityManager.entities { guard let playerComponent = entity.component(ofType: PlayerComponent.self) else { @@ -47,12 +47,12 @@ class ShootingComponent: TFComponent { let oppositePositionComponent = entity.component(ofType: PositionComponent.self) else { return } - + // Get the horizontal distance let distanceBetween = (positionComponent.position.x - oppositePositionComponent.position.x) - + // Check if within range - if(distanceBetween < range) { + if distanceBetween < range { // TODO : Change the hard coded velocity value let arrow = Arrow(position: positionComponent.position, velocity: playerComponent.player.getDirectionVelocity(), @@ -61,10 +61,12 @@ class ShootingComponent: TFComponent { guard let arrowSpriteComponent = arrow.component(ofType: SpriteComponent.self) else { return } + // Check if can attack if CACurrentMediaTime() - lastShotTime > fireRate { lastShotTime = CACurrentMediaTime() } - } } + } + } } } diff --git a/TowerForge/TowerForge/LevelManager/Components/HomeComponent.swift b/TowerForge/TowerForge/LevelManager/Components/HomeComponent.swift index 3c395f20..7aec4c44 100644 --- a/TowerForge/TowerForge/LevelManager/Components/HomeComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/HomeComponent.swift @@ -9,8 +9,8 @@ import Foundation import SpriteKit class HomeComponent: TFComponent { - public var lifeLeft: Int - public var points = 0 + var lifeLeft: Int + var points = 0 private var lastPointIncrease = TimeInterval(0) private var pointInterval: TimeInterval private var pointsPerInterval: Int = 10 @@ -30,11 +30,9 @@ class HomeComponent: TFComponent { override func update(deltaTime: TimeInterval) { super.update(deltaTime: deltaTime) // Points update - if(CACurrentMediaTime() - lastPointIncrease > pointInterval) { + if CACurrentMediaTime() - lastPointIncrease > pointInterval { lastPointIncrease = CACurrentMediaTime() points += self.pointsPerInterval } } } - - diff --git a/TowerForge/TowerForge/LevelManager/Components/PlayerComponent.swift b/TowerForge/TowerForge/LevelManager/Components/PlayerComponent.swift index 31b0f658..081c40ba 100644 --- a/TowerForge/TowerForge/LevelManager/Components/PlayerComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/PlayerComponent.swift @@ -11,7 +11,7 @@ import SpriteKit public enum Player: Int { case ownPlayer = 1 case oppositePlayer = 2 - + func getOppositePlayer() -> Player { switch self { case .ownPlayer: @@ -20,7 +20,7 @@ public enum Player: Int { return .ownPlayer } } - + func getDirectionVelocity() -> CGVector { switch self { case .ownPlayer: @@ -32,11 +32,9 @@ public enum Player: Int { } class PlayerComponent: TFComponent { - public var player: Player + var player: Player init(player: Player) { self.player = player super.init() } } - - diff --git a/TowerForge/TowerForge/LevelManager/Entities/BaseProjectile.swift b/TowerForge/TowerForge/LevelManager/Entities/BaseProjectile.swift index 1781b013..e5433f3d 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/BaseProjectile.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/BaseProjectile.swift @@ -28,6 +28,7 @@ class BaseProjectile: TFEntity { let positionComponent = PositionComponent(position: position) self.addComponent(positionComponent) } + private func createMovableComponent(position: CGPoint, velocity: CGVector) { let movableComponent = MovableComponent(position: position, velocity: velocity) self.addComponent(movableComponent) diff --git a/TowerForge/TowerForge/LevelManager/Entities/BaseUnit.swift b/TowerForge/TowerForge/LevelManager/Entities/BaseUnit.swift index 6151099b..1be08fa0 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/BaseUnit.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/BaseUnit.swift @@ -8,7 +8,7 @@ import Foundation class BaseUnit: TFEntity, HasCost { - var cost: Int + var cost: Int init(textureNames: [String], size: CGSize, key: String, diff --git a/TowerForge/TowerForge/LevelManager/Entities/SoldierUnit.swift b/TowerForge/TowerForge/LevelManager/Entities/SoldierUnit.swift index ff831bff..5b6daad7 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/SoldierUnit.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/SoldierUnit.swift @@ -25,6 +25,7 @@ class SoldierUnit: BaseUnit { cost: SoldierUnit.cost, velocity: velocity, team: team) + self.addComponent(ShootingComponent(fireRate: attackRate, range: 1.0, entityManager: entityManager, diff --git a/TowerForge/TowerForge/LevelManager/Entities/Team.swift b/TowerForge/TowerForge/LevelManager/Entities/Team.swift index 0cb2e3f1..98fd575e 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/Team.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/Team.swift @@ -10,12 +10,13 @@ import Foundation class Team: TFEntity { static let lifeCount = 5 static let pointsInterval = TimeInterval(0.5) - public var player: Player + var player: Player init(player: Player) { self.player = player super.init() createPlayerComponent(player: player) } + private func createPlayerComponent(player: Player) { let playerComponent = PlayerComponent(player: player) self.addComponent(playerComponent) diff --git a/TowerForge/TowerForge/LevelManager/EntityManager.swift b/TowerForge/TowerForge/LevelManager/EntityManager.swift index fbd26475..a5ba14b9 100644 --- a/TowerForge/TowerForge/LevelManager/EntityManager.swift +++ b/TowerForge/TowerForge/LevelManager/EntityManager.swift @@ -41,6 +41,7 @@ class EntityManager { func components(ofType type: T.Type) -> [T] { entities.compactMap { $0.component(ofType: type) } } + // TODO update to be changed to systems func update(_ deltaTime: TimeInterval) { for entity in entities { diff --git a/TowerForge/TowerForge/LevelManager/Events/Implemented Events/DamageEvent.swift b/TowerForge/TowerForge/LevelManager/Events/Implemented Events/DamageEvent.swift index aa42edfe..49db0cbe 100644 --- a/TowerForge/TowerForge/LevelManager/Events/Implemented Events/DamageEvent.swift +++ b/TowerForge/TowerForge/LevelManager/Events/Implemented Events/DamageEvent.swift @@ -18,7 +18,7 @@ struct DamageEvent: TFEvent { self.entityId = entityId self.damage = damage } - + func execute(in target: any EventTarget) -> EventOutput { target.system(ofType: HealthSystem.self) // TODO: Handle Damge Event return EventOutput() diff --git a/TowerForge/TowerForge/LevelManager/Events/TFEvent.swift b/TowerForge/TowerForge/LevelManager/Events/TFEvent.swift index 6261ffd5..1cd7cc79 100644 --- a/TowerForge/TowerForge/LevelManager/Events/TFEvent.swift +++ b/TowerForge/TowerForge/LevelManager/Events/TFEvent.swift @@ -10,7 +10,7 @@ import Foundation protocol TFEvent { var timestamp: TimeInterval { get } var entityId: UUID { get } - + func execute(in target: EventTarget) -> EventOutput } diff --git a/TowerForge/TowerForge/LevelManager/Generators/UnitGenerator.swift b/TowerForge/TowerForge/LevelManager/Generators/UnitGenerator.swift index 4a8c0300..9db26816 100644 --- a/TowerForge/TowerForge/LevelManager/Generators/UnitGenerator.swift +++ b/TowerForge/TowerForge/LevelManager/Generators/UnitGenerator.swift @@ -8,7 +8,7 @@ import Foundation class UnitGenerator { - public static func spawnMelee(at position: CGPoint, player: Player, entityManager: EntityManager) { + static func spawnMelee(at position: CGPoint, player: Player, entityManager: EntityManager) { // TODO: Change the default value and abstract as constant let unit = MeleeUnit(position: position, entityManager: entityManager, @@ -19,7 +19,7 @@ class UnitGenerator { spriteComponent?.node.position = position entityManager.add(unit) } - public static func spawnSoldier(at position: CGPoint, player: Player, entityManager: EntityManager) { + static func spawnSoldier(at position: CGPoint, player: Player, entityManager: EntityManager) { // TODO: Change the default value and abstract as constant let unit = SoldierUnit(position: position, entityManager: entityManager, diff --git a/TowerForge/TowerForge/LevelManager/Systems/MovementSystem.swift b/TowerForge/TowerForge/LevelManager/Systems/MovementSystem.swift index 26aa7a89..3a093f49 100644 --- a/TowerForge/TowerForge/LevelManager/Systems/MovementSystem.swift +++ b/TowerForge/TowerForge/LevelManager/Systems/MovementSystem.swift @@ -8,5 +8,5 @@ import Foundation class MovementSystem: TFSystem { - + } diff --git a/TowerForge/TowerForge/LevelManager/Systems/SpawnSystem.swift b/TowerForge/TowerForge/LevelManager/Systems/SpawnSystem.swift index 1d3a651b..41779826 100644 --- a/TowerForge/TowerForge/LevelManager/Systems/SpawnSystem.swift +++ b/TowerForge/TowerForge/LevelManager/Systems/SpawnSystem.swift @@ -8,5 +8,5 @@ import Foundation class SpawnSystem: TFSystem { - + } diff --git a/TowerForge/TowerForge/LevelManager/TFComponent.swift b/TowerForge/TowerForge/LevelManager/TFComponent.swift index 1a81cc0f..5cba87f9 100644 --- a/TowerForge/TowerForge/LevelManager/TFComponent.swift +++ b/TowerForge/TowerForge/LevelManager/TFComponent.swift @@ -8,7 +8,7 @@ import Foundation class TFComponent: Identifiable { - public var id = UUID() + var id = UUID() weak var entity: TFEntity? init() { @@ -20,6 +20,7 @@ class TFComponent: Identifiable { // Notify when the component is added to an entity. // This reference provides components other access to components // from the same entity, to allow collaboration in the ECS framework + func didAddToEntity(_ entity: TFEntity) { self.entity = entity } diff --git a/TowerForge/TowerForge/TFCore/TFNode.swift b/TowerForge/TowerForge/TFCore/TFNode.swift index 8236244f..bef64f34 100644 --- a/TowerForge/TowerForge/TFCore/TFNode.swift +++ b/TowerForge/TowerForge/TFCore/TFNode.swift @@ -10,9 +10,9 @@ import SpriteKit import CoreGraphics class TFNode: SKSpriteNode { - public var textures: TFTextures? - public var width: CGFloat - public var height: CGFloat + var textures: TFTextures? + var width: CGFloat + var height: CGFloat init(textures: TFTextures?, height: CGFloat, width: CGFloat) { if let textures = textures { diff --git a/TowerForge/TowerForge/TFCore/TFTextures.swift b/TowerForge/TowerForge/TFCore/TFTextures.swift index cea58547..1506129c 100644 --- a/TowerForge/TowerForge/TFCore/TFTextures.swift +++ b/TowerForge/TowerForge/TFCore/TFTextures.swift @@ -9,8 +9,8 @@ import Foundation import SpriteKit class TFTextures { - public var textures: [SKTexture] - public var mainTexture: SKTexture + var textures: [SKTexture] + var mainTexture: SKTexture init(textureNames: [String], textureAtlasName: String, mainTextureName: String? = nil) { let textureAtlas = SKTextureAtlas(named: textureAtlasName) diff --git a/TowerForge/TowerForgeTests/TFCoreTests/TFTexturesTests.swift b/TowerForge/TowerForgeTests/TFCoreTests/TFTexturesTests.swift index 6ec9ac1e..b4bf902f 100644 --- a/TowerForge/TowerForgeTests/TFCoreTests/TFTexturesTests.swift +++ b/TowerForge/TowerForgeTests/TFCoreTests/TFTexturesTests.swift @@ -5,11 +5,11 @@ //// Created by Vanessa Mae on 14/03/24. //// // -//import XCTest -//import SpriteKit -//@testable import TowerForge +// import XCTest +// import SpriteKit +// @testable import TowerForge // -//final class TFTexturesTests: XCTestCase { +// final class TFTexturesTests: XCTestCase { // // func testTexturesInitialization() throws { // let sampleTextureNames = ["texture1", "texture2", "texture3"] @@ -20,6 +20,7 @@ // textureAtlasName: textureAtlasName, // mainTextureName: mainTextureName) // // Verify that the main texture is set correctly -// XCTAssertEqual(tfTextures.mainTexture, SKTexture(imageNamed: mainTextureName), "Main texture should be 'texture2'") +// XCTAssertEqual(tfTextures.mainTexture, SKTexture(imageNamed: mainTextureName), +// "Main texture should be 'texture2'") // } -//} +// } diff --git a/TowerForge/TowerForgeTests/TowerForgeTests.swift b/TowerForge/TowerForgeTests/TowerForgeTests.swift index 5cbb3c99..8212725e 100644 --- a/TowerForge/TowerForgeTests/TowerForgeTests.swift +++ b/TowerForge/TowerForgeTests/TowerForgeTests.swift @@ -1,17 +1,10 @@ -// -// TowerForgeTests.swift -// TowerForgeTests -// -// Created by Vanessa Mae on 14/03/24. -// - import XCTest @testable import TowerForge final class TowerForgeTests: XCTestCase { override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. + // Put setup code here. This method is called before the invocation of each test method in the class. } override func tearDownWithError() throws { @@ -19,11 +12,7 @@ final class TowerForgeTests: XCTestCase { } func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + XCTAssertTrue(true) } func testPerformanceExample() throws { diff --git a/TowerForge/TowerForgeUITests/TowerForgeUITests.swift b/TowerForge/TowerForgeUITests/TowerForgeUITests.swift index ce767fc6..40db2051 100644 --- a/TowerForge/TowerForgeUITests/TowerForgeUITests.swift +++ b/TowerForge/TowerForgeUITests/TowerForgeUITests.swift @@ -1,10 +1,3 @@ -// -// TowerForgeUITests.swift -// TowerForgeUITests -// -// Created by Vanessa Mae on 14/03/24. -// - import XCTest final class TowerForgeUITests: XCTestCase { @@ -15,7 +8,8 @@ final class TowerForgeUITests: XCTestCase { // In UI tests it is usually best to stop immediately when a failure occurs. continueAfterFailure = false - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + // In UI tests it’s important to set the initial state - such as interface orientation + // - required for your tests before they run. The setUp method is a good place to do this. } override func tearDownWithError() throws { diff --git a/TowerForge/TowerForgeUITests/TowerForgeUITestsLaunchTests.swift b/TowerForge/TowerForgeUITests/TowerForgeUITestsLaunchTests.swift index d55aa392..306eea56 100644 --- a/TowerForge/TowerForgeUITests/TowerForgeUITestsLaunchTests.swift +++ b/TowerForge/TowerForgeUITests/TowerForgeUITestsLaunchTests.swift @@ -1,10 +1,3 @@ -// -// TowerForgeUITestsLaunchTests.swift -// TowerForgeUITests -// -// Created by Vanessa Mae on 14/03/24. -// - import XCTest final class TowerForgeUITestsLaunchTests: XCTestCase { @@ -18,6 +11,7 @@ final class TowerForgeUITestsLaunchTests: XCTestCase { } func testLaunch() throws { + let app = XCUIApplication() app.launch() diff --git a/TowerForge/forcerun.txt b/TowerForge/forcerun.txt new file mode 100644 index 00000000..a1b26bcb --- /dev/null +++ b/TowerForge/forcerun.txt @@ -0,0 +1,4 @@ +Edit this textfile to force a change that can be committed to the repo to trigger a build automation test. + + +test