gopher-battle/screen_main.go

372 lines
11 KiB
Go
Raw Normal View History

2016-01-06 18:24:08 +00:00
package main
import (
"fmt"
2016-01-08 00:35:13 +00:00
"math"
2016-01-06 18:24:08 +00:00
"math/rand"
"time"
"gogs.bullercodeworks.com/brian/termbox-util"
"github.com/nsf/termbox-go"
)
const (
modeInit = iota
modeRun
modeRunInput
2016-01-07 04:04:42 +00:00
modePause
2016-01-06 18:24:08 +00:00
)
type mainScreen struct {
GameMode int
PlayerTurn int
2016-01-07 04:04:42 +00:00
Player1 *player
Player2 *player
Bullet *projectile
2016-01-06 18:24:08 +00:00
Buildings []building
2016-01-07 04:04:42 +00:00
PauseMenu *termboxUtil.Menu
r *rand.Rand
animating bool
2016-01-08 00:35:13 +00:00
gravity float64
2016-01-06 18:24:08 +00:00
}
2016-01-07 04:04:42 +00:00
func (screen *mainScreen) handleKeyPress(event termbox.Event) int {
if event.Key == termbox.KeyEsc {
if screen.GameMode != modePause {
screen.GameMode = modePause
} else {
screen.GameMode = modeRun
}
}
if screen.GameMode == modePause {
screen.PauseMenu.HandleKeyPress(event)
if screen.PauseMenu.IsDone() {
selOpt := screen.PauseMenu.GetSelectedOption()
if selOpt.GetText() == "Exit" {
return exitScreenIndex
} else if selOpt.GetText() == "Resume" {
screen.GameMode = modeRun
} else if selOpt.GetText() == "Restart" {
//screen.GameMode = modeInit
//return titleScreenIndex
}
}
}
2016-01-06 18:24:08 +00:00
if screen.GameMode == modeRunInput {
2016-01-07 04:04:42 +00:00
if event.Key == termbox.KeySpace {
if screen.PlayerTurn == 1 {
2016-01-08 00:35:13 +00:00
screen.Bullet.launchTime = time.Now()
2016-01-07 04:04:42 +00:00
screen.Bullet.angle = screen.Player1.projAngle
screen.Bullet.speed = screen.Player1.projSpeed
2016-01-08 00:35:13 +00:00
screen.Bullet.startX, screen.Bullet.startY = screen.Player1.GetBulletHandPos()
2016-01-07 04:04:42 +00:00
} else {
2016-01-08 00:35:13 +00:00
screen.Bullet.launchTime = time.Now()
2016-01-07 04:04:42 +00:00
screen.Bullet.angle = 180 - screen.Player2.projAngle
screen.Bullet.speed = screen.Player2.projSpeed
2016-01-08 00:35:13 +00:00
screen.Bullet.startX, screen.Bullet.startY = screen.Player2.GetBulletHandPos()
2016-01-07 04:04:42 +00:00
}
2016-01-08 00:35:13 +00:00
screen.Bullet.x = screen.Bullet.startX
screen.Bullet.y = screen.Bullet.startY
2016-01-07 04:04:42 +00:00
screen.animating = true
screen.GameMode = modeRun
} else if event.Key == termbox.KeyArrowLeft || event.Ch == 'a' {
if screen.PlayerTurn == 1 {
if screen.Player1.projAngle < 180 {
screen.Player1.projAngle++
}
} else {
if screen.Player2.projAngle > 0 {
screen.Player2.projAngle--
}
}
} else if event.Key == termbox.KeyArrowRight || event.Ch == 'd' {
if screen.PlayerTurn == 1 {
if screen.Player1.projAngle > 0 {
screen.Player1.projAngle--
}
} else {
if screen.Player2.projAngle > 180 {
screen.Player2.projAngle++
}
}
} else if event.Key == termbox.KeyArrowUp || event.Ch == 'w' {
if screen.PlayerTurn == 1 {
2016-01-08 00:35:13 +00:00
// TODO: Upper speed limit
2016-01-07 04:04:42 +00:00
screen.Player1.projSpeed++
} else {
2016-01-08 00:35:13 +00:00
// TODO: Upper speed limit
2016-01-07 04:04:42 +00:00
screen.Player2.projSpeed++
}
} else if event.Key == termbox.KeyArrowDown || event.Ch == 's' {
if screen.PlayerTurn == 1 {
2016-01-08 00:35:13 +00:00
if screen.Player1.projSpeed > 0 {
screen.Player1.projSpeed--
}
2016-01-07 04:04:42 +00:00
} else {
2016-01-08 00:35:13 +00:00
if screen.Player2.projSpeed > 0 {
screen.Player2.projSpeed--
}
2016-01-07 04:04:42 +00:00
}
}
2016-01-06 18:24:08 +00:00
}
return mainScreenIndex
}
func (screen *mainScreen) performLayout(style style) {
var bldCity int
if screen.GameMode == modeInit {
2016-01-08 00:35:13 +00:00
// Default screen gravity:
screen.gravity = float64(-9.81)
b := projectile{gravity: screen.gravity}
2016-01-07 04:04:42 +00:00
screen.Bullet = &b
// TODO: Reset Buildings
//screen.Buildings = []building{}
2016-01-06 18:24:08 +00:00
// Create a random seed (from time)
seed := fmt.Sprintf("%d", time.Now().UnixNano())
2016-01-07 04:04:42 +00:00
screen.r = rand.New(rand.NewSource(getSeedFromString(seed + "-world")))
screen.PlayerTurn = screen.r.Intn(1) + 1
2016-01-06 18:24:08 +00:00
for bldCity < ScreenWidth {
2016-01-07 04:04:42 +00:00
w := screen.r.Intn(8) + 6
h := screen.r.Intn(ScreenHeight-10) + 2
2016-01-06 18:24:08 +00:00
var c termbox.Attribute
2016-01-07 04:04:42 +00:00
switch screen.r.Intn(3) {
2016-01-06 18:24:08 +00:00
case 0:
c = termbox.ColorRed
case 1:
c = termbox.ColorGreen
case 2:
c = termbox.ColorBlue
}
2016-01-07 04:04:42 +00:00
if ScreenWidth-(bldCity+w) < 5 {
w += ScreenWidth - (bldCity + w)
}
2016-01-06 18:24:08 +00:00
b := building{width: w, height: h, color: c}
screen.Buildings = append(screen.Buildings, b)
bldCity += w
}
2016-01-07 04:04:42 +00:00
// Player 1 should be on the first 1/3 of the buildings
bld := screen.r.Intn(len(screen.Buildings) / 3)
p1x, p1y := screen.getRndPosForBuilding(bld)
screen.Player1 = createPlayer(p1x, p1y)
// Player 2 should be on the third 1/3 of the buildings
bld = screen.r.Intn(len(screen.Buildings)/3) + ((len(screen.Buildings) * 2) / 3)
p2x, p2y := screen.getRndPosForBuilding(bld)
if ScreenWidth-p2x < 5 {
p2x, p2y = screen.getRndPosForBuilding(bld - 1)
2016-01-06 18:24:08 +00:00
}
2016-01-07 04:04:42 +00:00
screen.Player2 = createPlayer(p2x, p2y)
screen.PauseMenu = termboxUtil.CreateMenu("** GOPHER BATTLE **",
[]string{"Resume", "Restart", "Exit"},
(ScreenWidth/2)-11, (ScreenHeight/2)-3, 22, 6,
style.defaultFg, style.defaultBg)
screen.PauseMenu.SetBordered(true)
screen.GameMode = modeRun
2016-01-06 18:24:08 +00:00
}
2016-01-07 04:04:42 +00:00
}
func createPlayer(px, py int) *player {
p := player{x: px, y: py, projSpeed: 10, projAngle: 45, baseColor: termbox.ColorCyan}
return &p
2016-01-06 18:24:08 +00:00
}
// Trigger all updates
func (screen *mainScreen) update() {
if screen.GameMode == modeRun {
2016-01-07 04:04:42 +00:00
if !screen.animating {
screen.GameMode = modeRunInput
} else {
2016-01-08 00:35:13 +00:00
if screen.Bullet.x > 0 && screen.Bullet.x < ScreenWidth && screen.Bullet.y < ScreenHeight && screen.Bullet.y > -5000 {
screen.Bullet.update()
// Check for collisions
2016-01-07 04:04:42 +00:00
} else {
// Bullet went off the sides of the screen
screen.animating = false
}
}
2016-01-06 18:24:08 +00:00
}
}
func (screen *mainScreen) drawScreen(style style) {
// Draw Player 1
screen.Player1.draw()
// Draw Player 2
screen.Player2.draw()
// Draw Landscape
var x int
for i := range screen.Buildings {
screen.Buildings[i].draw(x)
x += screen.Buildings[i].width
}
if screen.GameMode == modeRun {
// Draw Projectile(s)
2016-01-07 04:04:42 +00:00
if screen.Bullet != nil {
screen.Bullet.draw()
}
2016-01-06 18:24:08 +00:00
} else if screen.GameMode == modeRunInput {
// Draw inputs
if screen.PlayerTurn == 1 {
2016-01-07 04:04:42 +00:00
angleText := fmt.Sprintf("Angle: %d", screen.Player1.projAngle)
speedText := fmt.Sprintf("Speed: %d", screen.Player1.projSpeed)
termboxUtil.DrawStringAtPoint(angleText, 0, 0, style.defaultFg, style.defaultBg)
termboxUtil.DrawStringAtPoint(speedText, 0, 1, style.defaultFg, style.defaultBg)
termboxUtil.DrawStringAtPoint("'space' to fire", 0, 2, style.defaultFg, style.defaultBg)
2016-01-06 18:24:08 +00:00
} else {
2016-01-07 04:04:42 +00:00
angleText := fmt.Sprintf("Angle: %d", screen.Player2.projAngle)
speedText := fmt.Sprintf("Speed: %d", screen.Player2.projSpeed)
termboxUtil.DrawStringAtPoint(angleText, ScreenWidth-11, 0, style.defaultFg, style.defaultBg)
termboxUtil.DrawStringAtPoint(speedText, ScreenWidth-11, 1, style.defaultFg, style.defaultBg)
termboxUtil.DrawStringAtPoint("'space' to fire", ScreenWidth-15, 2, style.defaultFg, style.defaultBg)
2016-01-06 18:24:08 +00:00
}
}
2016-01-07 04:04:42 +00:00
if screen.GameMode == modePause {
// Draw the pause menu
screen.PauseMenu.Draw()
}
2016-01-06 18:24:08 +00:00
}
2016-01-07 04:04:42 +00:00
func (screen *mainScreen) getRndPosForBuilding(i int) (int, int) {
retY := ScreenHeight - screen.Buildings[i].height
bldStX := 0
for idx := 0; idx < i; idx++ {
bldStX += screen.Buildings[idx].width
}
retX := screen.r.Intn(screen.Buildings[i].width-5) + bldStX
return retX, retY
2016-01-06 18:24:08 +00:00
}
func getSeedFromString(seed string) int64 {
2016-01-07 04:04:42 +00:00
// Does this algorithm work for string->seed generation?
// ~\_(o.o)_/~ - seems to.
2016-01-06 18:24:08 +00:00
var ret int64
for i, k := range seed {
ret += int64(k) * int64(i)
}
return ret
}
2016-01-08 00:35:13 +00:00
func degToRad(d int) float64 {
return (float64(d) * (math.Pi / float64(180)))
}
2016-01-07 04:04:42 +00:00
type projectile struct {
2016-01-08 00:35:13 +00:00
x, y int
startX, startY int
speed, angle int
gravity float64
launchTime time.Time
}
func (p *projectile) update() {
// On an update we increase the tick
tm := time.Since(p.launchTime).Seconds()
useSpeed := float64(p.speed)
useX, useY := float64(p.startX), float64(p.startY)
halfG := 0.5 * p.gravity
p.x = int(useX + (useSpeed * tm))
p.y = int(useY + (useSpeed * tm) - (halfG * tm * tm))
//p.x = int(useX + (math.Cos(degToRad(p.angle)) * useSpeed * tm))
//p.y = int(useY + (math.Sin(degToRad(p.angle)) * useSpeed * tm * halfG * tm * tm))
WriteToLog(fmt.Sprintf("(%d) %d,%d (s:%d;a:%d)\n", tm, p.x, p.y, useSpeed, p.angle))
2016-01-07 04:04:42 +00:00
}
func (p *projectile) draw() {
termbox.SetCell(p.x, p.y, '0', termbox.ColorYellow, termbox.ColorBlack)
}
type player struct {
x, y int
projSpeed int
projAngle int
baseColor termbox.Attribute
}
func (p *player) draw() {
termbox.SetCell(p.x, p.y-4, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+1, p.y-4, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+2, p.y-4, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+3, p.y-4, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+4, p.y-4, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x, p.y-3, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+1, p.y-3, '@', termbox.ColorBlack, termbox.ColorWhite)
termbox.SetCell(p.x+2, p.y-3, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+3, p.y-3, '@', termbox.ColorBlack, termbox.ColorWhite)
termbox.SetCell(p.x+4, p.y-3, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x, p.y-2, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+1, p.y-2, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+2, p.y-2, 'w', termbox.ColorWhite, p.baseColor)
termbox.SetCell(p.x+3, p.y-2, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+4, p.y-2, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x, p.y-1, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+1, p.y-1, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+2, p.y-1, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+3, p.y-1, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+4, p.y-1, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x, p.y, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+1, p.y, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+2, p.y, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+3, p.y, ' ', p.baseColor, p.baseColor)
termbox.SetCell(p.x+4, p.y, ' ', p.baseColor, p.baseColor)
// Now draw the arms
bulletHandX, bulletHandY := p.GetBulletHandPos()
termbox.SetCell(bulletHandX, bulletHandY, 'O', termbox.ColorBlack, p.baseColor)
}
func (p *player) GetBulletHandPos() (int, int) {
if p.projAngle <= 11 {
return p.x + 5, p.y - 2
} else if p.projAngle <= 22 {
return p.x + 5, p.y - 3
} else if p.projAngle <= 41 {
return p.x + 5, p.y - 4
} else if p.projAngle <= 50 {
return p.x + 5, p.y - 5
} else if p.projAngle <= 77 {
return p.x + 4, p.y - 5
} else if p.projAngle <= 86 {
return p.x + 3, p.y - 5
} else if p.projAngle <= 95 {
return p.x + 2, p.y - 5
} else if p.projAngle <= 119 {
return p.x + 1, p.y - 5
} else if p.projAngle <= 130 {
return p.x, p.y - 5
} else if p.projAngle <= 141 {
return p.x - 1, p.y - 5
} else if p.projAngle <= 152 {
return p.x - 1, p.y - 4
} else if p.projAngle <= 165 {
return p.x - 1, p.y - 3
}
return p.x - 1, p.y - 2
}
type building struct {
width, height int
color termbox.Attribute
windowsOn []int
}
func (b *building) draw(x int) {
for i := 0; i < b.height; i++ {
for j := 0; j < b.width; j++ {
c := b.color
/* TODO: Windows
if i > 0 && i < b.height && j > 0 && j < b.width {
if i%2 == 1 && j%2 == 1 {
c = termbox.ColorBlack
}
}
*/
termbox.SetCell(x+j, ScreenHeight-i, ' ', c, c)
}
}
2016-01-06 18:24:08 +00:00
}