-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
574 additions
and
0 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
Examples/SwiftIOPlayground/12MoreProjects/MazeGame/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.DS_Store | ||
/.build | ||
/Packages | ||
xcuserdata/ | ||
DerivedData/ | ||
.swiftpm/configuration/registries.json | ||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata | ||
.netrc |
17 changes: 17 additions & 0 deletions
17
Examples/SwiftIOPlayground/12MoreProjects/MazeGame/Package.mmp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# This is a MadMachine project file in TOML format | ||
# This file holds those parameters that could not be managed by SwiftPM | ||
# Edit this file would change the behavior of the building/downloading procedure | ||
# Those project files in the dependent libraries would be IGNORED | ||
|
||
# Specify the board name below | ||
# There are "SwiftIOBoard" and "SwiftIOMicro" now | ||
board = "SwiftIOMicro" | ||
|
||
# Specifiy the target triple below | ||
# There are "thumbv7em-unknown-none-eabi" and "thumbv7em-unknown-none-eabihf" now | ||
# If your code use significant floating-point calculation, | ||
# plz set it to "thumbv7em-unknown-none-eabihf" | ||
triple = "thumbv7em-unknown-none-eabi" | ||
|
||
# Reserved for future use | ||
version = 1 |
29 changes: 29 additions & 0 deletions
29
Examples/SwiftIOPlayground/12MoreProjects/MazeGame/Package.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// swift-tools-version: 5.9 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "MazeGame", | ||
dependencies: [ | ||
// Dependencies declare other packages that this package depends on. | ||
.package(url: "https://github.com/madmachineio/SwiftIO.git", branch: "main"), | ||
.package(url: "https://github.com/madmachineio/MadBoards.git", branch: "main"), | ||
.package(url: "https://github.com/madmachineio/MadDrivers.git", branch: "main"), | ||
.package(url: "https://github.com/madmachineio/MadGraphics.git", branch: "main") | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package, defining a module or a test suite. | ||
// Targets can depend on other targets in this package and products from dependencies. | ||
.executableTarget( | ||
name: "MazeGame", | ||
dependencies: [ | ||
"SwiftIO", | ||
"MadBoards", | ||
// Use specific library name rather than "MadDrivers" would speed up the build procedure. | ||
.product(name: "ST7789", package: "MadDrivers"), | ||
.product(name: "LIS3DH", package: "MadDrivers"), | ||
"MadGraphics" | ||
]), | ||
] | ||
) |
Binary file added
BIN
+164 KB
Examples/SwiftIOPlayground/12MoreProjects/MazeGame/Resources/Fonts/Roboto-Regular.ttf
Binary file not shown.
20 changes: 20 additions & 0 deletions
20
Examples/SwiftIOPlayground/12MoreProjects/MazeGame/Sources/Ball.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import MadGraphics | ||
|
||
struct Ball { | ||
var x1: Int | ||
var y1: Int | ||
let size: Int | ||
|
||
var x2: Int { | ||
x1 + size | ||
} | ||
var y2: Int { | ||
y1 + size | ||
} | ||
|
||
init(at point: Point, size: Int) { | ||
x1 = point.x | ||
y1 = point.y | ||
self.size = size | ||
} | ||
} |
266 changes: 266 additions & 0 deletions
266
Examples/SwiftIOPlayground/12MoreProjects/MazeGame/Sources/Game.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
import MadGraphics | ||
import ST7789 | ||
import SwiftIO | ||
|
||
// Place a ball at the upper left corner of the maze and move it based on acceleration. | ||
// If the ball reaches the destination (bottom right), the game ends. | ||
// Press the D1 button to restart the game. | ||
struct Game { | ||
var maze: Maze | ||
var ball: Ball | ||
let ballColor = Color(UInt32(0xEFE891)) | ||
|
||
let width = 20 | ||
var speed = 2 | ||
|
||
let screen: ST7789 | ||
let canvas: Canvas | ||
var frameBuffer: [UInt16] | ||
|
||
init(screen: ST7789, canvas: Canvas) { | ||
ball = Ball(at: Point(x: 1, y: 1), size: 7) | ||
maze = Maze(width: width, canvas: canvas) | ||
frameBuffer = [UInt16](repeating: 0, count: canvas.width * canvas.height) | ||
self.screen = screen | ||
self.canvas = canvas | ||
|
||
maze.generate() | ||
|
||
canvas.fillRectangle(at: Point(ball.x1, ball.y1), width: ball.size, height: ball.size, color: ballColor) | ||
updateDisplay(canvas: canvas, frameBuffer: &frameBuffer, screen: screen) | ||
} | ||
|
||
// Create a new maze and place the ball at the starting point. | ||
mutating func reset() { | ||
maze.reset() | ||
maze.generate() | ||
|
||
canvas.fillRectangle(at: Point(ball.x1, ball.y1), width: ball.size, height: ball.size, color: maze.bgColor) | ||
ball = Ball(at: Point(x: 1, y: 1), size: 7) | ||
canvas.fillRectangle(at: Point(ball.x1, ball.y1), width: ball.size, height: ball.size, color: ballColor) | ||
|
||
updateDisplay(canvas: canvas, frameBuffer: &frameBuffer, screen: screen) | ||
} | ||
|
||
// Update the display to show that the game has finished. | ||
mutating func finishGame() { | ||
canvas.fillRectangle(at: Point(0, 0), width: canvas.width, height: canvas.height, color: Color.red) | ||
|
||
var fileLength = 0 | ||
if let fontDataBuffer = openFile(path: "/lfs/Resources/Fonts/Roboto-Regular.ttf", length: &fileLength) { | ||
let largeFont = Font(from: fontDataBuffer, length: fileLength, pointSize: 10, dpi: 220) | ||
let largeText = largeFont.getMask("Good job!") | ||
canvas.blend(from: largeText, foreground: Color.white, to: Point(x: (canvas.width - largeText.width) / 2, y: 60)) | ||
|
||
let font = Font(from: fontDataBuffer, length: fileLength, pointSize: 6, dpi: 220) | ||
let text = font.getMask("Press D1 to continue") | ||
canvas.blend(from: text, foreground: Color.white, to: Point(x: (canvas.width - text.width) / 2, y: 140)) | ||
} | ||
|
||
updateDisplay(canvas: canvas, frameBuffer: &frameBuffer, screen: screen) | ||
} | ||
|
||
// Verify if the ball has reached the bottom right corner of the maze. | ||
func finished() -> Bool { | ||
return ball.x1 / width == maze.column - 1 && ball.y1 / width == maze.row - 1 | ||
} | ||
|
||
// Update the ball's position based on the acceleration. | ||
mutating func update(_ acceleration: (x: Float, y: Float, z: Float)) { | ||
guard !finished() else { | ||
finishGame() | ||
return | ||
} | ||
|
||
let lastBallPos = Point(ball.x1, ball.y1) | ||
|
||
// Move to the left. | ||
if acceleration.x > 0.25 { | ||
ball.x1 -= speed | ||
|
||
let gridXmin = max(ball.x1 / width, 0) | ||
let gridXmax = min(ball.x2 / width, maze.column - 1) | ||
let gridYmin = max(ball.y1 / width, 0) | ||
let gridYmax = min(ball.y2 / width, maze.row - 1) | ||
|
||
// Check if the ball collides with any walls. | ||
// If it does, reposition it close to the wall. | ||
for y in gridYmin...gridYmax { | ||
for x in gridXmin...gridXmax { | ||
let result = checkGridWalls(ballPos: Point(ball.x1, ball.y1), gridPos: Point(x, y)) | ||
|
||
if result.top || result.bottom || result.right { | ||
ball.x1 = (x + 1) * width + 1 | ||
} | ||
|
||
if result.left { | ||
ball.x1 = x * width + 1 | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Move to the right | ||
if acceleration.x < -0.25 { | ||
ball.x1 += speed | ||
|
||
let gridXmin = max(ball.x1 / width, 0) | ||
let gridXmax = min(ball.x2 / width, maze.column - 1) | ||
let gridYmin = max(ball.y1 / width, 0) | ||
let gridYmax = min(ball.y2 / width, maze.row - 1) | ||
|
||
for y in gridYmin...gridYmax { | ||
for x in gridXmin...gridXmax { | ||
let result = checkGridWalls(ballPos: Point(ball.x1, ball.y1), gridPos: Point(x, y)) | ||
|
||
if result.top || result.bottom || result.left { | ||
ball.x1 = x * width - ball.size - 1 | ||
} | ||
|
||
if result.right { | ||
ball.x1 = (x + 1) * width - ball.size - 1 | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Move downwards. | ||
if acceleration.y > 0.25 { | ||
ball.y1 += speed | ||
|
||
let gridXmin = max(ball.x1 / width, 0) | ||
let gridXmax = min(ball.x2 / width, maze.column - 1) | ||
let gridYmin = max(ball.y1 / width, 0) | ||
let gridYmax = min(ball.y2 / width, maze.row - 1) | ||
|
||
for y in gridYmin...gridYmax { | ||
for x in gridXmin...gridXmax { | ||
let result = checkGridWalls(ballPos: Point(ball.x1, ball.y1), gridPos: Point(x, y)) | ||
|
||
if result.bottom { | ||
ball.y1 = (y + 1) * width - 1 - ball.size | ||
} | ||
|
||
if result.top || result.right || result.left { | ||
ball.y1 = y * width - 1 - ball.size | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Move upwards. | ||
if acceleration.y < -0.25 { | ||
ball.y1 -= speed | ||
|
||
let gridXmin = max(ball.x1 / width, 0) | ||
let gridXmax = min(ball.x2 / width, maze.column - 1) | ||
let gridYmin = max(ball.y1 / width, 0) | ||
let gridYmax = min(ball.y2 / width, maze.row - 1) | ||
|
||
for y in gridYmin...gridYmax { | ||
for x in gridXmin...gridXmax { | ||
let result = checkGridWalls(ballPos: Point(ball.x1, ball.y1), gridPos: Point(x, y)) | ||
|
||
if result.top { | ||
ball.y1 = y * width + 1 | ||
} | ||
|
||
if result.bottom || result.right || result.left { | ||
ball.y1 = (y + 1) * width + 1 | ||
} | ||
} | ||
} | ||
} | ||
|
||
// If the ball's position has changed, update the display. | ||
if lastBallPos.x != ball.x1 || lastBallPos.y != ball.y1 { | ||
canvas.fillRectangle(at: lastBallPos, width: ball.size, height: ball.size, color: maze.bgColor) | ||
canvas.fillRectangle(at: Point(ball.x1, ball.y1), width: ball.size, height: ball.size, color: ballColor) | ||
updateDisplay(canvas: canvas, frameBuffer: &frameBuffer, screen: screen) | ||
} | ||
} | ||
|
||
// Check if the ball collides with a wall. | ||
func checkCollision(ballPos: Point, wallP1: Point, wallP2: Point) -> Bool { | ||
return ball.x1 <= wallP2.x && ball.x2 >= wallP1.x && ball.y1 <= wallP2.y && ball.y2 >= wallP1.y | ||
} | ||
|
||
// Check if the ball collides with any wall of a cell in the maze grid. | ||
func checkGridWalls(ballPos: Point, gridPos: Point) -> Wall { | ||
let walls = maze.grids[maze.getIndex(gridPos)].walls | ||
var result = Wall(top: false, right: false, bottom: false, left: false) | ||
|
||
if walls.top && | ||
checkCollision(ballPos: ballPos, wallP1: Point(gridPos.x * width, gridPos.y * width), wallP2: Point((gridPos.x + 1) * width, gridPos.y * width)) { | ||
result.top = true | ||
} | ||
|
||
if walls.right && | ||
checkCollision(ballPos: ballPos, wallP1: Point((gridPos.x + 1) * width, gridPos.y * width), wallP2: Point((gridPos.x + 1) * width, (gridPos.y + 1) * width)) { | ||
result.right = true | ||
|
||
} | ||
|
||
if walls.bottom && | ||
checkCollision(ballPos: ballPos, wallP1: Point(gridPos.x * width, (gridPos.y + 1) * width), wallP2: Point((gridPos.x + 1) * width, (gridPos.y + 1) * width)) { | ||
result.bottom = true | ||
} | ||
|
||
if walls.left && | ||
checkCollision(ballPos: ballPos, wallP1: Point(gridPos.x * width, gridPos.y * width), wallP2: Point(gridPos.x * width, (gridPos.y + 1) * width)) { | ||
result.left = true | ||
} | ||
|
||
return result | ||
} | ||
|
||
// Open a font file. | ||
func openFile(path: String, length: inout Int) -> UnsafeMutableRawBufferPointer? { | ||
var fontDataBuffer: UnsafeMutableRawBufferPointer? = nil | ||
|
||
print("open file:") | ||
do { | ||
let file = try FileDescriptor.open(path, .readOnly) | ||
|
||
try file.seek(offset: 0, from: FileDescriptor.SeekOrigin.end) | ||
let bytes = try file.tell() | ||
fontDataBuffer = UnsafeMutableRawBufferPointer.allocate(byteCount: bytes, alignment: 8) | ||
length = bytes | ||
|
||
try file.seek(offset: 0, from: FileDescriptor.SeekOrigin.start) | ||
try file.read(into: fontDataBuffer!, count: bytes) | ||
try file.close() | ||
} catch { | ||
print("Error, file handle error") | ||
if let buffer = fontDataBuffer { | ||
buffer.deallocate() | ||
} | ||
return nil | ||
} | ||
|
||
print("open file success") | ||
return fontDataBuffer | ||
} | ||
|
||
// Get the region that needs to be updated and send data to the screen. | ||
func updateDisplay(canvas: Canvas, frameBuffer: inout [UInt16], screen: ST7789) { | ||
guard let dirty = canvas.getDirtyRect() else { | ||
return | ||
} | ||
|
||
var index = 0 | ||
let stride = canvas.width | ||
let canvasBuffer = canvas.buffer | ||
for y in dirty.y0..<dirty.y1 { | ||
for x in dirty.x0..<dirty.x1 { | ||
frameBuffer[index] = Color.getRGB565LE(canvasBuffer[y * stride + x]) | ||
index += 1 | ||
} | ||
} | ||
frameBuffer.withUnsafeBytes { ptr in | ||
screen.writeBitmap(x: dirty.x, y: dirty.y, width: dirty.width, height: dirty.height, data: ptr) | ||
} | ||
|
||
canvas.finishRefresh() | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
Examples/SwiftIOPlayground/12MoreProjects/MazeGame/Sources/Grid.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
struct Wall { | ||
var top: Bool | ||
var right: Bool | ||
var bottom: Bool | ||
var left: Bool | ||
} | ||
|
||
struct Grid { | ||
let x: Int | ||
let y: Int | ||
var walls = Wall(top: true, right: true, bottom: true, left: true) | ||
var visited = false | ||
} |
Oops, something went wrong.