パズル「Cubes of Catfish」の実装について少し(Swift&SceneKit)

約1年前、モバイルストアには1933年に発明されたピートハインパズル「Soma Cubes」がないことに気付きました。 iOS用のゲームを書きたいという欲求は長い間頭を痛めていました。特にデザインが本当に必要ないので、最終的に決定しました(Blenderでキューブを描くことはカウントされません)。 パズルには、キューブから7つの要素があり、そこからさまざまな他の形状が組み立てられます( ウィキペディア )。



ゲームにすぐに提示される要件は、2つのポイントになりました。

1.開発ではサードパーティのフレームワークを使用しないでください。

2.ボタンは、フィギュアやシーンを制御するために使用するべきではありません-認識のみ。



請求項2によれば、オブジェクトを選択してからコントロールボタンをクリックする必要がある場合のシナリオは適合しません。



1.準備する



SceneKitがGame Techとして指定された作成中に、Blenderで描画されたキューブを.daeファイルにエクスポートし、ゲームプロジェクトの「art.scnassets」フォルダーに入れます。 インポートされたシーンおよびシーン上のオブジェクトへのアクセスは、次のように取得されます。



let cubeScene = SCNScene(named: "art.scnassets/cube.dae") let cubeNode1 = cubeScene!.rootNode.childNodeWithName("Cube", recursively: false) cubeNode1?.geometry?.materialWithName(CUBE_MATERIAL_NAME)?.diffuse.contents = COLORS_FOR_PRIMITIVES[1]
      
      





3行目は、キューブのエッジを目的の色で塗りつぶします。 これで、オブジェクトを複製し、座標を設定し、SCNNodeクラスのオブジェクトである親Figureに追加できます。 同様に、キューブを少し小さくした後、シーンの中心にアセンブリ用のフィギュアを配置します。



2.オブジェクトの回転、上昇、下降、およびドラッグ



このゲームでは、3つの軸すべてを中心にフィギュアを90度回転させる機能を提供する必要がありますが、最初はいくつかの困難を引き起こしましたが、2軸周りの回転の組み合わせですべての場合に十分であることがわかりました(1週間後)。 UISwipeGestureRecognizerは、計画を実装するために選択されました。 したがって、図を左右にスワイプすると、カメラの位置に関係なく垂直軸(Y)を中心に回転し、上下にスワイプすると、XまたはZ(カメラの位置に応じて)を中心に図が回転します。



UIPanGestureRecognizerを使用してXZプレーンに沿ってオブジェクトをドラッグするのは自然ですが、両方のハンドラーが機能するには、「スワイプ」と「ドラッグアンドドロップ」の関係を指定する必要があります。



 panGestureRecognizer.requireGestureRecognizerToFail(swipeGestureRecognizer)
      
      





興味のある人のためにオブジェクトをドラッグするためのコード
 func handlePanGestures(recogniser: UIPanGestureRecognizer){ if recogniser.state == .Began { let location = recogniser.locationInView(recogniser.view) let hits = sceneView.hitTest(location,options: nil) as! [SCNHitTestResult] for hit in hits { if Utils.nodeHasPrefix(hit.node.parentNode!, prefix: "fig"){ selectedNode = hit.node.parentNode saveOldPosition(selectedNode) let worldCoord = selectedNode.position let projectedOrigin = sceneView.projectPoint(worldCoord) curZ = projectedOrigin.z let unProj = sceneView.unprojectPoint(SCNVector3Make(Float(location.x), Float(location.y), projectedOrigin.z)) ofset = SCNVector3Make(selectedNode.position.x - unProj.x, selectedNode.position.y - unProj.y, selectedNode.position.z - unProj.z) break } } } if recogniser.state == .Changed { let curScreenPoint = SCNVector3Make(Float(location.x), Float(location.y), curZ) let curWorld = sceneView.unprojectPoint(curScreenPoint) let posPlusOffset = SCNVector3Make(curWorld.x + ofset.x, curWorld.y + ofset.y , curWorld.z + ofset.z) let newPosition = SCNVector3Make(posPlusOffset.x , selectedNode.position.y , posPlusOffset.z ) let projectedOrigin2 = sceneView.projectPoint(newPosition) curZ = projectedOrigin2.z selectedNode.position = newPosition } if recogniser.state == .Ended || recogniser.state == .Failed{ selectedNode.position.x = Utils.clamp(selectedNode.position.x, min : -9 , max: 9) selectedNode.position.y = round(selectedNode.position.y) selectedNode.position.z = Utils.clamp(selectedNode.position.z, min : -9 , max: 9) if testCollision(selectedNode){ selectedNode.position = selectedNodeOldPosition }else{ testGameOver(selectedNode as! SimpleFigure) } selectedNode = nil } }
      
      







Y軸に沿って1ユニットを上下させるために、UITapGestureRecognizerの2つのインスタンスが使用され、そのうちの1つだけがnumberOfTapsRequired = 2であり、依存関係も示されました。



 tapRecognizer.requireGestureRecognizerToFail(doubleTapRecognizer)
      
      





3.カメラ制御



カメラは、SCNNodeから少し離れた座標の中心に追加され、SCNNodeに向けられます。 つまり、カメラは、いわば球体の表面上にあり、カメラを回転させるには、親SCNNodeを特定の角度だけ回転させるだけで十分です。 ズームインおよびズームアウトするには、UIPinchGestureRecognizerを使用し、ハンドラーで同じSCNNodeの「スケール」を行うだけで十分です。



  let cameraNode = SCNNode() cameraNode.name="mainCamera" cameraNode.camera = SCNCamera() cameraNode.camera!.zFar = 100 cameraNode.position = SCNVector3(x: 0.0, y: 0.0, z: 8.0) let cameraOrbit = SCNNode() cameraOrbit.position = SCNVector3(x: 0.0, y: 0.0, z: 0.0) cameraOrbit.addChildNode(cameraNode) cameraOrbit.eulerAngles.x = -Float(M_PI_4)
      
      





cameraOrbitオブジェクトのeulerAnglesプロパティを使用して、シェイプと同じハンドラーで回転角度をインクリメントしました。以前はSCNHitTestResultでオブジェクトを特定していました。



4.その他のもの



衝突をテストするために、現在の図の各立方体(解放、回転など)の座標は、残りの6つの図の立方体と一致します。 レベルは、座標を含む単なるテキストファイルです。



このパズルを開発した結果、iOS、特にUIGestureRecognizersの実装に良い印象を残したと言いたいです。 ご清聴ありがとうございました。上記の誰かが助けてくれることを願っています。



All Articles