Use GamePieceView to encapsulate displaying the current piece
This commit is contained in:
parent
18c2938470
commit
907d92b3b8
|
@ -27,7 +27,7 @@ struct ContentView: View {
|
|||
.fontWeight(.bold)
|
||||
if self.controller.heldTetromino != nil {
|
||||
Group {
|
||||
TetrominoView(tetromino: self.controller.heldTetromino!)
|
||||
TetrominoView(size: 100 / 4, tetromino: self.controller.heldTetromino!)
|
||||
}.frame(width: 100, height: 100, alignment: .center)
|
||||
} else {
|
||||
Rectangle().foregroundColor(.clear).frame(width: 100, height: 100)
|
||||
|
@ -49,7 +49,7 @@ struct ContentView: View {
|
|||
Text("Next")
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
NextTetromioesView(tetrominoes: self.controller.nextTetrominoes)
|
||||
NextTetromioesView(size: 100, tetrominoes: self.controller.nextTetrominoes)
|
||||
.frame(width: 100)
|
||||
}
|
||||
.padding(.trailing, 8)
|
||||
|
|
|
@ -60,8 +60,9 @@
|
|||
D608564723551602005BE4BC /* BoardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D608564523551602005BE4BC /* BoardView.swift */; };
|
||||
D608564923551BAC005BE4BC /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D608564823551BAC005BE4BC /* GridView.swift */; };
|
||||
D608564A23551BAC005BE4BC /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D608564823551BAC005BE4BC /* GridView.swift */; };
|
||||
D6D84DED23551E5E002968FB /* CurrentPieceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D84DEB23551E37002968FB /* CurrentPieceView.swift */; };
|
||||
D6D84DEE23551E5E002968FB /* CurrentPieceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D84DEB23551E37002968FB /* CurrentPieceView.swift */; };
|
||||
D6AA0AE6235D273E00D2FFE8 /* GamePieceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AA0AE4235D272200D2FFE8 /* GamePieceView.swift */; };
|
||||
D6AA0AE7235D273F00D2FFE8 /* GamePieceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AA0AE4235D272200D2FFE8 /* GamePieceView.swift */; };
|
||||
D6AA0AE8235D273F00D2FFE8 /* GamePieceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AA0AE4235D272200D2FFE8 /* GamePieceView.swift */; };
|
||||
D6D84DF523567415002968FB /* Tetromino+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D84DF323567231002968FB /* Tetromino+Color.swift */; };
|
||||
D6D84DF623567415002968FB /* Tetromino+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D84DF323567231002968FB /* Tetromino+Color.swift */; };
|
||||
D6D84DF92356B903002968FB /* TetrominoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D84DF72356B8F0002968FB /* TetrominoView.swift */; };
|
||||
|
@ -87,7 +88,6 @@
|
|||
D6E5606C2357D65700BF9ACF /* TetrisUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D608560723550D3A005BE4BC /* TetrisUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D6E5606D2357D65700BF9ACF /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D608564823551BAC005BE4BC /* GridView.swift */; };
|
||||
D6E5606E2357D65700BF9ACF /* TilesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D608562F23551269005BE4BC /* TilesView.swift */; };
|
||||
D6E5606F2357D65700BF9ACF /* CurrentPieceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D84DEB23551E37002968FB /* CurrentPieceView.swift */; };
|
||||
D6E560702357D65700BF9ACF /* BoardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D608564523551602005BE4BC /* BoardView.swift */; };
|
||||
D6E560712357D65700BF9ACF /* TetrominoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D84DF72356B8F0002968FB /* TetrominoView.swift */; };
|
||||
D6E560722357D65700BF9ACF /* NextTetrominoesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DC0E9823579A4D008A0A98 /* NextTetrominoesView.swift */; };
|
||||
|
@ -305,7 +305,7 @@
|
|||
D608562F23551269005BE4BC /* TilesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TilesView.swift; sourceTree = "<group>"; };
|
||||
D608564523551602005BE4BC /* BoardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoardView.swift; sourceTree = "<group>"; };
|
||||
D608564823551BAC005BE4BC /* GridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridView.swift; sourceTree = "<group>"; };
|
||||
D6D84DEB23551E37002968FB /* CurrentPieceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentPieceView.swift; sourceTree = "<group>"; };
|
||||
D6AA0AE4235D272200D2FFE8 /* GamePieceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamePieceView.swift; sourceTree = "<group>"; };
|
||||
D6D84DF323567231002968FB /* Tetromino+Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tetromino+Color.swift"; sourceTree = "<group>"; };
|
||||
D6D84DF72356B8F0002968FB /* TetrominoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TetrominoView.swift; sourceTree = "<group>"; };
|
||||
D6DC0E9323575D7C008A0A98 /* DPadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DPadView.swift; sourceTree = "<group>"; };
|
||||
|
@ -524,9 +524,9 @@
|
|||
D6E5609F2358C68C00BF9ACF /* BundleHelper.swift */,
|
||||
D608564823551BAC005BE4BC /* GridView.swift */,
|
||||
D608562F23551269005BE4BC /* TilesView.swift */,
|
||||
D6D84DEB23551E37002968FB /* CurrentPieceView.swift */,
|
||||
D608564523551602005BE4BC /* BoardView.swift */,
|
||||
D6D84DF72356B8F0002968FB /* TetrominoView.swift */,
|
||||
D6AA0AE4235D272200D2FFE8 /* GamePieceView.swift */,
|
||||
D6DC0E9823579A4D008A0A98 /* NextTetrominoesView.swift */,
|
||||
D6D84DF323567231002968FB /* Tetromino+Color.swift */,
|
||||
D6E5609B2358C50A00BF9ACF /* Media.xcassets */,
|
||||
|
@ -1056,9 +1056,9 @@
|
|||
D608564623551602005BE4BC /* BoardView.swift in Sources */,
|
||||
D608564923551BAC005BE4BC /* GridView.swift in Sources */,
|
||||
D6DC0E9923579A4D008A0A98 /* NextTetrominoesView.swift in Sources */,
|
||||
D6D84DED23551E5E002968FB /* CurrentPieceView.swift in Sources */,
|
||||
D60856332355128F005BE4BC /* TilesView.swift in Sources */,
|
||||
D6D84DF523567415002968FB /* Tetromino+Color.swift in Sources */,
|
||||
D6AA0AE8235D273F00D2FFE8 /* GamePieceView.swift in Sources */,
|
||||
D6E560A02358C68C00BF9ACF /* BundleHelper.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -1071,9 +1071,9 @@
|
|||
D608564723551602005BE4BC /* BoardView.swift in Sources */,
|
||||
D608564A23551BAC005BE4BC /* GridView.swift in Sources */,
|
||||
D6DC0E9A23579A4D008A0A98 /* NextTetrominoesView.swift in Sources */,
|
||||
D6D84DEE23551E5E002968FB /* CurrentPieceView.swift in Sources */,
|
||||
D60856342355128F005BE4BC /* TilesView.swift in Sources */,
|
||||
D6D84DF623567415002968FB /* Tetromino+Color.swift in Sources */,
|
||||
D6AA0AE7235D273F00D2FFE8 /* GamePieceView.swift in Sources */,
|
||||
D6E560A12358C68C00BF9ACF /* BundleHelper.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -1110,8 +1110,8 @@
|
|||
D6E560732357D65700BF9ACF /* Tetromino+Color.swift in Sources */,
|
||||
D6E560702357D65700BF9ACF /* BoardView.swift in Sources */,
|
||||
D6E560712357D65700BF9ACF /* TetrominoView.swift in Sources */,
|
||||
D6E5606F2357D65700BF9ACF /* CurrentPieceView.swift in Sources */,
|
||||
D6E5606D2357D65700BF9ACF /* GridView.swift in Sources */,
|
||||
D6AA0AE6235D273E00D2FFE8 /* GamePieceView.swift in Sources */,
|
||||
D6E560A22358C68C00BF9ACF /* BundleHelper.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -29,7 +29,7 @@ struct ContentView: View {
|
|||
Text("Held")
|
||||
if self.controller.heldTetromino != nil {
|
||||
Group {
|
||||
TetrominoView(tetromino: self.controller.heldTetromino!)
|
||||
TetrominoView(size: 50 / 4, tetromino: self.controller.heldTetromino!)
|
||||
}.frame(width: 50, height: 50, alignment: .center)
|
||||
} else {
|
||||
Rectangle().foregroundColor(.clear).frame(width: 50, height: 50)
|
||||
|
@ -48,7 +48,7 @@ struct ContentView: View {
|
|||
|
||||
VStack {
|
||||
Text("Next")
|
||||
NextTetromioesView(tetrominoes: self.controller.nextTetrominoes)
|
||||
NextTetromioesView(size: 50, tetrominoes: self.controller.nextTetrominoes)
|
||||
.frame(width: 50)
|
||||
}
|
||||
.padding(.trailing, 8)
|
||||
|
|
|
@ -11,8 +11,9 @@ import Foundation
|
|||
public struct GamePiece {
|
||||
public let tetromino: Tetromino
|
||||
public var topLeft: (Int, Int)
|
||||
public internal(set) var rotation: Double = 0
|
||||
public internal(set) var tiles: [[Bool]]
|
||||
|
||||
|
||||
public init(tetromino: Tetromino, topLeft: (Int, Int) = (0, 0)) {
|
||||
self.tetromino = tetromino
|
||||
self.tiles = tetromino.shape
|
||||
|
@ -23,8 +24,10 @@ public struct GamePiece {
|
|||
switch direction {
|
||||
case .clockwise:
|
||||
self.tiles.rotateClockwise()
|
||||
rotation += 90
|
||||
case .counterClockwise:
|
||||
self.tiles.rotateCounterclockwise()
|
||||
rotation -= 90
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,17 @@ public struct BoardView: View {
|
|||
}
|
||||
|
||||
public var body: some View {
|
||||
ZStack {
|
||||
TilesView(board: $board)
|
||||
|
||||
CurrentPieceView(boardWidth: board.width, boardHeight: board.height, currentPiece: $currentPiece, droppedPiece: $droppedPiece)
|
||||
GeometryReader { (geometry) in
|
||||
ZStack(alignment: .topLeading) {
|
||||
TilesView(board: self.$board)
|
||||
|
||||
if self.currentPiece != nil {
|
||||
GamePieceView(size: min(geometry.size.width / CGFloat(self.board.width), geometry.size.height / CGFloat(self.board.height)), piece: self.currentPiece!)
|
||||
}
|
||||
if self.droppedPiece != nil {
|
||||
GamePieceView(size: min(geometry.size.width / CGFloat(self.board.width), geometry.size.height / CGFloat(self.board.height)), piece: self.droppedPiece!, color: .gray, border: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
//
|
||||
// CurrentPieceView.swift
|
||||
// Tetris
|
||||
//
|
||||
// Created by Shadowfacts on 10/14/19.
|
||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import TetrisKit
|
||||
|
||||
struct CurrentPieceView: View {
|
||||
let boardWidth: Int
|
||||
let boardHeight: Int
|
||||
@Binding var currentPiece: GamePiece?
|
||||
@Binding var droppedPiece: GamePiece?
|
||||
|
||||
var body: some View {
|
||||
GridView(rows: self.boardHeight, columns: self.boardWidth) { (col, row, size) in
|
||||
if self.currentPieceAt(col, row) {
|
||||
Rectangle()
|
||||
.foregroundColor(self.currentPiece!.tetromino.color)
|
||||
.frame(width: size, height: size)
|
||||
.border(self.currentPiece!.tetromino.borderColor, width: 6)
|
||||
} else if self.droppedPieceAt(col, row) {
|
||||
Rectangle()
|
||||
.foregroundColor(.gray)
|
||||
.frame(width: size, height: size)
|
||||
} else {
|
||||
Rectangle()
|
||||
.foregroundColor(.clear)
|
||||
.frame(width: size, height: size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func currentPieceAt(_ col: Int, _ row: Int) -> Bool {
|
||||
guard let currentPiece = self.currentPiece else { return false }
|
||||
let (left, top) = currentPiece.topLeft
|
||||
let pieceHeight = currentPiece.tiles.count
|
||||
let pieceWidth = currentPiece.tiles.first!.count
|
||||
return col - left >= 0 && col - left < pieceWidth && row - top >= 0 && row - top < pieceHeight && currentPiece.tiles[row - top][col - left]
|
||||
}
|
||||
|
||||
func droppedPieceAt(_ col: Int, _ row: Int) -> Bool {
|
||||
guard let droppedPiece = self.droppedPiece else { return false }
|
||||
let (left, top) = droppedPiece.topLeft
|
||||
let pieceHeight = droppedPiece.tiles.count
|
||||
let pieceWidth = droppedPiece.tiles.first!.count
|
||||
return col - left >= 0 && col - left < pieceWidth && row - top >= 0 && row - top < pieceHeight && droppedPiece.tiles[row - top][col - left]
|
||||
}
|
||||
}
|
||||
|
||||
struct CurrentPieceView_Previews: PreviewProvider {
|
||||
@State static var currentPiece: GamePiece? = GamePiece(tetromino: .t)
|
||||
@State static var droppedPiece: GamePiece? = {
|
||||
var piece = GamePiece(tetromino: .t)
|
||||
return piece.moved(by: (0, 16 - piece.tiles.count))
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
CurrentPieceView(boardWidth: 10, boardHeight: 16, currentPiece: $currentPiece, droppedPiece: $droppedPiece)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// GamePieceView.swift
|
||||
// Tetris
|
||||
//
|
||||
// Created by Shadowfacts on 10/20/19.
|
||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import TetrisKit
|
||||
|
||||
struct GamePieceView: View {
|
||||
let size: CGFloat
|
||||
let piece: GamePiece
|
||||
let color: Color
|
||||
let border: Bool
|
||||
|
||||
init(size: CGFloat, piece: GamePiece, color: Color? = nil, border: Bool = true) {
|
||||
self.size = size
|
||||
self.piece = piece
|
||||
self.color = color ?? piece.tetromino.color
|
||||
self.border = border
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
return TetrominoView(size: size, tetromino: piece.tetromino, color: color, border: border)
|
||||
.rotationEffect(.degrees(piece.rotation))
|
||||
.offset(x: CGFloat(piece.topLeft.0) * size, y: CGFloat(piece.topLeft.1) * size)
|
||||
.frame(width: size * CGFloat(piece.tiles.count), height: size * CGFloat(piece.tiles.count))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct GamePieceView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
GamePieceView(size: 100, piece: GamePiece(tetromino: .t))
|
||||
}
|
||||
}
|
|
@ -10,16 +10,18 @@ import SwiftUI
|
|||
import TetrisKit
|
||||
|
||||
public struct NextTetromioesView: View {
|
||||
let size: CGFloat
|
||||
let tetrominoes: [Tetromino]
|
||||
|
||||
public init(tetrominoes: [Tetromino]) {
|
||||
public init(size: CGFloat, tetrominoes: [Tetromino]) {
|
||||
self.size = size
|
||||
self.tetrominoes = tetrominoes
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
VStack {
|
||||
ForEach(0..<self.tetrominoes.count, id: \.self) { (index) in
|
||||
TetrominoView(tetromino: self.tetrominoes[index]).aspectRatio(1, contentMode: .fit)
|
||||
TetrominoView(size: self.size / 4, tetromino: self.tetrominoes[index]).aspectRatio(1, contentMode: .fit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +29,6 @@ public struct NextTetromioesView: View {
|
|||
|
||||
struct NextTetrominoesView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NextTetromioesView(tetrominoes: [.t, .l, .z])
|
||||
NextTetromioesView(size: 50, tetrominoes: [.t, .l, .z])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,51 +10,47 @@ import SwiftUI
|
|||
import TetrisKit
|
||||
|
||||
public struct TetrominoView: View {
|
||||
let size: CGFloat
|
||||
let tetromino: Tetromino
|
||||
let color: Color
|
||||
let border: Bool
|
||||
|
||||
public init(tetromino: Tetromino) {
|
||||
public init(size: CGFloat, tetromino: Tetromino, color: Color? = nil, border: Bool = true) {
|
||||
self.size = size
|
||||
self.tetromino = tetromino
|
||||
self.color = color ?? tetromino.color
|
||||
self.border = border
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
GridView(rows: self.rows, columns: self.columns) { (col, row, size) in
|
||||
GridView(rows: tetromino.shape.count, columns: tetromino.shape.first!.count) { (col, row, _) in
|
||||
if row < self.tetromino.shape.count && col < self.tetromino.shape[row].count && self.tetromino.shape[row][col] {
|
||||
Rectangle()
|
||||
.foregroundColor(self.tetromino.color)
|
||||
.frame(width: size, height: size)
|
||||
.border(self.tetromino.borderColor, width: 6)
|
||||
if self.border {
|
||||
Rectangle()
|
||||
.foregroundColor(self.color)
|
||||
.frame(width: self.size, height: self.size)
|
||||
.border(self.tetromino.borderColor, width: 6)
|
||||
} else {
|
||||
Rectangle()
|
||||
.foregroundColor(self.color)
|
||||
.frame(width: self.size, height: self.size)
|
||||
}
|
||||
} else {
|
||||
Rectangle()
|
||||
.foregroundColor(.clear)
|
||||
.frame(width: size, height: size)
|
||||
.frame(width: self.size, height: self.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var rows: Int {
|
||||
self.tetromino.shape.firstIndex(where: { row in
|
||||
row.allSatisfy({ el in
|
||||
!el
|
||||
})
|
||||
}) ?? self.tetromino.shape.count
|
||||
}
|
||||
|
||||
var columns: Int {
|
||||
self.tetromino.shape.map { row in
|
||||
(row.firstIndex(where: { el in
|
||||
!el
|
||||
}) ?? row.count - 1) + 1
|
||||
}.max() ?? self.tetromino.shape.first!.count
|
||||
}
|
||||
}
|
||||
|
||||
struct TetrominoView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
TetrominoView(tetromino: .t)
|
||||
TetrominoView(tetromino: .i)
|
||||
TetrominoView(tetromino: .z)
|
||||
TetrominoView(tetromino: .j)
|
||||
TetrominoView(size: 50, tetromino: .t)
|
||||
TetrominoView(size: 50, tetromino: .i)
|
||||
TetrominoView(size: 50, tetromino: .z)
|
||||
TetrominoView(size: 50, tetromino: .j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue