Creating a 3D Tic-Tac-Toe in SceneKit Under SwiftUI | by Mark Lucking | Aug, 2022

A stab at creating the classic Qubic game

Confirming winning lines on the qubic board

The tic-tac-toe game dates back a long time, with boards Wikipedia tells us turning up in places like ancient Egypt. It is a game that a company called Parker Brothers updated in 1964 with a 3D version called Qubic.

In their game, you have a cube that is 4x4x4 squares in which you have to do the same thing as you do in tic-tac-toe; that is, connect your zeros or crosses in a line.

Of course, with the 3D version, it’s a little more challenging since you have considerably more plays possible. Join me in looking at implementing it under the SceneKit framework within SwiftUI Implementation. A mini project that is challenging, but fun.

Bon. I want to start with a UIViewRepresentable view, the go-between SwiftUI and UIKit. The basic code template looks like this. I did not choose the SceneView available under SwiftUI because it doesn’t directly support tap gestures.

A view that creates a Scene within a UIKit environment that I can pass back to some SwiftUI code like this.

struct ContentView: View {
var scene = SCNScene(named: "SceneKitScene.scn")
var body: some View {
scene: scene!,
options: []

The SceneKitScene named here is nothing more than a basic *.scn file I created within Xcode and added to the project.

Within the sceneView code in place, I added a grid representing the game board and a gesture recognizer that would place pieces on my board as each player took turns.

A grid that looks like this.

A grid of 4x4x4. Note that I didn’t do a 3D grid that is 3x3x3 because doing so with the 3D version results in the first player always winning. In theory, you can, of course, create an even larger board. With a larger grid, you can invite more players, all food for thought; future versions.


The tapGesture within the code refers to a method handleTap. The basic code for that method is here:

This code comes directly from Apple and looks to see which of the 64 nodes I tapped on and adds a cube or a sphere at the same position, alternating between the two.

1* n9smmsD0gADW 1 eD5Ahg
Selecting different nodes in my online qubic game

Note I didn’t use crosses or circles because cubes and spheres work far better in a 3D world — an impressive result for just 100 lines of code.

The game needs to check when you try to play if the grid is free and, indeed, ideally will stop play and declare a winner too should one of the two players get a line, neither of which it does yet.

I had wanted to use the grid coordinates to map a data structure, but I couldn’t since they are not decimals. To try and keep it as simple as possible, I extended SCNNode so I could add index values.

Now I could add an integer index against my nodes to each node such that I could look for sequences or winning nodes after each play. Next, I created an array of the new structure with this one-liner.

var board: [[[NewNode?]]] = .init(repeating: .init(repeating: .init(repeating: nil, count: 4), count: 4), count: 4)

Code added to the tapGesture method.

Finally, I added some signatures of winning lines and some code to test said signatures against plays made.

It all looked good; I added two dozen more signatures before taking a break to think about it a little more.

As I looked over the signatures, it dawned on me that the difference, for the most part, with many of them was a single figure in the three number tuples that represented the coordinates.

I could, I thought, with a little more engineering, build said signatures with only a handful of templates.
I used the Combine framework subscription pattern described in this article to set up a means to change the node’s color for testing my new method. You can see it in action here.

testing signatures for winning lines in qubic

As I continued to work on this — it became evident that there were a lot more winning lines than I had initially thought. I checked the Wikipedia page on the subject and discovered I should have 76 lines — I set about creating all of them that evening.

That done I cleaned up the code and started to investigate the possibility of building an AI capable of playing against you in the game.

A subject that I sure will be an article in its own right — so I’ll bring this paper to end here.

News Credit

%d bloggers like this: