From 6e081d1f073041b373c54248a3743b66f87c730e Mon Sep 17 00:00:00 2001 From: tobias <thinkdifferent055@gmail.com> Date: Sun, 9 Jul 2017 22:04:08 +0200 Subject: [PATCH] Improve pacman moving; Cleanup code --- Pacman3D-iOS.xcodeproj/project.pbxproj | 12 +- Pacman3D-iOS/GameViewController.swift | 145 +++++-------------------- Pacman3D-iOS/Level.swift | 36 ++++++ Pacman3D-iOS/MotionInput.swift | 47 ++++++++ Pacman3D-iOS/Player.swift | 66 +++++++++++ Pacman3D-iOS/TouchInputHandler.swift | 25 +++++ 6 files changed, 212 insertions(+), 119 deletions(-) create mode 100644 Pacman3D-iOS/MotionInput.swift create mode 100644 Pacman3D-iOS/TouchInputHandler.swift diff --git a/Pacman3D-iOS.xcodeproj/project.pbxproj b/Pacman3D-iOS.xcodeproj/project.pbxproj index 7a725d6..f61ba54 100644 --- a/Pacman3D-iOS.xcodeproj/project.pbxproj +++ b/Pacman3D-iOS.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + F6621DF41F12B09800F9E486 /* TouchInputHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6621DF31F12B09800F9E486 /* TouchInputHandler.swift */; }; + F6621DF61F12B82200F9E486 /* MotionInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6621DF51F12B82200F9E486 /* MotionInput.swift */; }; F6BEB8071EF7F99B00EDAA66 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6BEB8061EF7F99B00EDAA66 /* AppDelegate.swift */; }; F6BEB8091EF7F99B00EDAA66 /* art.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = F6BEB8081EF7F99B00EDAA66 /* art.scnassets */; }; F6BEB80B1EF7F99B00EDAA66 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6BEB80A1EF7F99B00EDAA66 /* GameViewController.swift */; }; @@ -42,6 +44,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + F6621DF31F12B09800F9E486 /* TouchInputHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchInputHandler.swift; sourceTree = "<group>"; }; + F6621DF51F12B82200F9E486 /* MotionInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MotionInput.swift; sourceTree = "<group>"; }; F6BEB8031EF7F99B00EDAA66 /* Pacman3D-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Pacman3D-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; F6BEB8061EF7F99B00EDAA66 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; F6BEB8081EF7F99B00EDAA66 /* art.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = art.scnassets; sourceTree = "<group>"; }; @@ -116,10 +120,12 @@ F6FEE7141EF80AB900C1DE35 /* Level */, F6FEE7191EF80C1900C1DE35 /* Uilts */, F6BEB8061EF7F99B00EDAA66 /* AppDelegate.swift */, - F6BEB8081EF7F99B00EDAA66 /* art.scnassets */, F6BEB80A1EF7F99B00EDAA66 /* GameViewController.swift */, - F6BEB80C1EF7F99B00EDAA66 /* Main.storyboard */, + F6621DF31F12B09800F9E486 /* TouchInputHandler.swift */, + F6621DF51F12B82200F9E486 /* MotionInput.swift */, + F6BEB8081EF7F99B00EDAA66 /* art.scnassets */, F6BEB80F1EF7F99B00EDAA66 /* Assets.xcassets */, + F6BEB80C1EF7F99B00EDAA66 /* Main.storyboard */, F6BEB8111EF7F99B00EDAA66 /* LaunchScreen.storyboard */, F6BEB8141EF7F99B00EDAA66 /* Info.plist */, F6FEE71A1EF8135200C1DE35 /* level.plv */, @@ -305,9 +311,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F6621DF61F12B82200F9E486 /* MotionInput.swift in Sources */, F6E4AE451F0CF1DF004BFDBF /* Direction.swift in Sources */, F6FEE7181EF80C1500C1DE35 /* StreamReader.swift in Sources */, F6FEE7161EF80AD500C1DE35 /* Level.swift in Sources */, + F6621DF41F12B09800F9E486 /* TouchInputHandler.swift in Sources */, F6BEB80B1EF7F99B00EDAA66 /* GameViewController.swift in Sources */, F6BEB8071EF7F99B00EDAA66 /* AppDelegate.swift in Sources */, F6E4AE431F0CEC6C004BFDBF /* Monster.swift in Sources */, diff --git a/Pacman3D-iOS/GameViewController.swift b/Pacman3D-iOS/GameViewController.swift index b07b55d..be8c1b6 100644 --- a/Pacman3D-iOS/GameViewController.swift +++ b/Pacman3D-iOS/GameViewController.swift @@ -12,7 +12,7 @@ import SceneKit import SpriteKit import CoreMotion -class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDelegate, SCNSceneRendererDelegate { +class GameViewController: UIViewController, SKSceneDelegate, SCNPhysicsContactDelegate, SCNSceneRendererDelegate { var motionManager: CMMotionManager? var scene: SCNScene! @@ -22,17 +22,19 @@ class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDe static let monsterCollision = 0b011 //3 static let pointsCollision = 0b100 //4 - var isRotating: Bool = false + // MARK: - Overlay - var direction: Direction = .north - - // overlay var pointsLabel: SKLabelNode! var lifeLabel: SKLabelNode! - var player: Player = Player() + // MARK: - Game Objects + + var player: Player! var monsters: [Monster] = [] + // MARK: - Input Handler + private var touchInputHandler: TouchInputHandler! + private var motionInput: MotionInput? override func viewDidLoad() { super.viewDidLoad() @@ -42,6 +44,9 @@ class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDe // create a new scene scene = SCNScene(named: "art.scnassets/ship.scn")! + let pacman = scene.rootNode.childNode(withName: "Pacman", recursively: true)! + player = Player(node: pacman, scene: scene, level: level) + // create and add a camera to the scene let cameraNode = SCNNode() cameraNode.camera = SCNCamera() @@ -50,42 +55,10 @@ class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDe // place the camera cameraNode.position = SCNVector3(x: 0, y: 0, z: 15) - for (x, line) in level.data.enumerated() { - for (z, block) in line.enumerated() { - if block == .wall { - let box = SCNBox(width: 5, height: 2, length: 5, chamferRadius: 0) - let node = SCNNode(geometry: box) - node.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: box, options: nil)) - node.physicsBody?.categoryBitMask = GameViewController.wallCollision - node.physicsBody?.contactTestBitMask = GameViewController.pacmanCollision - node.position = SCNVector3(x: Float(x * 5), y: 1, z:Float(z * 5)) - node.name = "\(x) \(z)" - scene.rootNode.addChildNode(node) - } else if block == .blank { - let shere = SCNSphere(radius: 0.5) - shere.firstMaterial?.diffuse.contents = UIColor.blue - let node = SCNNode(geometry: shere) - node.physicsBody = SCNPhysicsBody(type: .static, shape: nil) - node.physicsBody?.categoryBitMask = GameViewController.pointsCollision - node.physicsBody?.contactTestBitMask = GameViewController.pacmanCollision - node.name = "Point" - node.position = SCNVector3(x: Float(x * 5), y: 1, z:Float(z * 5)) - self.scene.rootNode.addChildNode(node) - } - } - } - - let pacman = self.scene.rootNode.childNode(withName: "Pacman", recursively: true)! - let pacmanBox = SCNBox(width: 5, height: 2, length: 5, chamferRadius: 0) - pacmanBox.firstMaterial?.diffuse.contents = UIColor.clear - let boxNode = SCNNode(geometry: pacmanBox) - pacman.addChildNode(boxNode) - pacman.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(geometry: pacmanBox, options: nil)) - pacman.physicsBody?.categoryBitMask = GameViewController.pacmanCollision - pacman.physicsBody?.contactTestBitMask = GameViewController.wallCollision - pacman.physicsBody?.isAffectedByGravity = false scene.physicsWorld.contactDelegate = self + level.createLevelEnviroment(scene: scene) + // // create and add a light to the scene // let lightNode = SCNNode() // lightNode.light = SCNLight() @@ -119,38 +92,14 @@ class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDe scnView.backgroundColor = UIColor.black // add a tap gesture recognizer - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) - scnView.addGestureRecognizer(tapGesture) + touchInputHandler = TouchInputHandler(target: self, action: #selector(handleTap(_:))) + scnView.addGestureRecognizer(touchInputHandler) + self.motionInput = MotionInput(gameScene: self) motionManager = CMMotionManager() if (motionManager?.isAccelerometerAvailable)! { motionManager?.accelerometerUpdateInterval = 0.1 - motionManager?.startAccelerometerUpdates(to: OperationQueue.main, withHandler: { (data, error) in - let rotate = data!.acceleration.y - //print(rotate) - let pacman = self.scene.rootNode.childNode(withName: "Pacman", recursively: true)! - let direction: Float = rotate < 0 ? 1.0 : -1.0 - if abs(rotate) > 0.3 { - if !self.isRotating { - let action = SCNAction.rotateBy(x: 0, y: CGFloat(direction * Float.pi * 0.5), z: 0, duration: 0.25) - pacman.runAction(action, completionHandler: { - self.isContact = false - }) - self.isRotating = true - - var directionVal = self.direction.rawValue + Int(direction) - if directionVal == 5 { - directionVal = 1 - } - if directionVal == 0 { - directionVal = 4 - } - self.direction = Direction(rawValue: directionVal)! - } - } else { - self.isRotating = false - } - }) + motionManager?.startAccelerometerUpdates(to: OperationQueue.main, withHandler: motionInput!.handleMotionInput) } if (motionManager?.isDeviceMotionAvailable)! { motionManager?.deviceMotionUpdateInterval = 0.1 @@ -169,7 +118,7 @@ class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDe }) } - for _ in 1...1 { + for _ in 1...10 { let postion = level.nextFreeSpace() let monster = Monster(position: SCNVector3(5 * postion.x, 1, 5 * postion.z), level: level, scene: scene) monster.addToScene(rootScene: self.scene) @@ -191,8 +140,6 @@ class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDe } } - var isContact: Bool = false - func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) { if contact.nodeA.name ?? "" == "Monster" && contact.nodeB.name ?? "" == "Monster" { return @@ -226,44 +173,22 @@ class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDe contact.nodeB.removeFromParentNode() } } - - if(contact.nodeA == pacman && contact.nodeB.physicsBody?.categoryBitMask == GameViewController.wallCollision) || (contact.nodeA.physicsBody?.categoryBitMask == GameViewController.wallCollision && contact.nodeB == pacman){ - - func block() { - if let box = contact.nodeA.geometry as? SCNBox { - box.firstMaterial?.diffuse.contents = UIColor.blue - } - - if let box = contact.nodeB.geometry as? SCNBox { - box.firstMaterial?.diffuse.contents = UIColor.blue - } - isContact = true - } - - if direction == .north { - if contact.contactNormal.x == 1.0 { - block() - } - } else if direction == .east { - if contact.contactNormal.z == -1.0 { - block() - } - } else if direction == .south { - if contact.contactNormal.x == -1.0 { - block() - } - } else if direction == .west { - if contact.contactNormal.z == 1.0 { - block() - } - } - } } + private var lastTime: TimeInterval = 0 + func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { for monster in monsters { monster.move() } + + + if time - lastTime > 0.25 { + if touchInputHandler.isTouchDown { + player.move() + } + lastTime = time + } } func createOverlay() -> SKScene { @@ -283,20 +208,6 @@ class GameViewController: UIViewController, SKSceneDelegate ,SCNPhysicsContactDe } func handleTap(_ gestureRecognize: UIGestureRecognizer) { - if isContact { - return - } - - let pacman = scene.rootNode.childNode(withName: "Pacman", recursively: true)! - if direction == .north { - pacman.position.x += 5 - } else if direction == .east { - pacman.position.z -= 5 - } else if direction == .south { - pacman.position.x -= 5 - } else if direction == .west { - pacman.position.z += 5 - } } override var shouldAutorotate: Bool { diff --git a/Pacman3D-iOS/Level.swift b/Pacman3D-iOS/Level.swift index d0e153f..9f31ffd 100644 --- a/Pacman3D-iOS/Level.swift +++ b/Pacman3D-iOS/Level.swift @@ -7,6 +7,7 @@ // import Foundation +import SceneKit class Level { @@ -44,6 +45,41 @@ class Level { data = [[]] } + func createLevelEnviroment(scene: SCNScene) { + for (x, line) in data.enumerated() { + for (z, block) in line.enumerated() { + if block == .wall { + addBlock(toScene: scene, at: (x, z)) + } else if block == .blank { + //addPointObject(toScene: scene, at: (x, z)) + } + } + } + } + + private func addBlock(toScene scene: SCNScene, at point: (x: Int, z: Int)) { + let box = SCNBox(width: 5, height: 2, length: 5, chamferRadius: 0) + let node = SCNNode(geometry: box) + node.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: box, options: nil)) + node.physicsBody?.categoryBitMask = GameViewController.wallCollision + node.physicsBody?.contactTestBitMask = GameViewController.pacmanCollision + node.position = SCNVector3(x: Float(point.x * 5), y: 1, z: Float(point.z * 5)) + node.name = "\(point.x) \(point.z)" + scene.rootNode.addChildNode(node) + } + + private func addPointObject(toScene scene: SCNScene, at point: (x: Int, z: Int)) { + let shere = SCNSphere(radius: 0.5) + shere.firstMaterial?.diffuse.contents = UIColor.blue + let node = SCNNode(geometry: shere) + node.physicsBody = SCNPhysicsBody(type: .static, shape: nil) + node.physicsBody?.categoryBitMask = GameViewController.pointsCollision + node.physicsBody?.contactTestBitMask = GameViewController.pacmanCollision + node.name = "Point" + node.position = SCNVector3(x: Float(point.x * 5), y: 1, z:Float(point.z * 5)) + scene.rootNode.addChildNode(node) + } + func nextFreeSpace() -> (x: Int, z: Int) { while true { let x = Int(arc4random_uniform(UInt32(data.count))) diff --git a/Pacman3D-iOS/MotionInput.swift b/Pacman3D-iOS/MotionInput.swift new file mode 100644 index 0000000..822bdaf --- /dev/null +++ b/Pacman3D-iOS/MotionInput.swift @@ -0,0 +1,47 @@ +// +// MotionInput.swift +// Pacman3D-iOS +// +// Created by Tobias on 09.07.17. +// Copyright © 2017 Tobias. All rights reserved. +// + +import Foundation +import CoreMotion +import SceneKit + +class MotionInput { + + private let gameScene: GameViewController + private var isRotating = false + + init(gameScene: GameViewController) { + self.gameScene = gameScene + } + + func handleMotionInput(data: CMAccelerometerData?, error: Error?) -> Swift.Void { + let rotate = data!.acceleration.y + //print(rotate) + let pacman = gameScene.scene.rootNode.childNode(withName: "Pacman", recursively: true)! + let direction: Float = rotate < 0 ? 1.0 : -1.0 + if abs(rotate) > 0.3 { + if !self.isRotating { + let action = SCNAction.rotateBy(x: 0, y: CGFloat(direction * Float.pi * 0.5), z: 0, duration: 0.25) + pacman.runAction(action, completionHandler: nil) + self.isRotating = true + + var directionVal = gameScene.player.direction.rawValue - Int(direction) + if directionVal == 5 { + directionVal = 1 + } + if directionVal == 0 { + directionVal = 4 + } + gameScene.player.direction = Direction(rawValue: directionVal)! + } + } else { + self.isRotating = false + } + + } +} diff --git a/Pacman3D-iOS/Player.swift b/Pacman3D-iOS/Player.swift index 68af9fd..b85151f 100644 --- a/Pacman3D-iOS/Player.swift +++ b/Pacman3D-iOS/Player.swift @@ -7,9 +7,75 @@ // import Foundation +import SceneKit class Player { var points: Int = 0 var life: Int = 3 + + private let level: Level + + private let node: SCNNode + + var direction: Direction = .north + var position: SCNVector3 + + init(node: SCNNode, scene: SCNScene, level: Level) { + self.node = node + self.position = node.position + self.level = level + + let pacmanBox = SCNBox(width: 5, height: 2, length: 5, chamferRadius: 0) + pacmanBox.firstMaterial?.diffuse.contents = UIColor.clear + let boxNode = SCNNode(geometry: pacmanBox) + node.addChildNode(boxNode) + node.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(geometry: pacmanBox, options: nil)) + node.physicsBody?.categoryBitMask = GameViewController.pacmanCollision + node.physicsBody?.contactTestBitMask = GameViewController.wallCollision + node.physicsBody?.isAffectedByGravity = false + } + + func move() { + print("\(direction)\t\(findFreeSpaces())") + if !findFreeSpaces().contains(direction) { + return + } + + if direction == .north { + position.x += 5 + } else if direction == .east { + position.z += 5 + } else if direction == .south { + position.x -= 5 + } else if direction == .west { + position.z -= 5 + } + let action = SCNAction.move(to: position, duration: 0.25) + node.runAction(action, completionHandler: nil) + } + + private func findFreeSpaces() -> [Direction] { + var directions: [Direction] = [] + + let x: Int = Int(position.x / 5) + let z: Int = Int(position.z / 5) + + print("\(x) \(z)") + + if level.data[x - 1][z] == .blank { + directions.append(.south) + } + if level.data[x][z - 1] == .blank { + directions.append(.west) + } + if level.data[x + 1][z] == .blank { + directions.append(.north) + } + if level.data[x][z + 1] == .blank { + directions.append(.east) + } + + return directions + } } diff --git a/Pacman3D-iOS/TouchInputHandler.swift b/Pacman3D-iOS/TouchInputHandler.swift new file mode 100644 index 0000000..0927f2d --- /dev/null +++ b/Pacman3D-iOS/TouchInputHandler.swift @@ -0,0 +1,25 @@ +// +// InputHandler.swift +// Pacman3D-iOS +// +// Created by Tobias on 09.07.17. +// Copyright © 2017 Tobias. All rights reserved. +// + +import UIKit +import UIKit.UIGestureRecognizerSubclass + +import SceneKit + +class TouchInputHandler: UIGestureRecognizer { + + var isTouchDown: Bool = false + + override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) { + self.isTouchDown = true + } + + override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) { + self.isTouchDown = false + } +} -- GitLab