commit 77b6918c9fc5887c619c493e4675ad8049bc948d Author: Dustin Pianalto Date: Sun May 3 21:48:15 2020 -0800 Initial commit diff --git a/constants.go b/constants.go new file mode 100644 index 0000000..d2e7681 --- /dev/null +++ b/constants.go @@ -0,0 +1,46 @@ +package main + +var nums = [][]byte{ + { + 1,1,1, + 1,0,1, + 1,0,1, + 1,0,1, + 1,1,1, + }, + { + 1,1,0, + 0,1,0, + 0,1,0, + 0,1,0, + 1,1,1, + }, + { + 1,1,1, + 0,0,1, + 1,1,1, + 1,0,0, + 1,1,1, + }, + { + 1,1,1, + 0,0,1, + 0,1,1, + 0,0,1, + 1,1,1, + }, + { + 1,0,1, + 1,0,1, + 1,1,1, + 0,0,1, + 0,0,1, + }, + { + 1,1,1, + 1,0,0, + 1,1,1, + 0,0,1, + 1,1,1, + }, +} diff --git a/drawing.go b/drawing.go new file mode 100644 index 0000000..c3f08cb --- /dev/null +++ b/drawing.go @@ -0,0 +1,50 @@ +package main + +import "github.com/veandco/go-sdl2/sdl" + +func (p *paddle) draw(pixels []byte) { + startX := int(p.x - p.w / 2) + startY := int(p.y - p.h / 2) + + for y := 0; y < int(p.h); y++ { + for x := 0; x < int(p.w); x++ { + setPixel(startX + x, startY + y, p.color, pixels) + } + } + + numPos := pos{ + x: lerp(p.x, getCenter().x, 0.2), + y: 50, + } + drawNumber(numPos, p.color, 10, p.score, pixels) +} + +func (b *ball) draw(pixels []byte) { + for y := -b.radius; y < b.radius; y++ { + for x := -b.radius; x < b.radius; x++ { + if x * x + y * y < b.radius * b.radius { + setPixel(int(b.x+x), int(b.y+y), b.color, pixels) + } + } + } +} + +func drawNumber(pos pos, color sdl.Color, size, num int, pixels []byte) { + startX := int(pos.x) - (size * 3) / 2 + startY := int(pos.y) - (size * 5) / 2 + + for i, v := range nums[num] { + if v == 1 { + for y := startY; y < startY + size; y++ { + for x := startX; x < startX + size; x++ { + setPixel(x, y, color, pixels) + } + } + } + startX += size + if (i + 1) % 3 == 0 { + startY += size + startX -= size * 3 + } + } +} \ No newline at end of file diff --git a/main_loop.go b/main_loop.go new file mode 100644 index 0000000..2b93788 --- /dev/null +++ b/main_loop.go @@ -0,0 +1,65 @@ +package main + +import ( + "github.com/veandco/go-sdl2/sdl" + "log" + "time" +) + +func gameLoop(pixels []byte, player1, player2 paddle, ball ball, renderer *sdl.Renderer, tex *sdl.Texture, keyState []uint8) { + var frameStart time.Time + var elapsedTime float32 + + for { + frameStart = time.Now() + for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { + switch event.(type) { + case *sdl.QuitEvent: + return + } + } + if err := renderer.Clear(); err != nil { + log.Fatal(err) + } + + if state == play { + if player1.score == 5 || player2.score == 5 { + state = start + } + player1.update(keyState, elapsedTime) + player2.aiUpdate(&ball, elapsedTime) + ball.update(&player1, &player2, elapsedTime) + } else if state == start { + if keyState[sdl.SCANCODE_SPACE] != 0 { + player1.score = 0 + player2.score = 0 + resetBall(&ball) + state = play + } + } else if state == pause { + if keyState[sdl.SCANCODE_SPACE] != 0 { + resetBall(&ball) + state = play + } + } + + clearScreen(pixels) + player1.draw(pixels) + player2.draw(pixels) + ball.draw(pixels) + + if err := tex.Update(nil, pixels, winWidth*4); err != nil { + log.Fatal(err) + } + if err := renderer.Copy(tex, nil, nil); err != nil { + log.Fatal(err) + } + renderer.Present() + + elapsedTime = float32(time.Since(frameStart).Seconds()) + if elapsedTime < 0.005 { + sdl.Delay(5 - uint32(elapsedTime / 1000)) + elapsedTime = float32(time.Since(frameStart).Seconds()) + } + } +} \ No newline at end of file diff --git a/pong.go b/pong.go new file mode 100644 index 0000000..940d470 --- /dev/null +++ b/pong.go @@ -0,0 +1,84 @@ +package main + +import ( + "github.com/veandco/go-sdl2/sdl" + "log" +) + +var ( + winWidth = 800 + winHeight = 600 + state = start +) + +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() + + tex, err := renderer.CreateTexture( + sdl.PIXELFORMAT_ABGR8888, + sdl.TEXTUREACCESS_STREAMING, + int32(winWidth), + int32(winHeight)) + if err != nil { + log.Fatal(err) + } + defer tex.Destroy() + + player1 := paddle{ + pos: pos{50, 300}, + w: 20, + h: 100, + speed: 300, + score: 0, + color: sdl.Color{255, 0, 0, 255}, + } + + player2 := paddle{ + pos: pos{750, 300}, + w: 20, + h: 100, + speed: 300, + score: 0, + color: sdl.Color{0, 255, 0, 255}, + } + + ball := ball{ + pos: pos{400, 300}, + radius: 20, + dx: 400, + dy: 400, + color: sdl.Color{0, 0, 255, 255}, + } + + keyState := sdl.GetKeyboardState() + pixels := make([]byte, winHeight*winWidth*4) + + resetBall(&ball) + + gameLoop(pixels, player1, player2, ball, renderer, tex, keyState) + +} + + diff --git a/types.go b/types.go new file mode 100644 index 0000000..5b35c3c --- /dev/null +++ b/types.go @@ -0,0 +1,32 @@ +package main + +import "github.com/veandco/go-sdl2/sdl" + +type pos struct { + x, y float32 +} + +type ball struct { + pos + radius float32 + dx float32 + dy float32 + color sdl.Color +} + +type paddle struct { + pos + w float32 + h float32 + speed float32 + score int + color sdl.Color +} + +type gameState int +const ( + start gameState = iota + play + pause + end +) \ No newline at end of file diff --git a/updating.go b/updating.go new file mode 100644 index 0000000..7d0f6ff --- /dev/null +++ b/updating.go @@ -0,0 +1,63 @@ +package main + +import ( + "github.com/veandco/go-sdl2/sdl" + "math" +) + +func (p *paddle) update(keyState []uint8, et float32) { + if keyState[sdl.SCANCODE_UP] != 0 && p.y - p.h / 2 > 0 { + p.y -= p.speed * et + } + if keyState[sdl.SCANCODE_DOWN] != 0 && p.y + p.h / 2 < float32(winHeight) { + p.y += p.speed * et + } +} + +func (p *paddle) aiUpdate(ball *ball, et float32) { + if ball.y + p.h / 2 < float32(winHeight) && ball.y - p.h / 2 > 0 { + p.y = ball.y + } +} + +func (b *ball) update(p1, p2 *paddle, et float32) { + if detectCollision(b, p1) { + if b.y < p1.y+p1.h/2 && b.y > p1.y-p1.h/2 && b.dx < 0{ + b.dx = -b.dx + } else if b.x < p1.x + p1.w / 2 && b.x > p1.x - p1.w / 2 { + b.dy = -b.dy + } else { + testX, testY := closestCorner(b, p1) + vx, vy := testX - b.x, testY - b.y + vd := float32(math.Sqrt(float64(vx * vx + vy * vy))) + ux, uy := vx / vd, vy / vd + b.x, b.y = testX - b.radius * ux, testY - b.radius * uy + + q := -(2 * (b.dx * (b.x - testX) + b.dy * (b.y - testY)) / (b.radius * b.radius)) + b.dx = b.dx + q * (b.x - testX) + b.dy = b.dy + q * (b.y - testY) + } + } + + b.x += b.dx * et + b.y += b.dy * et + if b.y - b.radius < 1 || b.y + b.radius > float32(winHeight) - 1 { + b.dy = -b.dy + } + + if b.x - b.radius < 0 { + p2.score++ + b.pos = getCenter() + state = pause + } else if b.x + b.radius > float32(winWidth) { + p1.score++ + b.pos = getCenter() + state = pause + } + + if b.x + b.radius >= p2.x - p2.w / 2 && b.dx > 0{ + if b.y < p2.y+p2.h/2 && b.y > p2.y-p2.h/2 { + b.dx = -b.dx + } + } +} \ No newline at end of file diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..91b35bf --- /dev/null +++ b/utils.go @@ -0,0 +1,63 @@ +package main + +import ( + "github.com/veandco/go-sdl2/sdl" + "math/rand" + "time" +) + +func closestCorner(b *ball, p *paddle) (float32, float32) { + testX := b.x + testY := b.y + if b.x < p.x - p.w / 2 { + testX = p.x - p.w / 2 + } else if b.x > p.x + p.w / 2 { + testX = p.x + p.w / 2 + } + if b.y < p.y - p.h / 2 { + testY = p.y - p.h / 2 + } else if b.y > p.y + p.h / 2 { + testY = p.y + p.h / 2 + } + return testX, testY +} + +func detectCollision(b *ball, p *paddle) bool { + testX, testY := closestCorner(b, p) + + sideX := b.x - testX + sideY := b.y - testY + return b.radius * b.radius >= sideX * sideX + sideY * sideY +} + +func setPixel(x, y int, c sdl.Color, pixels []byte) { + index := (y*winWidth + x) * 4 + if index < len(pixels) - 4 && index >= 0 { + pixels[index] = c.R + pixels[index+1] = c.G + pixels[index+2] = c.B + //pixels[index+3] = c.A + } +} + +func clearScreen(pixels []byte) { + for i := range pixels { + pixels[i] = 0 + } +} + +func getCenter() pos { + return pos{float32(winWidth) / 2, float32(winHeight) / 2} +} + +func lerp(a, b, pct float32) float32 { + return a + pct * (b - a) +} + +func resetBall(b *ball) { + choices := []float32{-400, -200, 200, 400} + s := rand.NewSource(time.Now().Unix()) + r := rand.New(s) + b.dy = choices[r.Intn(len(choices))] + b.dx = choices[r.Intn(len(choices))] +} \ No newline at end of file