Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jaroshevskii committed Oct 28, 2022
0 parents commit dfbd190
Show file tree
Hide file tree
Showing 7 changed files with 398 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
22 changes: 22 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug Snake",
"program": "${workspaceFolder:snake}/.build/debug/Snake",
"args": [],
"cwd": "${workspaceFolder:snake}",
"preLaunchTask": "swift: Build Debug Snake"
},
{
"type": "lldb",
"request": "launch",
"name": "Release Snake",
"program": "${workspaceFolder:snake}/.build/release/Snake",
"args": [],
"cwd": "${workspaceFolder:snake}",
"preLaunchTask": "swift: Build Release Snake"
}
]
}
14 changes: 14 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "raylib",
"kind" : "remoteSourceControl",
"location" : "https://github.com/STREGAsGate/Raylib.git",
"state" : {
"branch" : "master",
"revision" : "e7cbfd48d26f85994fecc85881b4f38ca23516a3"
}
}
],
"version" : 2
}
20 changes: 20 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// swift-tools-version: 5.6
// 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/STREGAsGate/Raylib.git", branch: "master")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.executableTarget(
name: "Snake",
dependencies: ["Raylib"]
)
]
)
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Snake

A description of this package.
324 changes: 324 additions & 0 deletions Sources/Snake/Game.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
//
// Snake
//

import Raylib

class Game {
// 16:9
// private let windowWidth: Int32 = 640
// private let windowHeight: Int32 = 360

// 16:10
private let windowWidth: Int32 = 640
private let windowHeight: Int32 = 400

// 21:9
// private let windowWidth: Int32 = 840
// private let windowHeight: Int32 = 360

private let fieldSquareSize: Int32 = 20
private let fieldWidth: Int32
private let fieldHeight: Int32
private let fieldRender: RenderTexture2D
// private let fieldTexture: Texture2D
private let fieldPositionDraw: Vector2

struct Position2D {
var x: Int32, y: Int32
}

struct SnakeHead {
var position: Vector2

enum Movement {
case up, down, left, right
}

var movement: Movement
var previousPosition: Position2D {
var position = Position2D(x: Int32(position.x), y: Int32(position.y))
switch movement {
case .up:
position.y += 1
case .down:
position.y -= 1
case .left:
position.x += 1
case .right:
position.x -= 1
}
return position
}
let speed: Float32
}

private var snakeHead = SnakeHead(position: Vector2(x: 3, y: 3), movement: .right, speed: 12.5)
private var snakeTail = [Position2D]()

private var fruitPosition: Position2D
// Position2D(x: Int32.random(in: 0...fieldWidth), y: Int32.random(in: 0...fieldHeight))

private var isPause = false

init() {
Raylib.setConfigFlags(.vsyncHint)
Raylib.initWindow(windowWidth, windowHeight, "Snake")
// Raylib.setWindowPosition(364, 364)
Raylib.setExitKey(.letterQ)

fieldWidth = windowWidth / fieldSquareSize
fieldHeight = windowHeight / fieldSquareSize

fieldRender = Raylib.loadRenderTexture(
fieldWidth * fieldSquareSize, fieldHeight * fieldSquareSize)

Raylib.beginTextureMode(fieldRender)
Raylib.clearBackground(.lightGray)

for positionX in 0..<fieldWidth {
for positionY in 0..<fieldHeight {
// Notebook cells.
Raylib.drawRectangle(
positionX * fieldSquareSize + 1, positionY * fieldSquareSize + 1, fieldSquareSize - 2,
fieldSquareSize - 2, .white)

// Chess board.
// if (positionX + positionY) % 2 == 0 {
// Raylib.drawRectangle(
// positionX * fieldSquareSize, positionY * fieldSquareSize, fieldSquareSize,
// fieldSquareSize, .white)
// }
}
}

Raylib.endTextureMode()

// fieldTexture = fieldRender.texture
fieldPositionDraw = Vector2(
x: (Float(windowWidth) - Float(fieldRender.texture.width)) / 2,
y: (Float(windowHeight) - Float(fieldRender.texture.height)) / 2
)

fruitPosition = Position2D(
x: fieldWidth - Int32(snakeHead.position.x),
y: fieldHeight - Int32(snakeHead.position.y)
)

// MARK: TODO
// snakeTail.append(Position2D(x: Int32(snakeHead.position.x), y: Int32(snakeHead.position.y)))
}

private func input() {
// switch Raylib.getKeyPressed() {
// case .up where snakeHead.movement == .right || snakeHead.movement == .right:
// snakeHead.movement = .up
// case .down where snakeHead.movement == .right || snakeHead.movement == .right:
// snakeHead.movement = .down
// case .left where snakeHead.movement == .up || snakeHead.movement == .down:
// snakeHead.movement = .left
// case .right where snakeHead.movement == .up || snakeHead.movement == .down:
// snakeHead.movement = .right
// // case .letterP:
// // isPause.toggle()
// // case .letterR:
// // snakeHead = SnakeHead(position: Vector2(x: 3, y: 3), movement: .right, speed: 5)
// // snakeTail = [Position2D(x: Int32(snakeHead.position.x), y: Int32(snakeHead.position.y))]
// default: break
// }

if snakeHead.movement == .up || snakeHead.movement == .down {
if Raylib.isKeyPressed(.left) {
snakeHead.movement = .left
}
if Raylib.isKeyPressed(.right) {
snakeHead.movement = .right
}
}
if snakeHead.movement == .left || snakeHead.movement == .right {
if Raylib.isKeyPressed(.up) {
snakeHead.movement = .up
}
if Raylib.isKeyPressed(.down) {
snakeHead.movement = .down
}
}

if Raylib.isKeyPressed(.letterP) || Raylib.isKeyPressed(.enter) {
isPause.toggle()
}
if Raylib.isKeyPressed(.letterR) || Raylib.isKeyPressed(.enter) {
snakeHead = SnakeHead(position: Vector2(x: 3, y: 3), movement: .right, speed: 12.5)
// snakeTail = [Position2D(x: Int32(snakeHead.position.x), y: Int32(snakeHead.position.y))]
snakeTail.removeAll()
isPause = false
}
}

private func update(deltaTime: Float) {
if isPause { return }

// let x = Int32(snakeHead.position.x)
// let y = Int32(snakeHead.position.y)
// if x < 0 || x >= fieldWidth || y < 0 || y >= fieldHeight {
// isPause = true
// }

if snakeHead.position.x < 0 {
snakeHead.position.x += Float(fieldWidth)
} else if snakeHead.position.x > Float(fieldWidth) {
snakeHead.position.x -= Float(fieldWidth)
}
if snakeHead.position.y < 0 {
snakeHead.position.y += Float(fieldHeight)
} else if snakeHead.position.y > Float(fieldHeight) {
snakeHead.position.y -= Float(fieldHeight)
}

let previousPosition = Position2D(
x: Int32(snakeHead.position.x), y: Int32(snakeHead.position.y))

switch snakeHead.movement {
case .up:
snakeHead.position.y -= snakeHead.speed * deltaTime
case .down:
snakeHead.position.y += snakeHead.speed * deltaTime
case .left:
snakeHead.position.x -= snakeHead.speed * deltaTime
case .right:
snakeHead.position.x += snakeHead.speed * deltaTime
}

if Int32(snakeHead.position.x) != previousPosition.x
|| Int32(snakeHead.position.y) != previousPosition.y
{
snakeTail.append(snakeHead.previousPosition)
// snakeTail.append(Position2D(x: Int32(snakeHead.position.x), y: Int32(snakeHead.position.y)))
snakeTail.removeFirst()
}

if Int32(snakeHead.position.x) == fruitPosition.x
&& Int32(snakeHead.position.y) == fruitPosition.y
{
snakeTail.append(Position2D(x: Int32(snakeHead.position.x), y: Int32(snakeHead.position.y)))

fruitPosition = Position2D(
x: Int32.random(in: 0..<fieldWidth),
y: Int32.random(in: 0..<fieldHeight)
)
}

// for tailItem in snakeTail
// where snakeTail.count > 4 && tailItem.x != snakeTail.first?.x && tailItem.y != snakeTail.first?.y
// {
// if Int32(snakeHead.position.x) == tailItem.x && Int32(snakeHead.position.y) == tailItem.y {
// isPause = true
// }
// }
}

private func render() {
// Raylib.beginTextureMode(fieldRender)
// Raylib.clearBackground(.black)

// // Raylib.drawTextureV(fieldTexture, Vector2(), .white)
// // Raylib.drawTexture(fieldTexture, 0, 0, .blue)
// Raylib.drawRectangle(1, 1, 30, 30, .white)
// // Draw snake head.
// Raylib.drawRectangle(
// snakeHead.position.x * fieldSquareSize, snakeHead.position.y * fieldSquareSize,
// fieldSquareSize, fieldSquareSize, .magenta)

// Raylib.endTextureMode()

Raylib.beginDrawing()
Raylib.clearBackground(.white)

// Raylib.drawRectangleGradientH(0, 0, windowWidth, windowHeight, .magenta, .black)
// Raylib.drawCircleGradient(windowWidth / 2, windowHeight / 2, Float(windowWidth), .black, .magenta)

// Raylib.drawRectangleLines(
// Int32(fieldPositionDraw.x - 1), Int32(fieldPositionDraw.y - 1),
// fieldWidth * fieldSquareSize + 2,
// fieldHeight * fieldSquareSize + 2, .lightGray)

// Draw field border.
// Raylib.drawRectangleLines(
// Int32(fieldPositionDraw.x - 1), Int32(fieldPositionDraw.y - 1),
// fieldWidth * fieldSquareSize + 2,
// fieldHeight * fieldSquareSize + 2, .lightGray)
// Draw field.
Raylib.drawTextureV(fieldRender.texture, fieldPositionDraw, .white)

// Draw snake tail.
for snakeTailItem in snakeTail {
Raylib.drawRectangleRec(
Rectangle(
x: Float(snakeTailItem.x) * Float(fieldSquareSize) + fieldPositionDraw.x,
y: Float(snakeTailItem.y) * Float(fieldSquareSize) + fieldPositionDraw.y,
width: Float(fieldSquareSize),
height: Float(fieldSquareSize)
), .purple)
}
// Draw snake head.
Raylib.drawRectangleRec(
Rectangle(
x: Float(Int32(snakeHead.position.x)) * Float(fieldSquareSize) + fieldPositionDraw.x,
y: Float(Int32(snakeHead.position.y)) * Float(fieldSquareSize) + fieldPositionDraw.y,
width: Float(fieldSquareSize),
height: Float(fieldSquareSize)
), .darkPurple)
// Draw fruit.
Raylib.drawRectangleRec(
Rectangle(
x: Float(fruitPosition.x) * Float(fieldSquareSize) + fieldPositionDraw.x,
y: Float(fruitPosition.y) * Float(fieldSquareSize) + fieldPositionDraw.y,
width: Float(fieldSquareSize), height: Float(fieldSquareSize)
), .red)

if isPause {
Raylib.drawRectangleRec(
Rectangle(x: 0, y: 0, width: Float(windowWidth), height: Float(windowHeight)),
// Color(r: 0, g: 0, b: 0, a: 128)
Color(r: 255, g: 255, b: 255, a: 128)
// Color(r: 230, g: 41, b: 55, a: 128)
// Color(r: 0, g: 121, b: 241, a: 128)
)

let text = "Pause"
let fontSize: Int32 = 30
let positionDraw = Position2D(
x: (windowWidth - Raylib.measureText(text, fontSize)) / 2, y: (windowHeight - fontSize) / 2)

// Draw shadow.
// Raylib.drawText(text, positionDraw.x + 1, positionDraw.y + 1, fontSize, .black)
// Draw text.
Raylib.drawText(text, positionDraw.x, positionDraw.y, fontSize, .black)
}

Raylib.drawFPS(8, 8)
Raylib.drawText(
"""
Snake head:
Position: \(Int32(snakeHead.position.x)), \(Int32(snakeHead.position.y))
Speed: \(snakeHead.speed)
Snake tail:
Count: \(snakeTail.count)
""", 8, 36, 10, .black)

Raylib.endDrawing()
}

func run() {
while !Raylib.windowShouldClose {
input()
update(deltaTime: Raylib.getFrameTime())
render()
}
}

deinit {
Raylib.closeWindow()
}
}
Loading

0 comments on commit dfbd190

Please sign in to comment.