Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
krylovia committed Aug 13, 2020
0 parents commit 99154f8
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/.*
!/.gitignore
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Go snake

![Game screenshot](./screenshot.png 'Game screenshot')

## Run game

```
$ cd cmd/game
$ go run *go
```

## Sprites

[DungeonTilesetII](https://0x72.itch.io/dungeontileset-ii)
Binary file added assets/sprites.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
207 changes: 207 additions & 0 deletions cmd/game/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package main

import (
"image"
_ "image/png"
"log"
"math/rand"
"time"

"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil"
"github.com/hajimehoshi/ebiten/inpututil"
)

const (
screenWidth = 240
screenHeight = 240

tileSize = 16
tileXNum = 32

// SpriteBack - sprite for background
SpriteBack = 129

// SpriteSnake - sprite for snake piece
SpriteSnake = 126
)

var (
tilesImage *ebiten.Image
snakePosition [][]int
currentDirection = ebiten.KeyRight
isFinished = true
pieceToPick = [2]int{-1, -1}
)

func init() {
var err error
tilesImage, _, err = ebitenutil.NewImageFromFile("assets/sprites.png", ebiten.FilterDefault)
if err != nil {
log.Fatal(err)
}
rand.Seed(time.Now().UnixNano())
}

// Game ...
type Game struct {
counter int
}

// Update state
func (g *Game) Update(screen *ebiten.Image) error {
if isFinished {
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
initNewGame()
} else {
return nil
}
}
g.counter++
doStep := g.counter%10 == 1
if doStep {
const xNum = screenWidth / tileSize
const yNum = screenHeight / tileSize
oldFirstSnakePiece := snakePosition[len(snakePosition)-1]
newFirstSnakePiece := []int{oldFirstSnakePiece[0], oldFirstSnakePiece[1]}
isFinished = true
if currentDirection == ebiten.KeyUp {
if newFirstSnakePiece[1] > 0 {
newFirstSnakePiece[1]--
isFinished = false
}
} else if currentDirection == ebiten.KeyDown {
if newFirstSnakePiece[1] < (yNum - 1) {
newFirstSnakePiece[1]++
isFinished = false
}
} else if currentDirection == ebiten.KeyLeft {
if newFirstSnakePiece[0] > 0 {
newFirstSnakePiece[0]--
isFinished = false
}
} else if currentDirection == ebiten.KeyRight {
if newFirstSnakePiece[0] < (xNum - 1) {
newFirstSnakePiece[0]++
isFinished = false
}
}
if !isFinished {
// Check self-crossing
for i, piece := range snakePosition {
if i == 0 {
continue // Skip first item (it is last snake piece and will be deleted anyway)
}
if piece[0] == newFirstSnakePiece[0] && piece[1] == newFirstSnakePiece[1] {
isFinished = true
break
}
}
}
if isFinished {
return nil
}
startIndex := 1
if newFirstSnakePiece[0] == pieceToPick[0] && newFirstSnakePiece[1] == pieceToPick[1] {
startIndex = 0
pieceToPick = getPieceToPick()
}
snakePosition = append(snakePosition[startIndex:len(snakePosition)], newFirstSnakePiece)
}
if inpututil.IsKeyJustPressed(ebiten.KeyUp) && currentDirection != ebiten.KeyDown {
currentDirection = ebiten.KeyUp
} else if inpututil.IsKeyJustPressed(ebiten.KeyDown) && currentDirection != ebiten.KeyUp {
currentDirection = ebiten.KeyDown
} else if inpututil.IsKeyJustPressed(ebiten.KeyLeft) && currentDirection != ebiten.KeyRight {
currentDirection = ebiten.KeyLeft
} else if inpututil.IsKeyJustPressed(ebiten.KeyRight) && currentDirection != ebiten.KeyLeft {
currentDirection = ebiten.KeyRight
}
return nil
}

func initNewGame() {
snakePosition = [][]int{
{0, 0},
{1, 0},
{2, 0},
{3, 0},
{4, 0},
}
currentDirection = ebiten.KeyRight
pieceToPick = getPieceToPick()
isFinished = false
}

func getPieceToPick() [2]int {
const xMax = screenWidth / tileSize
const yMax = screenHeight / tileSize
var newPieceX, newPieceY int
for {
newPieceIndex := rand.Intn(xMax * yMax)
newPieceX = newPieceIndex % xMax
newPieceY = newPieceIndex / xMax
isEmptyCell := true
for _, piece := range snakePosition {
if piece[0] == newPieceX && piece[1] == newPieceY {
isEmptyCell = false
break
}
}
if isEmptyCell {
break
}
}
return [2]int{newPieceX, newPieceY}
}

// Draw scene
func (g *Game) Draw(screen *ebiten.Image) {
const xNum = screenWidth / tileSize
const yNum = screenHeight / tileSize
// Draw background
sx := (SpriteBack % tileXNum) * tileSize
sy := (SpriteBack / tileXNum) * tileSize
for x := 0; x < xNum; x++ {
for y := 0; y < yNum; y++ {
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(x*tileSize), float64(y*tileSize))
screen.DrawImage(tilesImage.SubImage(image.Rect(sx, sy, sx+tileSize, sy+tileSize)).(*ebiten.Image), op)
}
}
// Draw snake
sx = (SpriteSnake % tileXNum) * tileSize
sy = (SpriteSnake / tileXNum) * tileSize
for _, p := range snakePosition {
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(p[0]*tileSize), float64(p[1]*tileSize))
screen.DrawImage(tilesImage.SubImage(image.Rect(sx, sy, sx+tileSize, sy+tileSize)).(*ebiten.Image), op)
}
// Draw piece to pick
if pieceToPick[0] != -1 {
sx = (SpriteSnake % tileXNum) * tileSize
sy = (SpriteSnake / tileXNum) * tileSize
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(pieceToPick[0]*tileSize), float64(pieceToPick[1]*tileSize))
screen.DrawImage(tilesImage.SubImage(image.Rect(sx, sy, sx+tileSize, sy+tileSize)).(*ebiten.Image), op)
}
// Draw finish text
if isFinished {
ebitenutil.DebugPrint(screen, "You've lost :( Press R to restart")
}
}

// Layout ...
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
return screenWidth, screenHeight
}

func main() {
g := &Game{}
ebiten.SetWindowSize(screenWidth*2, screenHeight*2)
ebiten.SetWindowTitle("Go Snake")
initNewGame()
if err := ebiten.RunGame(g); err != nil {
log.Fatal(err)
}
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/kiaplayer/go_snake

go 1.14

require github.com/hajimehoshi/ebiten v1.11.7
51 changes: 51 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc=
github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/hajimehoshi/bitmapfont v1.2.0/go.mod h1:h9QrPk6Ktb2neObTlAbma6Ini1xgMjbJ3w7ysmD7IOU=
github.com/hajimehoshi/ebiten v1.11.7 h1:kxfhTXvKsS8y4XYJUhmjBUYf+V7H9GQrmq0SnKO6duo=
github.com/hajimehoshi/ebiten v1.11.7/go.mod h1:/cgFsE6vG9LItlxHpVqb33Pcw7DrJFOzGnl/uNifIcE=
github.com/hajimehoshi/go-mp3 v0.2.1/go.mod h1:Rr+2P46iH6PwTPVgSsEwBkon0CK5DxCAeX/Rp65DCTE=
github.com/hajimehoshi/oto v0.3.4/go.mod h1:PgjqsBJff0efqL2nlMJidJgVJywLn6M4y8PI4TfeWfA=
github.com/hajimehoshi/oto v0.6.3/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/jakecoffman/cp v0.1.0/go.mod h1:a3xPx9N8RyFAACD644t2dj/nK4SuLg1v+jL61m2yVo4=
github.com/jfreymuth/oggvorbis v1.0.0/go.mod h1:abe6F9QRjuU9l+2jek3gj46lu40N4qlYxh2grqkLEDM=
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mobile v0.0.0-20200222142934-3c8601c510d0/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 99154f8

Please sign in to comment.