commit
5af07f0aec
@ -0,0 +1,216 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
|
type snakeBody struct {
|
||||||
|
sdl.Rect
|
||||||
|
dx int32
|
||||||
|
dy int32
|
||||||
|
tex *sdl.Texture
|
||||||
|
next *snakeBody
|
||||||
|
}
|
||||||
|
|
||||||
|
type fruit struct {
|
||||||
|
sdl.Rect
|
||||||
|
tex *sdl.Texture
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snakeBody) detectCollision(rect sdl.Rect) bool {
|
||||||
|
return s.X == rect.X && s.Y == rect.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snakeBody) foundFruit(fruit fruit) bool {
|
||||||
|
return s.detectCollision(fruit.Rect)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snakeBody) detectBodyCollision() bool {
|
||||||
|
nextChunk := s.next
|
||||||
|
for nextChunk != nil {
|
||||||
|
if s.detectCollision(nextChunk.Rect) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
nextChunk = nextChunk.next
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snakeBody) draw(renderer *sdl.Renderer) {
|
||||||
|
chunk := s
|
||||||
|
for chunk != nil {
|
||||||
|
renderer.Copy(chunk.tex, nil, &chunk.Rect)
|
||||||
|
chunk = chunk.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snakeBody) update() {
|
||||||
|
prevRect := s.Rect
|
||||||
|
s.X += s.dx
|
||||||
|
s.Y += s.dy
|
||||||
|
next := s.next
|
||||||
|
for next != nil {
|
||||||
|
nextRect := next.Rect
|
||||||
|
next.Rect = prevRect
|
||||||
|
prevRect = nextRect
|
||||||
|
next = next.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snakeBody) grow() {
|
||||||
|
last := s
|
||||||
|
for {
|
||||||
|
if last.next == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
last = last.next
|
||||||
|
}
|
||||||
|
var newSnake *snakeBody
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
newSnake = &snakeBody{
|
||||||
|
Rect: last.Rect,
|
||||||
|
dx: 0,
|
||||||
|
dy: 0,
|
||||||
|
tex: last.tex,
|
||||||
|
next: newSnake,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last.next = newSnake
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snakeBody) canMoveTo(dx, dy int32) bool {
|
||||||
|
if s.next == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
nextRect := s.next.Rect
|
||||||
|
if s.X + dx == nextRect.X && s.Y + dy == nextRect.Y {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fruit) draw(renderer *sdl.Renderer) {
|
||||||
|
renderer.Copy(f.tex, nil, &f.Rect)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fruit) newLoc(s *snakeBody, w, h int) {
|
||||||
|
rect := getRandomRect(w, h)
|
||||||
|
for !isEmpty(rect, s) {
|
||||||
|
rect = getRandomRect(w, h)
|
||||||
|
}
|
||||||
|
f.X = rect.X
|
||||||
|
f.Y = rect.Y
|
||||||
|
}
|
||||||
Loading…
Reference in new issue