SwiftUI | Shapes | Tic-Tac-Toe Game

Manisha Roy
Globant
Published in
4 min readJul 26, 2022

This is part 4 of the Tic-Tac-Toe Game series. Here we will learn more about in-built Shapes provided by SwiftUI and also design a baton for selecting the first player to play the game.

Shapes

SwiftUI gives us five built-in shapes that are commonly used: rectangle, rounded rectangle, circle, ellipse, and capsule. We can demonstrate all the options with one example:

VStack {
Rectangle()
.fill(.red)
.frame(width: 200, height: 200)
RoundedRectangle(cornerRadius: 15)
.fill(.orange)
.frame(width: 150, height: 175)
Capsule()
.fill(.yellow)
.frame(width: 125, height: 150)
Ellipse()
.fill(.green)
.frame(width: 100, height: 75)
Circle()
.fill(.blue)
.frame(width: 25, height: 50)
}
  • Rectangle draws a square shape of exact dimensions 200*200.
  • RoundedRectable does the same ie drawing rectangle with provided dimensions, except now you can round the corners by a certain value.
  • Capsule also draws a rectangular box of provided dimensions but its two edges will be rounded depending upon which axis is having a lower value. The above example is having a dimension of 125*150 that’s why it will have top and bottom rounded edges.
  • Eclipse draws an eclipse of provided dimensions.
  • Circle draws rounded eclipse where it takes smaller dimensions among height and width as radius. The above example is having a dimension of 25*50 but it will take 25 and draw an eclipse of 25*25.

Here we have used VStack for arranging our shapes, just replace it with ZStack and see the magic.

We will draw a baton for deciding which player will play first. Create a new SwiftUI file and name it GameScreen. Create PlayerInfo enum for accessing player information like player name and their strike color:

enum PlayerInfo: Int {
case player1 = 1
case player2
func getPlayerName() -> String {
switch self {
case .player2:
return “Player 2”
default:
return “Player 1”
}
}
func getPlayerColor() -> Color {
switch self {
case .player2:
return .green
default:
return .blue
}
}
}

Next, create one PlayerView for displaying player details.

struct PlayerView: View {
var player: PlayerInfo
var body: some View {
Text(player.getPlayerName())
.foregroundColor(player.getPlayerColor())
.padding(20)
.font(.title)
}
}

The view for players is ready but we need one baton as well. Create a new SwiftUI file naming it BatonView and add one rectangle with these modifiers:

var body: some View {
Rectangle()
.frame(width: 60, height: 5, alignment: .center)
.foregroundColor(.gray)
.shadow(radius: 10)

Go back to the GameScreen body and add two instances of PlayerView horizontally and put BatonView between them.

HStack {
PlayerView(player: PlayerInfo.player1)
BatonView()
PlayerView(player: PlayerInfo.player2)
}...
Updated GameScreen

Let’s add some animation to our baton and randomly choose the first player to play.

Baton is spinning but at the same time PlayerView is also animating, we will fix that later but first select our first player randomly. For that we will create a new model like this:

class GameSettings: ObservableObject {
@Published var currentPlayer = 0
var noOfStrokes = 0
}

GameSettings is having game details like who is playing at this moment and the number of strikes played by both players. Update the code as a screenshot and the game will be able to select the first player once the baton stops spinning.

  • BatonView is having rotation animation for 10 seconds which automatically starts on its appearance.
  • Hence we are waiting for 10 seconds on GameScreen’s appearance for 10 seconds to set the currentPlayer randomly.
  • Once currentPlayer is decided, the whole view gets redrawn with the above effects.

Please note that we need to initialize EnvironmentObject settings while adding GameScreen as:

NavigationLink(“Play Game”) {
GameScreen().environmentObject(GameSettings())
...

and to stop unnecessary animation just add this modifier to both PlayerView instances and we are good to go:

.scaleEffect(self.settings.currentPlayer == 1 ? 1.5 : 1)
.animation(.easeInOut)
....

Do check out my other articles in this series:

Text view styling

Button

Navigation

Drawing

Data Flow

List

Animation

If you liked this article then please appreciate it with claps and comments. This will encourage me to write more!!!!

--

--

Manisha Roy
Globant
Writer for

An enthusiastic iOS Developer. Keep learning!!