Post

Replies

Boosts

Views

Activity

How to integrate UIDevice rotation and creating a new UIBezierPath after rotation?
How to integrate UIDevice rotation and creating a new UIBezierPath after rotation? My challenge here is to successfully integrate UIDevice rotation and creating a new UIBezierPath every time the UIDevice is rotated. (Please accept my apologies for this Post’s length .. but I can’t seem to avoid it) As a preamble, I have bounced back and forth between NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: UIDevice.orientationDidChangeNotification, object: nil) called within my viewDidLoad() together with @objc func rotated() { } and override func viewWillLayoutSubviews() { // please see code below } My success was much better when I implemented viewWillLayoutSubviews(), versus rotated() .. so let me provide detailed code just for viewWillLayoutSubviews(). I have concluded that every time I rotate the UIDevice, a new UIBezierPath needs to be generated because positions and sizes of my various SKSprieNodes change. I am definitely not saying that I have to create a new UIBezierPath with every rotation .. just saying I think I have to. Start of Code // declared at the top of my `GameViewController`: var myTrain: SKSpriteNode! var savedTrainPosition: CGPoint? var trackOffset = 60.0 var trackRect: CGRect! var trainPath: UIBezierPath! My UIBezierPath creation and SKAction.follow code is as follows: // called with my setTrackPaths() – see way below func createTrainPath() { // savedTrainPosition initially set within setTrackPaths() // and later reset when stopping + resuming moving myTrain // via stopFollowTrainPath() trackRect = CGRect(x: savedTrainPosition!.x, y: savedTrainPosition!.y, width: tracksWidth, height: tracksHeight) trainPath = UIBezierPath(ovalIn: trackRect) trainPath = trainPath.reversing() // makes myTrain move CW } // createTrainPath func startFollowTrainPath() { let theSpeed = Double(5*thisSpeed) var trainAction = SKAction.follow( trainPath.cgPath, asOffset: false, orientToPath: true, speed: theSpeed) trainAction = SKAction.repeatForever(trainAction) createPivotNodeFor(myTrain) myTrain.run(trainAction, withKey: runTrainKey) } // startFollowTrainPath func stopFollowTrainPath() { guard myTrain == nil else { myTrain.removeAction(forKey: runTrainKey) savedTrainPosition = myTrain.position return } } // stopFollowTrainPath Here is the detailed viewWillLayoutSubviews I promised earlier: override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() if (thisSceneName == "GameScene") { // code to pause moving game pieces setGamePieceParms() // for GamePieces, e.g., trainWidth setTrackPaths() // for trainPath reSizeAndPositionNodes() // code to resume moving game pieces } // if (thisSceneName == "GameScene") } // viewWillLayoutSubviews func setGamePieceParms() { if (thisSceneName == "GameScene") { roomScale = 1.0 let roomRect = UIScreen.main.bounds roomWidth = roomRect.width roomHeight = roomRect.height roomPosX = 0.0 roomPosY = 0.0 tracksScale = 1.0 tracksWidth = roomWidth - 4*trackOffset // inset from screen edge #if os(iOS) if UIDevice.current.orientation.isLandscape { tracksHeight = 0.30*roomHeight } else { tracksHeight = 0.38*roomHeight } #endif // center horizontally tracksPosX = roomPosX // flush with bottom of UIScreen let temp = roomPosY - roomHeight/2 tracksPosY = temp + trackOffset + tracksHeight/2 trainScale = 2.8 trainWidth = 96.0*trainScale // original size = 96 x 110 trainHeight = 110.0*trainScale trainPosX = roomPosX #if os(iOS) if UIDevice.current.orientation.isLandscape { trainPosY = temp + trackOffset + tracksHeight + 0.30*trainHeight } else { trainPosY = temp + trackOffset + tracksHeight + 0.20*trainHeight } #endif } // setGamePieceParms // a work in progress func setTrackPaths() { if (thisSceneName == "GameScene") { if (savedTrainPosition == nil) { savedTrainPosition = CGPoint(x: tracksPosX - tracksWidth/2, y: tracksPosY) } else { savedTrainPosition = CGPoint(x: tracksPosX - tracksWidth/2, y: tracksPosY) } createTrainPath() } // if (thisSceneName == "GameScene") } // setTrackPaths func reSizeAndPositionNodes() { myTracks.size = CGSize(width: tracksWidth, height: tracksHeight) myTracks.position = CGPoint(x: tracksPosX, y: tracksPosY) // more Nodes here .. } End of Code My theory says when I call setTrackPaths() with every UIDevice rotation, createTrainPath() is called. Nothing happens of significance visually as far as the UIBezierPath is concerned .. until I call startFollowTrainPath(). Bottom Line It is then that I see for sure that a new UIBezierPath has not been created as it should have been when I called createTrainPath() when I rotated the UIDevice. The new UIBezierPath is not new, but the old one. If you’ve made it this far through my long code, the question is what do I need to do to make a new UIBezierPath that fits the resized and repositioned SKSpriteNode?
8
0
1.5k
Feb ’24
100% Inappropriate Behavior of a App Reviewer
Someone somewhere in Apple Development needs to do something. This just cannot be allowed to continue. This has been reported by many others before me .. but nothing changes. What their Reviewers do borders on Assault which is a Crime. How much longer? The very capable folk such as Quinn are tarnished by working along side some of the Reviewers. I truly feel sorry for Quinn. Submitted my Monster Paddle Pong App that operates on Apple TV and iPad with a Game Controller.  SO the Tester uploads my App to their iPad and starts poking their finger all over the screen .. and NOTHING happens.  Maybe their reading skills aren’t ample because that Game Controller requirement is delineated in sentence #1.  Promotional Text: Monster Paddle Pong is FUN! to play on a iPad + Apple TV with a Extended Game Controller. Match wits with your skill to react quickly. See the Description for more info. Description Text: Monster Paddle Pong is FUN! to play on a iPad or Apple TV with a Game Controller. It mischievously matches wits with your skill to react quickly. It's 100% free, so give it a GO!  Pressing the Right Shoulder Button starts the Game and causes the Dinossaur Ball to start moving .. and unless the Ball is moving the Monster Paddle will not move. As a matter of fact, until this Right Shoulder Button is first pressed, only the Left Shoulder Button works (described below). This makes sense because after all what’s so hard in hitting a stationary target? Right? Use your Game Controller’s A, B, X, Y buttons & the Joysticks to move the Monster Paddle and hit the moving Dinossaur Ball. If you’re successful then your Score in the upper right corner advances. If instead your Monster Paddle hits one of the 4 Walls, your score decreases by 1. All this is graphically depicted in the About Scene which can be accessed by pressing your Controller’s Left Shoulder Button once. BTW, press this Left Shoulder a 2nd time, and you will see my Credits Scene. I don’t want to get too detailed here because a big part of FUN! is the thrill of Discovering. So, feel free to DISCOVER, most notably pressing all the buttons on your Controller to see the MAGIC! each of them makes happen.
9
0
1.8k
Feb ’23
Too complex to compile after update to Xcode 14.3.1
Too Complex to Compile? Ventura 13.4.1 New error after update to Xcode 14.3.1 from 14.3.0 // ... <= -(roomHeight/2 - kFudge) too complex to compile ?? if (playerPosY - playerHeight/2) <= (kFudge - roomHeight/2) { // ... this variation works, the previous one doesn't } kFudge and the other parms are declared Double! within AppDelegate. I don't understand what is suddenly wrong after Xcode update.
9
0
1.1k
Jun ’23
Using Swift, how do I *continuously* test for a GamePad being on/connected?
Using Swift, how do I continuously test for a GamePad being on/connected? When you build a Browser-based Canvas + Javascript Game, you do the above via: function listenForGamepadConnected() {     window.addEventListener("gamepadconnected", (event) => {                // this is the BIGEE that is always testing     }); }   // listenForGamepadConnected And it definitely works! I cannot find its equivalent in the Xcode/Swift world? I do see the following that’s built into a boilerplate Game that you initially create using Xcode - but it seems that it just looks once, versus continuously:     func ObserveForGameControllers() {                          NotificationCenter.default.addObserver(                     self,                     selector: #selector(connectControllers),                     name: NSNotification.Name.GCControllerDidConnect,                     object: nil)                 NotificationCenter.default.addObserver(                     self,                     selector: #selector(disconnectControllers),                     name: NSNotification.Name.GCControllerDidDisconnect,                     object: nil)             }   // ObserveForGameControllers                  @objc func connectControllers() {                 // Unpause the Game if it is currently paused         self.isPaused = false                 // Used to register the Nimbus Controllers to a specific Player Number         var indexNumber = 0         // Run through each controller currently connected to the system         for controller in GCController.controllers() {                         // Check to see whether it is an extended Game Controller (Such as a Nimbus)             if controller.extendedGamepad != nil {                 print("CONNECTED - Extended Gamepad #\(indexNumber)")                                  controller.playerIndex = GCControllerPlayerIndex.init(rawValue: indexNumber)!                                  indexNumber += 1                 setupControllerControls(controller: controller)             }             else {                 print("CONNECTED - but, NOT an Extended Gamepad #\(indexNumber)")             }                     }             }   // connectControllers          @objc func disconnectControllers() {                 print("DIS-CONNECTED")         // Pause the Game if a controller is disconnected ~ This is mandated by Apple         self.isPaused = true             }   // disconnectControllers I try to call it in a Timer loop, but still does not work:     @objc func testForGamepadIsConnected() {         ObserveForGameControllers         var gamepadOn = !self.isPaused   // does not work             }   // testForGamepadIsConnected     func startTestForGamepad() {         guard (gamepadTimer != nil) else {             gamepadTimer = Timer.scheduledTimer(                                     timeInterval: 1.0,                                     target: self,                                     selector:#selector(testForGamepadIsConnected),                                     userInfo: nil,                                     repeats: true)             return         }     }   // startTestForGamepad     func stopTestForGamepad() {         guard (gamepadTimer == nil) else {             gamepadTimer!.invalidate()             // .invalidate() removes Timer() from gamepadTimer, so reinitialize it.             gamepadTimer = Timer()             return         }     }   // stopTestForGamepad Scoured the Google world, but I’ve come up empty. Would appreciate some genius out there providing what I’m missing. Thanks loads.
17
0
2.5k
Apr ’23