1package main 2 3import ( 4 "github.com/xyproto/vt100" 5 "os" 6 "os/signal" 7 "sync" 8 "syscall" 9 "time" 10) 11 12type Bob struct { 13 x, y int 14 color string 15 state rune 16} 17 18func (b *Bob) ToggleColor() { 19 const c1 = "Red" 20 const c2 = "Yellow" 21 if b.color == c1 { 22 b.color = c2 23 } else { 24 b.color = c1 25 } 26} 27 28func (b *Bob) ToggleState() { 29 const up = 'O' 30 const down = 'o' 31 if b.state == up { 32 b.state = down 33 } else { 34 b.state = up 35 } 36} 37 38func (b *Bob) Draw(c *vt100.Canvas) { 39 c.PlotColor(uint(b.x), uint(b.y), vt100.LightColorMap[b.color], b.state) 40} 41 42func (b *Bob) Right(c *vt100.Canvas) bool { 43 b.x += 1 44 if b.x >= int(c.W()) { 45 b.x -= 1 46 return false 47 } 48 return true 49} 50 51func (b *Bob) Left(c *vt100.Canvas) bool { 52 if b.x-1 < 0 { 53 return false 54 } 55 b.x -= 1 56 return true 57} 58 59func (b *Bob) Up(c *vt100.Canvas) bool { 60 if b.y-1 < 0 { 61 return false 62 } 63 b.y -= 1 64 return true 65} 66 67func (b *Bob) Down(c *vt100.Canvas) bool { 68 b.y += 1 69 if b.y >= int(c.H()) { 70 b.y -= 1 71 return false 72 } 73 return true 74} 75 76func main() { 77 78 c := vt100.NewCanvas() 79 tty, err := vt100.NewTTY() 80 if err != nil { 81 panic(err) 82 } 83 84 var bob Bob 85 bob.state = 'o' 86 bob.color = "Yellow" 87 bob.x = 10 88 bob.y = 10 89 90 var draw sync.RWMutex 91 sigChan := make(chan os.Signal, 1) 92 signal.Notify(sigChan, syscall.SIGWINCH) 93 go func() { 94 for range sigChan { 95 // Terminal was resized 96 97 // Prepare to resize the canvas 98 draw.Lock() 99 100 // Clear the screen after the resize 101 vt100.Clear() 102 103 // Create a new canvas, with the new size 104 nc := c.Resized() 105 if nc != nil { 106 c.Clear() 107 c.Draw() 108 c = nc 109 } 110 // Clear again, for good measure 111 vt100.Clear() 112 // Redraw the characters 113 c.Redraw() 114 // Done 115 draw.Unlock() 116 } 117 }() 118 119 vt100.Clear() 120 vt100.ShowCursor(false) 121 vt100.SetLineWrap(true) 122 123 running := true 124 for running { 125 126 //vt100.Clear() 127 128 // Draw elements in their new positions 129 draw.Lock() 130 bob.Draw(c) 131 draw.Unlock() 132 133 // Update the canvas 134 draw.Lock() 135 c.Draw() 136 draw.Unlock() 137 138 // Wait a bit 139 time.Sleep(time.Millisecond * 10) 140 141 // Change state 142 oldx := bob.x 143 oldy := bob.y 144 moved := false 145 146 // Handle events 147 draw.Lock() 148 switch tty.Key() { 149 case 253: // Up 150 moved = bob.Up(c) 151 case 255: // Down 152 moved = bob.Down(c) 153 case 254: // Right 154 moved = bob.Right(c) 155 case 252: // Left 156 moved = bob.Left(c) 157 case 27, 113: // ESC or q 158 running = false 159 break 160 case 32: // Space 161 bob.ToggleColor() 162 } 163 draw.Unlock() 164 165 if moved { 166 bob.ToggleState() 167 168 // Erase elements at their old positions 169 draw.Lock() 170 c.Plot(uint(oldx), uint(oldy), ' ') 171 draw.Unlock() 172 } 173 } 174 tty.Close() 175 176 vt100.SetLineWrap(true) 177 vt100.ShowCursor(true) 178 vt100.Home() 179} 180