commit
77b6918c9f
@ -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,
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -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
|
||||||
|
)
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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))]
|
||||||
|
}
|
||||||
Loading…
Reference in new issue