Skip to content

Commit

Permalink
Add snake game
Browse files Browse the repository at this point in the history
  • Loading branch information
Ines333 committed Mar 4, 2024
1 parent bfb0649 commit f37f5bb
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Examples/SwiftIOPlayground/12MoreProjects/Snake/.gitignore
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 Examples/SwiftIOPlayground/12MoreProjects/Snake/Package.mmp
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
26 changes: 26 additions & 0 deletions Examples/SwiftIOPlayground/12MoreProjects/Snake/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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: "Snake",
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"),
],
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: "Snake",
dependencies: [
"SwiftIO",
"MadBoards",
// Use specific library name rather than "MadDrivers" would speed up the build procedure.
.product(name: "ST7789", package: "MadDrivers")
]),
]
)
166 changes: 166 additions & 0 deletions Examples/SwiftIOPlayground/12MoreProjects/Snake/Sources/Snake.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import ST7789
import SwiftIO

typealias Point = (x: Int, y: Int)

struct Food {
var pos: Point
let size = 10
let color = UInt16(0xF81F).byteSwapped
let strokeColor = UInt16(0xC618)

// Generate food at a random position, ensuring it does not overlap with the snake.
init(screen: ST7789, snakeBody: [Point]) {
pos = (0, 0)
createNew(snakeBody: snakeBody)
}

// Check if the snake eats the food.
mutating func isEaten(at pos: Point) -> Bool {
return pos.x == self.pos.x && pos.y == self.pos.y
}

mutating func createNew(snakeBody: [Point]) {
repeat {
pos.x = Array(1..<screen.width / size).shuffled().randomElement()! * size
pos.y = Array(1..<screen.height / size).shuffled().randomElement()! * size
} while snakeBody.contains (where: { $0.x == pos.x && $0.y == pos.y })

screen.drawSquare(at: pos, width: size, color: color, strokeColor: strokeColor)
}
}

struct Snake {
let size = 10
let color = UInt16(0x07FF).byteSwapped
let strokeColor = UInt16(0xC618)
var xSpeed: Int
var ySpeed: Int

var food: Food
var body: [Point] = []

let screen: ST7789
var lastUpdateTime: Int64
var end = false

// Initialize the snake in the middle of the screen.
init(screen: ST7789) {
xSpeed = 1
ySpeed = 0
self.screen = screen

let pos = (screen.width / 2, screen.height / 2)
body.append(pos)

food = Food(screen: screen, snakeBody: body)

screen.drawSquare(at: pos, width: size, color: color, strokeColor: strokeColor)
lastUpdateTime = getSystemUptimeInMilliseconds()
}

// Update direction.
mutating func setSpeed(clockwise: Bool) {
let direction = clockwise ? 1 : -1

switch (xSpeed, ySpeed) {
case (-1, 0):
xSpeed = 0
ySpeed = -direction
case (0, -1):
xSpeed = direction
ySpeed = 0
case (1, 0):
xSpeed = 0
ySpeed = direction
case (0, 1):
xSpeed = -direction
ySpeed = 0
default: break
}
}

// Check if the snake collides with the wall or itself.
mutating func gameOver() -> Bool {
// Check if the snake's head collides with its own body.
for i in 1..<body.count {
if body[i].x == body[0].x && body[i].y == body[0].y {
return true
}
}

// Check if the snake's head collides with the boundaries.
return body[0].x > screen.width - size || body[0].x < 0 || body[0].y > screen.height - size || body[0].y < 0
}

// Move the snake in the specified direction.
mutating func update() {
for i in (1..<body.count).reversed() {
body[i] = body[i-1]
}

body[0].x += xSpeed * size
body[0].y += ySpeed * size
}

mutating func play() {
let current = getSystemUptimeInMilliseconds()
if current - lastUpdateTime >= 300 {
let lastBody = body

// Update snake's position.
update()

if gameOver() {
end = true
screen.clearScreen(UInt16(0xF800).byteSwapped)
} else {
screen.drawSquare(at: lastBody.last!, width: size, color: 0)
screen.drawSquare(at: body[0], width: size, color: color, strokeColor: strokeColor)

if food.isEaten(at: body[0]) {
food.createNew(snakeBody: body)

if let last = lastBody.last {
body.append(last)
screen.drawSquare(at: last, width: size, color: color, strokeColor: strokeColor)
}
}
}

lastUpdateTime = current
}
}
}

extension ST7789 {
func drawSquare(at point: Point, width: Int, color: UInt16, strokeColor: UInt16) {
for py in (point.y + 1)..<(point.y + width - 1) {
for px in (point.x + 1)..<(point.x + width - 1) {
writePixel(x: px, y: py, color: color)
}
}

for w in 0..<width {
for line in 0..<1 {
writePixel(x: point.x + w, y: point.y + line, color: strokeColor)
writePixel(x: point.x + w, y: point.y + width - 1 + line, color: strokeColor)
}
}

for h in 1..<(width - 1) {
for line in 0..<1 {
writePixel(x: point.x + line, y: point.y + h, color: 0)
writePixel(x: point.x + width - 1 + line, y: point.y + h, color: strokeColor)
}
}
}

func drawSquare(at point: Point, width: Int, color: UInt16) {
for py in point.y..<(point.y + width) {
for px in point.x..<(point.x + width) {
writePixel(x: px, y: py, color: color)
}
}
}
}
55 changes: 55 additions & 0 deletions Examples/SwiftIOPlayground/12MoreProjects/Snake/Sources/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Import SwiftIO to set the communication and MadBoard to use pin id.
import SwiftIO
import MadBoard
// Import the library to configure the LCD and write pixels on it.
import ST7789

// Initialize the SPI pin and the digital pins for the LCD.
let bl = DigitalOut(Id.D2)
let rst = DigitalOut(Id.D12)
let dc = DigitalOut(Id.D13)
let cs = DigitalOut(Id.D5)
let spi = SPI(Id.SPI0, speed: 30_000_000)

// Initialize the LCD using the pins above. Rotate the screen to keep the original at the upper left.
let screen = ST7789(spi: spi, cs: cs, dc: dc, rst: rst, bl: bl, rotation: .angle90)

// Initialize the two buttons for changing the snake's direction.
let clockwiseButton = DigitalIn(Id.D1)
let anticlockwiseButton = DigitalIn(Id.D19)

var clockwisePressCount = 0
var anticlockwisePressCount = 0

var snake = Snake(screen: screen)

while true {
if !snake.end {
// If a button is pressed, the snake's direction will change accordingly,
if clockwisePressCount > 25 && !clockwiseButton.read() {
snake.setSpeed(clockwise: true)
clockwisePressCount = 0
}

if clockwiseButton.read() {
clockwisePressCount += 1
} else {
clockwisePressCount = 0
}

if anticlockwisePressCount > 25 && !anticlockwiseButton.read() {
snake.setSpeed(clockwise: false)
anticlockwisePressCount = 0
}

if anticlockwiseButton.read() {
anticlockwisePressCount += 1
} else {
anticlockwisePressCount = 0
}

snake.play()
}

sleep(ms: 2)
}

0 comments on commit f37f5bb

Please sign in to comment.