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