func (g *Game) buildLevel(gameLevel int) { level := tl.NewBaseLevel(tl.Cell{}) // TODO: Remove this abomination width := boardWidth*squareWidth + (boardWidth+1)*borderWidth height := boardHeight*squareHeight + (boardHeight+1)*borderHeight level.AddEntity(tl.NewRectangle(1, 1, width, height, tl.ColorGreen)) for i := 0; i < boardHeight; i++ { for j := 0; j < boardWidth; j++ { x := offsetX + borderWidth + (j * squareWidth) + j*borderWidth y := offsetY + borderHeight + (i * squareHeight) + i*borderHeight level.AddEntity(tl.NewRectangle(x, y, squareWidth, squareHeight, tl.ColorBlue)) } } g.board.populateBoard(gameLevel, answersPerLevel, level) level.AddEntity(g.player) // Add Foes foes := int(gameLevel/10) + 2 g.foes = g.foes[:0] var foe *Foe for i := 0; i < foes; i++ { foe = NewFoe(g) g.foes = append(g.foes, foe) level.AddEntity(foe) } g.game.Screen().SetLevel(level) g.updateStatus() }
func (board *Board) build() { for i := 0; i <= 12; i++ { for j := 0; j <= 12; j++ { board.spots[i][j].outer = termloop.NewRectangle( i*pw, j*pl, pw, pl, termloop.ColorWhite) board.spots[i][j].inner = termloop.NewRectangle( i*pw+1, j*pl+1, pw-2, pl-2, termloop.ColorWhite) } } for i := 1; i <= 4; i++ { tltext := termloop.NewText(3, i, "", termloop.ColorWhite, termloop.ColorBlack) board.texts = append(board.texts, tltext) } }
func world() { game := tl.NewGame() level := tl.NewBaseLevel(tl.Cell{ Bg: tl.ColorWhite, Fg: tl.ColorWhite, Ch: '_', }) for i := -1000; i < 1000; i = i + 40 { if i == 0 { continue } for j := -1000; j < 1000; j = j + 40 { level.AddEntity(tl.NewRectangle(i, j, 20, 10, tl.ColorBlue)) } } player := Player{ entity: tl.NewEntity(1, 1, 1, 1), level: level, } player.entity.SetCell(0, 0, &tl.Cell{Fg: tl.ColorBlack, Ch: '옷'}) level.AddEntity(&player) game.Screen().SetLevel(level) go func() { for { player.Tick(tl.Event{}) time.Sleep(200 * time.Millisecond) } }() game.Start() }
func (l *endLevel) ActivateWin() { l.Level = tl.NewBaseLevel(tl.Cell{Bg: l.bg, Fg: l.fg}) l.Level.AddEntity(&l.gt.console) l.win = true moneyEarned := 1000 l.gt.stats.LevelsCompleted++ l.gt.stats.LevelsAttempted++ l.gt.stats.Dollars += moneyEarned l.gt.stats.TotalEarned += moneyEarned l.gt.console.SetText("") w, h := l.gt.g.Screen().Size() rect := tl.NewRectangle(10, 2, w-20, h-4, tl.ColorCyan) l.AddEntity(rect) l.endMessages = []*tl.Entity{} l.addEndMessage("data/you_win_a.txt", w/2, 3) l.addEndMessage("data/you_win_b.txt", w/2, 3) l.AddEntity(l.endMessages[l.currentMessage]) l.PrintStats(moneyEarned, w/2, 13) l.Activate() }
func main() { // create game object game := tl.NewGame() // create cell cell := tl.Cell{ Bg: tl.ColorGreen, Fg: tl.ColorBlack, Ch: 'v', } // create level filled with cell level := tl.NewBaseLevel(cell) // create body of water level.AddEntity(tl.NewRectangle(10, 10, 50, 20, tl.ColorBlue)) // create player player := Player{ entity: tl.NewEntity(1, 1, 1, 1), level: level, } player.entity.SetCell(0, 0, &tl.Cell{Fg: tl.ColorRed, Ch: '@'}) // add player to level level.AddEntity(&player) // set level of screen game.Screen().SetLevel(level) // start the game game.Start() }
func (l *endLevel) ActivateFail() { l.win = false l.gt.stats.LevelsAttempted++ l.gt.stats.Lives-- if l.gt.stats.Lives == 0 { l.ActivateGameOver() return } l.Level = tl.NewBaseLevel(tl.Cell{Bg: l.bg, Fg: l.fg}) l.AddEntity(&l.gt.console) l.gt.console.SetText("") w, h := l.gt.g.Screen().Size() rect := tl.NewRectangle(10, 2, w-20, h-4, tl.ColorCyan) l.AddEntity(rect) l.endMessages = []*tl.Entity{} l.addEndMessage("data/you_loose_a.txt", w/2, 3) l.addEndMessage("data/you_loose_b.txt", w/2, 3) l.AddEntity(l.endMessages[l.currentMessage]) l.PrintStats(0, w/2, 13) l.Activate() }
func (player *Player) Draw(s *tl.Screen) { screenWidthidth, screenh := s.Size() x := player.sprite.x + screenWidthidth/2 - 30 y := player.sprite.y + screenh - 25 bg := tl.NewRectangle(x, y, x+20, y+10, StatsBG) bg.Draw(s) health := tl.NewText(x+1, y+1, fmt.Sprintf("%3.f%% health", float32(player.health)/float32(player.maxHealth)*100), tl.ColorRed, StatsBG) health.Draw(s) mana := tl.NewText(x+27, y+1, fmt.Sprintf("%3.f%% mana", float32(player.mana)/float32(player.maxMana)*100), tl.ColorBlue, StatsBG) mana.Draw(s) gold := tl.NewText(x+1, y+12, fmt.Sprintf("%d gold", player.gold), tl.ColorYellow, StatsBG) gold.Draw(s) experience := tl.NewText(x+29, y+12, fmt.Sprintf("%3.f%% xp", float32(player.experience)/float32(player.experienceToLevel)*100), tl.ColorMagenta, StatsBG) experience.Draw(s) if player.isCasting { player.isCasting = false newSpellEffect := NewSpellEffect(player.sprite, player.spellCanvases[player.sprite.direction], player.sprite.level) player.sprite.level.AddEntity(newSpellEffect) } e := tl.NewEntityFromCanvas(x+12, y+1, *player.portrait) e.Draw(s) }
func main() { g := tl.NewGame() l := tl.NewBaseLevel(tl.Cell{ Bg: tl.ColorWhite, }) l.AddEntity(&CollRec{ r: tl.NewRectangle(3, 3, 3, 3, tl.ColorRed), move: true, }) l.AddEntity(&CollRec{ r: tl.NewRectangle(7, 4, 3, 3, tl.ColorGreen), move: false, }) g.SetLevel(l) g.Start() }
func main() { rand.Seed(time.Now().UTC().UnixNano()) game := tl.NewGame() level := tl.NewBaseLevel(tl.Cell{ Bg: tl.ColorWhite, }) for i := 0; i < 4; i++ { TilePos[i] = rand.Intn(4) level.AddEntity(&Tile{ r: tl.NewRectangle(X+TilePos[i]*(TileWidth+BorderWidth), Y-i*(TileHeight+BorderHeight), TileWidth, TileHeight, tl.ColorBlack), }) } level.AddEntity(tl.NewText(X+TileWidth/2-1, Y+TileHeight, "←", tl.ColorBlack, tl.ColorWhite)) level.AddEntity(tl.NewText(X+(TileWidth+BorderWidth)+TileWidth/2-1, Y+TileHeight, "↓", tl.ColorBlack, tl.ColorWhite)) level.AddEntity(tl.NewText(X+2*(TileWidth+BorderWidth)+TileWidth/2-1, Y+TileHeight, "↑", tl.ColorBlack, tl.ColorWhite)) level.AddEntity(tl.NewText(X+3*(TileWidth+BorderWidth)+TileWidth/2-1, Y+TileHeight, "→", tl.ColorBlack, tl.ColorWhite)) level.AddEntity(&RemainingTime{ r: tl.NewText(X+4*(TileWidth+BorderWidth), 0, fmt.Sprintf("%.3f", Time), tl.ColorRed, tl.ColorDefault), s: tl.NewText(0, 0, "0", tl.ColorRed, tl.ColorDefault), t: Time, m: tl.NewText(0, Y+TileHeight+1, "", tl.ColorRed, tl.ColorDefault), e: tl.NewText(X+4*(TileWidth+BorderWidth), Y+TileHeight+1, "", tl.ColorRed, tl.ColorDefault), }) game.Screen().SetLevel(level) game.Start() }
// TODO move to snobee.go func NewSnobee(x, y int, game *tl.Game) *Snobee { return &Snobee{ r: tl.NewRectangle(x, y, 1, 1, tl.ColorYellow), x: x, y: y, g: game, } }
func main() { g := tl.NewGame() g.Screen().SetFps(60) l := tl.NewBaseLevel(tl.Cell{ Bg: tl.ColorWhite, }) l.AddEntity(&CollRec{ r: tl.NewRectangle(3, 3, 3, 3, tl.ColorRed), move: true, }) l.AddEntity(&CollRec{ r: tl.NewRectangle(7, 4, 3, 3, tl.ColorGreen), move: false, }) g.Screen().SetLevel(l) g.Screen().AddEntity(tl.NewFpsText(0, 0, tl.ColorRed, tl.ColorDefault, 0.5)) g.Start() }
// TODO move to pengo.go func NewPengo(x, y int, game *tl.Game) *Pengo { return &Pengo{ r: tl.NewRectangle(x, y, 1, 1, tl.ColorRed), x: x, y: y, g: game, d: NONE, } }
func (l *storeLevel) refresh() { l.Level = tl.NewBaseLevel(tl.Cell{Bg: l.bg, Fg: l.fg}) l.gt.store.AddEntity(&l.gt.console) l.gt.console.SetText("") w, h := l.gt.g.Screen().Size() rect := tl.NewRectangle(10, 2, w-20, h-4, tl.ColorGreen) l.AddEntity(rect) store, _ := ioutil.ReadFile("data/store.txt") c := tl.CanvasFromString(string(store)) l.AddEntity(tl.NewEntityFromCanvas(w/2-len(c)/2, 4, c)) msg := "Up/Down(j/k), Enter to purchase, N to return to the game" l.AddEntity(tl.NewText(w/2-len(msg)/2, 10, msg, tl.ColorBlack, tl.ColorDefault)) msg = fmt.Sprintf("Cash: $%d", l.gt.stats.Dollars) l.AddEntity(tl.NewText(14, 11, msg, tl.ColorBlack, tl.ColorDefault)) y := 12 for idx, i := range l.items { i.Reset(l.gt) x := 14 fg := tl.ColorBlack if i.Price() > l.gt.stats.Dollars { fg = tl.ColorRed } var price string if l.currentItem == idx { price = ">" + i.PriceDesc() + "<" } else { price = " " + i.PriceDesc() } l.AddEntity(tl.NewText(x, y, price, fg, tl.ColorDefault)) x += len(i.PriceDesc()) + 4 l.AddEntity(tl.NewText(x, y, i.Name(), tl.ColorBlue, tl.ColorDefault)) y++ } desc := l.items[l.currentItem].Desc() l.AddEntity(tl.NewText(14, y+1, desc, tl.ColorBlue, tl.ColorDefault)) y = 12 x := w - 30 msg = fmt.Sprintf("Goroutines: %d", len(l.gt.items)) l.AddEntity(tl.NewText(x, y, msg, tl.ColorBlue, tl.ColorDefault)) y++ msg = fmt.Sprintf("CPU Upgrades: %d", l.gt.stats.CPUUpgrades) l.AddEntity(tl.NewText(x, y, msg, tl.ColorBlue, tl.ColorDefault)) y++ msg = fmt.Sprintf("Go Version: %0.1f", l.gt.stats.GoVersion) l.AddEntity(tl.NewText(x, y, msg, tl.ColorBlue, tl.ColorDefault)) y++ l.gt.g.Screen().SetLevel(l) }
func NewBlock(x, y int, color tl.Attr, g *tl.Game, w, h, score int, scoretext *tl.Text) *Block { return &Block{ r: tl.NewRectangle(x, y, 1, 1, color), g: g, w: w, h: h, score: score, scoretext: scoretext, } }
func buildLevel(g *tl.Game, w, h, score int) { maze := generateMaze(w, h) l := tl.NewBaseLevel(tl.Cell{}) g.SetLevel(l) g.Log("Building level with width %d and height %d", w, h) scoretext := tl.NewText(0, 1, "Levels explored: "+strconv.Itoa(score), tl.ColorBlue, tl.ColorBlack) g.AddEntity(tl.NewText(0, 0, "Pyramid!", tl.ColorBlue, tl.ColorBlack)) g.AddEntity(scoretext) for i, row := range maze { for j, path := range row { if path == '*' { l.AddEntity(tl.NewRectangle(i, j, 1, 1, tl.ColorWhite)) } else if path == 'S' { l.AddEntity(NewBlock(i, j, tl.ColorRed, g, w, h, score, scoretext)) } else if path == 'L' { l.AddEntity(tl.NewRectangle(i, j, 1, 1, tl.ColorBlue)) } } } }
// TODO move to iceblock.go func NewIceBlock(x, y int, game *tl.Game, color tl.Attr) *Iceblock { return &Iceblock{ r: tl.NewRectangle(x, y, 1, 1, color), g: game, startPos: Point{ x: x, y: y, }, endPos: Point{ x: x, y: y, }, update: 0.05, direction: NONE, } }
// Handles player movement and food spawn rate. func (player *Player) Update(screen *tl.Screen) { player.snakeTime += screen.TimeDelta() if player.snakeTime > snakeRate { player.snakeTime -= snakeRate player.prevX, player.prevY = player.Position() switch player.direction { case "right": player.SetPosition(player.prevX+1, player.prevY) case "left": player.SetPosition(player.prevX-1, player.prevY) case "up": player.SetPosition(player.prevX, player.prevY-1) case "down": player.SetPosition(player.prevX, player.prevY+1) } player.SnakeMovement() } player.spawnTime += screen.TimeDelta() if player.spawnTime > spawnRate { player.spawnTime -= spawnRate screenWidth, screenHeight := screen.Size() rando := rand.New(rand.NewSource(time.Now().UnixNano())) spawnX, spawnY := rando.Intn(screenWidth), rando.Intn(screenHeight) screen.Level().AddEntity(tl.NewRectangle(spawnX, spawnY, 1, 1, tl.ColorGreen)) game.Log("Spawn at (%d,%d)", spawnX, spawnY) } //Check box boundaries playerX, playerY := player.Position() screenWidth, screenHeight := game.Screen().Size() //<= is used on the upper-boundaries to prevent the player from disappearing offscreen //by one square //(Funnily enough, when player.snake is more than one unit long, just stopping the player at //the boundaries also causes a game over state because the tail slides into the head) if playerX < 0 || playerX >= screenWidth { GameOver() } if playerY < 0 || playerY >= screenHeight { GameOver() } }
func main() { game := tl.NewGame() level := tl.NewBaseLevel(tl.Cell{ Bg: tl.ColorGreen, Fg: tl.ColorBlack, Ch: 'v', }) level.AddEntity(tl.NewRectangle(10, 10, 50, 20, tl.ColorBlue)) player := Player{ entity: tl.NewEntity(1, 1, 1, 1), level: level, } // Set the character at position (0, 0) on the entity. player.entity.SetCell(0, 0, &tl.Cell{Fg: tl.ColorRed, Ch: '옷'}) level.AddEntity(&player) game.SetLevel(level) game.Start() }
func (l *endLevel) ActivateGameOver() { l.Level = tl.NewBaseLevel(tl.Cell{Bg: l.bg, Fg: l.fg}) l.AddEntity(&l.gt.console) l.gt.console.SetText("") l.gt.g.SetEndKey(tl.KeyEnter) w, h := l.gt.g.Screen().Size() rect := tl.NewRectangle(10, 2, w-20, h-4, tl.ColorCyan) l.AddEntity(rect) l.endMessages = []*tl.Entity{} l.addEndMessage("data/game_over_a.txt", w/2, 3) l.addEndMessage("data/game_over_b.txt", w/2, 3) l.AddEntity(l.endMessages[l.currentMessage]) l.PrintStats(0, w/2, 13) l.Activate() }
func (text *StartLevel) Tick(event tl.Event) { if event.Type == tl.EventKey { if event.Key == tl.KeyEnter { level := tl.NewBaseLevel(tl.Cell{ Bg: tl.ColorBlack, Fg: tl.ColorBlack, }) player := Player{ snake: []*tl.Rectangle{tl.NewRectangle(0, 0, 1, 1, tl.ColorRed)}, level: level, } //player.entity.SetCell(0, 0, &tl.Cell{Fg: tl.ColorRed, Ch: '☺'}) level.AddEntity(&player) game.Screen().SetLevel(level) } } }
// Controls snake-like movement of the snake body. func (player *Player) SnakeMovement() { //Don't do anything if it's currently just the head if len(player.snake) > 1 { // Change color to white here because of difficulties putting it in player.Eat() player.snake[len(player.snake)-1].SetColor(tl.ColorWhite) // Need Deep Copy: refSnake := make([]*tl.Rectangle, len(player.snake)) for i := 0; i < len(player.snake); i++ { prevX, prevY := player.snake[i].Position() refSnake[i] = tl.NewRectangle(prevX, prevY, 1, 1, tl.ColorGreen) } for i := 1; i < len(player.snake)-1; i++ { prevX, prevY := refSnake[i].Position() player.snake[i+1].SetPosition(prevX, prevY) } player.snake[1].SetPosition(player.prevX, player.prevY) } }
func (l *introLevel) refresh() { l.gt.intro.AddEntity(&l.gt.console) l.gt.console.SetText("") w, h := l.gt.g.Screen().Size() quarterH := h / 4 rect := tl.NewRectangle(10, 2, w-20, h-4, tl.ColorCyan) l.AddEntity(rect) logo, _ := ioutil.ReadFile("data/logo.txt") c := tl.CanvasFromString(string(logo)) logoEntity := tl.NewEntityFromCanvas(w/2-len(c)/2, quarterH, tl.CanvasFromString(string(logo))) l.AddEntity(logoEntity) msg := "Press any key to continue" l.pressAKeyText = tl.NewText(w/2-len(msg)/2, h/2, msg, tl.ColorBlue|tl.AttrReverse, tl.ColorDefault) l.AddEntity(l.pressAKeyText) instructions, _ := ioutil.ReadFile("data/instructions.txt") c = tl.CanvasFromString(string(instructions)) l.AddEntity(tl.NewEntityFromCanvas(w/2-len(c)/2, h/2+2, c)) l.needsRefresh = false }
func NewClickable(x, y, w, h int, col tl.Attr) *Clickable { return &Clickable{ r: tl.NewRectangle(x, y, w, h, col), } }
func (d *TermloopDriver) OnInit(c *hachi.Chip8) { // hex keyboard with 16 keys. // 8, 4, 6 and 2 are typically used for directional input. d.keyMap = map[tl.Key]uint16{ tl.KeyTab: hachi.Key0, tl.KeyF2: hachi.Key1, tl.KeyF3: hachi.Key2, tl.KeyF4: hachi.Key3, tl.KeyF5: hachi.Key4, tl.KeyF6: hachi.Key5, tl.KeyF7: hachi.Key6, tl.KeyF8: hachi.Key7, tl.KeyF9: hachi.Key8, tl.KeyF10: hachi.Key9, tl.KeyCtrlA: hachi.KeyA, tl.KeyCtrlB: hachi.KeyB, tl.KeyCtrlC: hachi.KeyC, tl.KeyCtrlD: hachi.KeyD, tl.KeyCtrlE: hachi.KeyE, tl.KeyCtrlF: hachi.KeyF, tl.KeyArrowDown: hachi.Key2, tl.KeyArrowLeft: hachi.Key4, tl.KeyArrowRight: hachi.Key6, tl.KeyArrowUp: hachi.Key8, tl.KeyEnter: hachi.Key5, } // init termloop d.g = tl.NewGame() scr := d.g.Screen() scr.AddEntity(&inputHandler{c, d, make(map[uint16]time.Time)}) scr.AddEntity(tl.NewText(0, 0, "Stack Syscalls", tl.ColorDefault, tl.ColorDefault)) // stack d.stack = make([]*tl.Text, len(c.Stack)) for i := 0; i < len(d.stack); i++ { d.stack[i] = tl.NewText( 0, i+1, "", tl.ColorDefault, tl.ColorDefault) d.g.Screen().AddEntity(d.stack[i]) } // syscall log for i := 0; i < 10; i++ { d.syscalls[i] = tl.NewText( 8, i+1, "", tl.ColorDefault, tl.ColorDefault) d.g.Screen().AddEntity(d.syscalls[i]) } // chip info d.memory = tl.NewText(20, 0, "placeholder", tl.ColorDefault, tl.ColorDefault) scr.AddEntity(d.memory) d.registers = tl.NewText(20, 1, "placeholder", tl.ColorDefault, tl.ColorDefault) scr.AddEntity(d.registers) d.pointersAndTimers = tl.NewText(20, 2, "placeholder", tl.ColorDefault, tl.ColorDefault) scr.AddEntity(d.pointersAndTimers) d.devices = tl.NewText(20, 3, "placeholder", tl.ColorDefault, tl.ColorDefault) scr.AddEntity(d.devices) // screen preview at 20,5 d.screen = make([][]*tl.Rectangle, c.Width) color := tl.ColorWhite // foreground for i := uint8(0); i < c.Width; i++ { d.screen[i] = make([]*tl.Rectangle, c.Height) for j := uint8(0); j < c.Height; j++ { d.screen[i][j] = tl.NewRectangle( 20+int(i), 5+int(j), 1, 1, color, ) } } d.lastScreen = make([]byte, uint16(c.Width)*uint16(c.Height)/8) log.Println("TermloopDriver initialized") }
//Handles auto events func (player *Player) Update(screen *tl.Screen) { //tl.Screen.size() parameters are evidently zero until the game.Start(), //So this is a crude solution intended to center the player after the game has begun if firstPass { screenWidth, screenHeight := screen.Size() player.SetPosition(screenWidth/2, screenHeight/2) firstPass = false } snakeTime += screen.TimeDelta() if snakeTime > 0.1 { snakeTime -= 0.1 player.prevX, player.prevY = player.Position() switch player.direction { case "right": player.SetPosition(player.prevX+1, player.prevY) //player.SnakeMovement(player.prevX+1, player.prevY) case "left": player.SetPosition(player.prevX-1, player.prevY) //player.SnakeMovement(player.prevX-1, player.prevY) case "up": player.SetPosition(player.prevX, player.prevY-1) //player.SnakeMovement(player.prevX, player.prevY-1) case "down": player.SetPosition(player.prevX, player.prevY+1) //player.SnakeMovement(player.prevX, player.prevY+1) } player.SnakeMovement() } spawnTime += screen.TimeDelta() if spawnTime > 1 { spawnTime -= 1 screenWidth, screenHeight := screen.Size() rando := rand.New(rand.NewSource(time.Now().UnixNano())) spawnX, spawnY := rando.Intn(screenWidth), rando.Intn(screenHeight) screen.Level().AddEntity(tl.NewRectangle(spawnX, spawnY, 1, 1, tl.ColorGreen)) game.Log("Spawn at (%d,%d)", spawnX, spawnY) } //Check box boundaries playerX, playerY := player.Position() screenWidth, screenHeight := game.Screen().Size() //<= is used on the upper-boundaries to prevent the player from disappearing offscreen //by one square //(Funnily enough, when player.snake is more than one unit long, just stopping the player at //the boundaries also causes a game over state because the tail slides into the head) if playerX < 0 || playerX >= screenWidth { GameOver() //player.SetPosition(player.prevX, player.prevY) } if playerY < 0 || playerY >= screenHeight { GameOver() //player.SetPosition(player.prevX, player.prevY) } }