You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
4.4 KiB

package main
import (
"github.com/veandco/go-sdl2/sdl"
"log"
"math"
"math/rand"
"time"
)
var (
winWidth = 800
winHeight = 600
speed = 10
blockSize = 10
random = rand.New(rand.NewSource(time.Now().Unix()))
)
func main() {
err := sdl.Init(sdl.INIT_EVERYTHING)
if err != nil {
log.Fatal(err)
}
defer sdl.Quit()
window, err := sdl.CreateWindow(
"PONG",
sdl.WINDOWPOS_CENTERED,
sdl.WINDOWPOS_CENTERED,
int32(winWidth),
int32(winHeight),
sdl.WINDOW_SHOWN)
if err != nil {
log.Fatal(err)
}
defer window.Destroy()
renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
if err != nil {
log.Fatal(err)
}
defer renderer.Destroy()
centerX, centerY := getCenter()
snakeRect := sdl.Rect{
X: int32(centerX),
Y: int32(centerY),
W: 10,
H: 10,
}
fruitRect := sdl.Rect{
X: 0,
Y: 0,
W: 10,
H: 10,
}
background, err := renderer.CreateTexture(
sdl.PIXELFORMAT_ABGR8888,
sdl.TEXTUREACCESS_STREAMING,
int32(winWidth),
int32(winHeight))
if err != nil {
log.Fatal(err)
}
defer background.Destroy()
snakeTex, err := renderer.CreateTexture(
sdl.PIXELFORMAT_ABGR8888,
sdl.TEXTUREACCESS_STREAMING,
snakeRect.W,
snakeRect.H)
if err != nil {
log.Fatal(err)
}
defer snakeTex.Destroy()
fruitTex, err := renderer.CreateTexture(
sdl.PIXELFORMAT_ABGR8888,
sdl.TEXTUREACCESS_STREAMING,
fruitRect.W,
fruitRect.H)
if err != nil {
log.Fatal(err)
}
defer fruitTex.Destroy()
fruitPixels := make([]byte, fruitRect.H * fruitRect.W * 4)
for y := 1; y < int(fruitRect.H) - 1; y++ {
for x := 1; x < int(fruitRect.W) - 1; x++ {
i := (y * int(fruitRect.W) + x) * 4
fruitPixels[i] = 255
fruitPixels[i + 1] = 0
fruitPixels[i + 2] = 0
fruitPixels[i + 3] = 255
}
}
fruitTex.Update(nil, fruitPixels, int(fruitRect.W) * 4)
snakePixels := make([]byte, snakeRect.H * snakeRect.W * 4)
for y := 1; y < int(snakeRect.H) - 1; y++ {
for x := 1; x < int(snakeRect.W) - 1; x++ {
i := (y * int(snakeRect.W) + x) * 4
snakePixels[i] = 255
snakePixels[i + 1] = 255
snakePixels[i + 2] = 255
snakePixels[i + 3] = 255
}
}
snakeTex.Update(nil, snakePixels, int(snakeRect.W) * 4)
keyState := sdl.GetKeyboardState()
pixels := make([]byte, winHeight*winWidth*4)
background.Update(nil, pixels, winWidth * 4)
renderer.Copy(background, nil, nil)
snake := &snakeBody{
Rect: snakeRect,
dx: 0,
dy: -snakeRect.H,
tex: snakeTex,
next: nil,
}
fruit := &fruit{
Rect: fruitRect,
tex: fruitTex,
}
fruit.newLoc(snake, winWidth - int(fruit.W), winHeight - int(fruit.H))
snake.draw(renderer)
fruit.draw(renderer)
renderer.Present()
frameStart := time.Now()
for {
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
switch event.(type) {
case *sdl.QuitEvent:
return
}
}
if keyState[sdl.SCANCODE_UP] != 0 {
if snake.canMoveTo(0, -snakeRect.H) {
snake.dy = -snakeRect.H
snake.dx = 0
}
} else if keyState[sdl.SCANCODE_DOWN] != 0 {
if snake.canMoveTo(0, snakeRect.H) {
snake.dy = snakeRect.H
snake.dx = 0
}
} else if keyState[sdl.SCANCODE_RIGHT] != 0 {
if snake.canMoveTo(snakeRect.W, 0) {
snake.dy = 0
snake.dx = snakeRect.W
}
} else if keyState[sdl.SCANCODE_LEFT] != 0 {
if snake.canMoveTo(-snakeRect.W, 0) {
snake.dy = 0
snake.dx = -snakeRect.W
}
}
if time.Since(frameStart).Milliseconds() >= 150 {
renderer.Clear()
renderer.Copy(background, nil, nil)
snake.update()
if snake.detectBodyCollision() || snake.X < 0 || snake.X >= int32(winWidth) || snake.Y < 0 || snake.Y >= int32(winHeight) {
log.Println("Game Over")
break
}
if snake.foundFruit(*fruit) {
log.Println("Found Fruit")
snake.grow()
log.Println("Grown")
fruit.newLoc(snake, winWidth-int(fruit.W), winHeight-int(fruit.H))
log.Println("New Fruit location")
}
snake.draw(renderer)
fruit.draw(renderer)
renderer.Present()
frameStart = time.Now()
}
sdl.Delay(10)
}
}
func isEmpty(rect sdl.Rect, s *snakeBody) bool {
for s != nil {
if rect.X == s.Rect.X && rect.Y == s.Rect.Y {
return false
}
s = s.next
}
return true
}
func getRandomRect(w, h int) sdl.Rect {
randX := int32(random.Intn(w))
randY := int32(random.Intn(h))
return sdl.Rect{
X: round(randX, 10),
Y: round(randY, 10),
}
}
func round(x, unit int32) int32 {
return int32(math.Round(float64(x/unit))) * unit
}
func getCenter() (int, int) {
return winWidth / 2, winHeight / 2
}