parent
a2075eea59
commit
00647a20e1
@ -0,0 +1,38 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"github.com/gdamore/tcell/v2" |
||||
) |
||||
|
||||
const ( |
||||
WALL = '#' |
||||
SPACE = '.' |
||||
PATH_LIMIT = 1000 |
||||
RENDER = true |
||||
SHOW_RENDER = false |
||||
SHOW_PATHS = false |
||||
HEARING_DISTANCE = 6 |
||||
) |
||||
|
||||
type Map [][]rune |
||||
|
||||
type Position struct { |
||||
X int |
||||
Y int |
||||
} |
||||
|
||||
type Enemy struct { |
||||
HP int |
||||
Pos Position |
||||
Damage int |
||||
} |
||||
|
||||
type Game struct { |
||||
Screen tcell.Screen |
||||
Level Map |
||||
Player Enemy |
||||
Status string |
||||
Width int |
||||
Height int |
||||
Enemies map[Position]*Enemy |
||||
} |
@ -0,0 +1,14 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"log" |
||||
"os" |
||||
) |
||||
|
||||
var dbg *log.Logger |
||||
|
||||
func DebugInit() { |
||||
out, err := os.Create("debug.log") |
||||
if err != nil { log.Fatal(err) } |
||||
dbg = log.New(out, "", log.LstdFlags) |
||||
} |
@ -0,0 +1,27 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"os" |
||||
) |
||||
|
||||
func NewGame(width int, height int) (*Game) { |
||||
var game Game |
||||
|
||||
game.Width = width |
||||
game.Height = height |
||||
game.Enemies = make(map[Position]*Enemy) |
||||
|
||||
game.Level = make(Map, height, height) |
||||
|
||||
game.Player = Enemy{20, Position{1,1}, 4} |
||||
|
||||
return &game |
||||
} |
||||
|
||||
func (game *Game) Exit() { |
||||
if RENDER { |
||||
game.Screen.Fini() |
||||
} |
||||
|
||||
os.Exit(0) |
||||
} |
@ -0,0 +1,65 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"slices" |
||||
) |
||||
|
||||
func compass(near Position, offset int) []Position { |
||||
return []Position{ |
||||
Position{near.X, near.Y - offset}, |
||||
Position{near.X, near.Y + offset}, |
||||
Position{near.X + offset, near.Y}, |
||||
Position{near.X - offset, near.Y}, |
||||
} |
||||
} |
||||
|
||||
func (game *Game) CloneMap() Map { |
||||
// this is a shallow copy though
|
||||
new_map := slices.Clone(game.Level) |
||||
|
||||
for i, row := range new_map { |
||||
// this makes sure the row is an actual copy
|
||||
new_map[i] = slices.Clone(row) |
||||
} |
||||
|
||||
return new_map |
||||
} |
||||
|
||||
func (game *Game) Inbounds(pos Position, offset int) bool { |
||||
return pos.X >= offset && |
||||
pos.X < game.Width - offset && |
||||
pos.Y >= offset && |
||||
pos.Y < game.Height - offset |
||||
} |
||||
|
||||
func (game *Game) Occupied(pos Position) bool { |
||||
is_player := pos == game.Player.Pos |
||||
|
||||
// Inbounds comes first to prevent accessing level with bad x,y
|
||||
return !game.Inbounds(pos, 1) || |
||||
game.Level[pos.Y][pos.X] == WALL || |
||||
is_player |
||||
} |
||||
|
||||
func (game *Game) FillMap(target Map, setting rune) { |
||||
for y := 0 ; y < game.Height; y++ { |
||||
target[y] = slices.Repeat([]rune{setting}, game.Width) |
||||
} |
||||
} |
||||
|
||||
|
||||
func (game *Game) NewMap() { |
||||
game.Level = Map{ |
||||
[]rune("#################"), |
||||
[]rune("#.#...#.........#"), |
||||
[]rune("#.#.###.#.###.#.#"), |
||||
[]rune("#.#.....#...#.#.#"), |
||||
[]rune("#.#.#######.#.###"), |
||||
[]rune("#.#...#...#.#...#"), |
||||
[]rune("#.###.###...###.#"), |
||||
[]rune("#...#.......#...#"), |
||||
[]rune("#.#.#########...#"), |
||||
[]rune("#.#.............#"), |
||||
[]rune("#################"), |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
package main |
||||
|
||||
func (game *Game) MovePlayer(x_delta int, y_delta int) { |
||||
target := Position{ |
||||
game.Player.Pos.X + x_delta, |
||||
game.Player.Pos.Y + y_delta, |
||||
} |
||||
|
||||
if !game.Occupied(target) { |
||||
game.Player.Pos = target |
||||
} |
||||
} |
@ -0,0 +1,114 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"log" |
||||
"fmt" |
||||
"github.com/gdamore/tcell/v2" |
||||
"github.com/gdamore/tcell/v2/encoding" |
||||
) |
||||
|
||||
//// DRAWING
|
||||
|
||||
func (game *Game) DrawText(x int, y int, text string) { |
||||
for i, cell := range text { |
||||
game.Screen.SetContent(x+i, y, cell, nil, tcell.StyleDefault) |
||||
} |
||||
} |
||||
|
||||
func (game *Game) DrawStatus() { |
||||
game.DrawText(0, game.Height, game.Status) |
||||
|
||||
hp := fmt.Sprintf("HP: %d", game.Player.HP) |
||||
|
||||
game.DrawText(game.Width - len(hp), game.Height, hp) |
||||
} |
||||
|
||||
func (game *Game) SetStatus(msg string) { |
||||
game.Status = msg |
||||
} |
||||
|
||||
func (game *Game) DrawEntity(symbol rune, pos Position, color tcell.Color) { |
||||
style := tcell.StyleDefault.Bold(true).Foreground(color) |
||||
game.Screen.SetContent(pos.X, pos.Y, symbol, nil, style) |
||||
} |
||||
|
||||
func (game *Game) DrawMap() { |
||||
gray := tcell.StyleDefault.Foreground(tcell.ColorGray) |
||||
|
||||
for y, line := range game.Level { |
||||
for x, cell := range line { |
||||
if cell == SPACE { |
||||
game.Screen.SetContent(x, y, cell, nil, gray) |
||||
} else { |
||||
game.Screen.SetContent(x, y, cell, nil, tcell.StyleDefault) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
///// RENDERING
|
||||
|
||||
func (game *Game) InitScreen() { |
||||
var err error |
||||
encoding.Register() |
||||
|
||||
game.Screen, err = tcell.NewScreen() |
||||
|
||||
// using log.Fatal instead of dbg.Fatal
|
||||
// because the screen isn't setup yet
|
||||
if err != nil { log.Fatal(err) } |
||||
|
||||
err = game.Screen.Init() |
||||
if err != nil { log.Fatal(err) } |
||||
} |
||||
|
||||
func (game *Game) Render() { |
||||
if !RENDER { return } |
||||
|
||||
game.Screen.Clear() |
||||
|
||||
game.DrawMap() |
||||
|
||||
game.DrawEntity('@', game.Player.Pos, tcell.ColorYellow) |
||||
|
||||
game.DrawStatus() |
||||
|
||||
game.Screen.Show() |
||||
} |
||||
|
||||
//// EVENTS
|
||||
|
||||
func (game *Game) HandleKeys(ev *tcell.EventKey) bool { |
||||
switch ev.Key() { |
||||
case tcell.KeyEscape: |
||||
return false |
||||
case tcell.KeyUp: |
||||
game.MovePlayer(0, -1) |
||||
case tcell.KeyDown: |
||||
game.MovePlayer(0, 1) |
||||
case tcell.KeyRight: |
||||
game.MovePlayer(1, 0) |
||||
case tcell.KeyLeft: |
||||
game.MovePlayer(-1, 0) |
||||
} |
||||
|
||||
switch ev.Rune() { |
||||
case 'q': |
||||
return false |
||||
} |
||||
|
||||
return true |
||||
} |
||||
|
||||
func (game *Game) HandleEvents() bool { |
||||
if !RENDER { return false } |
||||
|
||||
switch ev := game.Screen.PollEvent().(type) { |
||||
case *tcell.EventResize: |
||||
game.Screen.Sync() |
||||
case *tcell.EventKey: |
||||
return game.HandleKeys(ev) |
||||
} |
||||
|
||||
return true |
||||
} |
Loading…
Reference in new issue