package main import ( "log" "strings" "time" _ "embed" "github.com/gdamore/tcell/v3" "github.com/gdamore/tcell/v3/color" ) //go:embed assets/title/title_idle.txt var title_idle string //go:embed assets/title/title_blinking.txt var title_blinking string func drawText(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style, text string) { row := y1 col := x1 var width int for text != "" { text, width = s.Put(col, row, text, style) col += width if col >= x2 { row++ col = x1 } if row > y2 { break } if width == 0 { // incomplete grapheme at end of string break } } } func drawTitle(s tcell.Screen, x, padding_top, frame int, style tcell.Style, titles [][]string) int{ lines := titles[frame] frame = (frame + 1) % 2 // Draw Title xmax, ymax := s.Size() for l:= range lines{ drawText(s,x, l+padding_top, xmax, ymax, style, lines[l]) } return len(lines) } func main() { cats := [][]string{ strings.Split(string(title_idle), "\n"), strings.Split(string(title_blinking), "\n")} defStyle := tcell.StyleDefault.Background(color.Black).Foreground(color.NewHexColor(0xf3e5ab)) // Initialize screen s, err := tcell.NewScreen() if err != nil { log.Fatalf("%+v", err) } if err := s.Init(); err != nil { log.Fatalf("%+v", err) } s.SetStyle(defStyle) s.Clear() quit := func() { // You have to catch panics in a defer, clean up, and // re-raise them - otherwise your application can // die without leaving any diagnostic trace. maybePanic := recover() s.Fini() if maybePanic != nil { panic(maybePanic) } } defer quit() // Here's how to get the screen size when you need it. // xmax, ymax := s.Size() // Here's an example of how to inject a keystroke where it will // be picked up by a future read of the event queue. Note that // care should be used to avoid blocking writes to the queue if // this is done from the same thread that is responsible for reading // the queue, or else a single-party deadlock might occur. // s.EventQ() <- tcell.NewEventKey(tcell.KeyRune, rune('a'), 0) curr_menu_item := 0 menu := true gap_title_menu := 3 credits := false frame := 0 ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() // Event loop for { s.Clear() title_size := drawTitle(s, 10, 2, frame, defStyle, cats) frame = (frame + 1) % 2 xmax,ymax := s.Size() // Draw Menu if menu { drawText(s, 10, title_size+gap_title_menu, xmax, ymax, defStyle, "Use arrows to navigate. Press ENTER to select") switch curr_menu_item { case 0: drawText(s, 10, title_size+gap_title_menu+2, xmax, ymax, defStyle, "▶ Start New Game") drawText(s, 10, title_size+gap_title_menu+3, xmax, ymax, defStyle, " Level Selector") drawText(s, 10, title_size+gap_title_menu+4, xmax, ymax, defStyle, " Credits") case 1: drawText(s, 10, title_size+gap_title_menu+2, xmax, ymax, defStyle, " Start New Game") drawText(s, 10, title_size+gap_title_menu+3, xmax, ymax, defStyle, "▶ Level Selector") drawText(s, 10, title_size+gap_title_menu+4, xmax, ymax, defStyle, " Credits") case 2: drawText(s, 10, title_size+gap_title_menu+2, xmax, ymax, defStyle, " Start New Game") drawText(s, 10, title_size+gap_title_menu+3, xmax, ymax, defStyle, " Level Selector") drawText(s, 10, title_size+gap_title_menu+4, xmax, ymax, defStyle, "▶ Credits") } } if credits { drawText(s, 10, title_size+gap_title_menu, xmax,ymax, defStyle, "Abderrahmane Faiz") drawText(s, 10, title_size+gap_title_menu+1, xmax,ymax, defStyle, "\u001B]8;;https://afaiz.dev\u001B\\https://afaiz.dev\u001B]8;;\u001B\\") drawText(s, 10, title_size+gap_title_menu+2, xmax,ymax, defStyle, "ASCII Art found on https://emojicombos.com/cat") drawText(s, 10, title_size+gap_title_menu+4, xmax,ymax, defStyle, "Press ENTER to go back to the menu") } // Update screen s.Show() // Poll event (this can be in a select statement as well) select{ case <- ticker.C: continue case ev := <-s.EventQ(): // Process event switch ev := ev.(type) { default: continue case *tcell.EventResize: s.Sync() case *tcell.EventKey: if ev.Key() == tcell.KeyEscape || ev.Key() == tcell.KeyCtrlC { return } else if ev.Key() == tcell.KeyUp && menu { if curr_menu_item == 0 { curr_menu_item = 2 } else { curr_menu_item = curr_menu_item - 1 } } else if ev.Key() == tcell.KeyDown && menu { curr_menu_item = (curr_menu_item + 1) % 3 } else if ev.Key() == tcell.KeyEnter && credits { credits = false menu = true } else if ev.Key() == tcell.KeyEnter && curr_menu_item == 2 { menu = false credits = true } } } } }