Пример #1
0
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()
}
Пример #2
0
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)
	}
}
Пример #3
0
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()
}
Пример #4
0
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()
}
Пример #5
0
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()
}
Пример #6
0
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()
}
Пример #7
0
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)
}
Пример #8
0
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()
}
Пример #9
0
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()
}
Пример #10
0
// 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,
	}
}
Пример #11
0
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()
}
Пример #12
0
// 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,
	}
}
Пример #13
0
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)
}
Пример #14
0
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,
	}
}
Пример #15
0
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))
			}
		}
	}
}
Пример #16
0
// 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,
	}
}
Пример #17
0
// 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()
	}
}
Пример #18
0
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()
}
Пример #19
0
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()
}
Пример #20
0
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)
		}
	}
}
Пример #21
0
// 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)
	}
}
Пример #22
0
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
}
Пример #23
0
func NewClickable(x, y, w, h int, col tl.Attr) *Clickable {
	return &Clickable{
		r: tl.NewRectangle(x, y, w, h, col),
	}
}
Пример #24
0
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")
}
Пример #25
0
//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)
	}
}