JoelOtter / termloop

Terminal-based game engine for Go, built on top of Termbox
Other
1.43k stars 83 forks source link

How to Have Fixed Position Text #57

Closed chrisjd20 closed 3 years ago

chrisjd20 commented 3 years ago

I'm trying to create an in-game hud using a Text object that's position is always fixed to the top-left corner of the screen.

I can get the text to the correct position sorta but it will not be perfectly fixed. It moves to the desired position when the whole screen updates next but it creates this laggy looking effect where part of the grid coordinates gets cut off or appear off screen for a short time.

Here's what I got in code so far (its chopped out but here is the important bits):

type GridCoordinates struct {
    *tl.Text
}

// positions the coords Text object in top-left.
func (m *GridCoordinates) Tick(ev tl.Event) {
    // plr is the player object
    mx, my := m.Position()
    x, y := plr.Position()
    sx, sy := game.Screen().Size()
    finx := x - sx/2
    finy := y - sy/2
    if finx != mx || finy != my {
        crd := "x" + strconv.Itoa(x) + ",y" + strconv.Itoa(y)
        m.SetPosition(x-sx/2, y-sy/2)
        m.SetText(crd)
    }
}

GridText := tl.NewText(0, 0, "x0,y0", tl.ColorWhite, tl.ColorBlue)
coords = GridCoordinates{GridText}
level.AddEntity(&coords)

This is the visual result:

image

How could I get some Text to always stay fixed in the upper left hand corner?

chrisjd20 commented 3 years ago

My guess is that the screen offset is updating after the fact due to SetOffset here:

func (player *Player) Draw(screen *tl.Screen) {
    screenWidth, screenHeight := screen.Size()
    x, y := player.Position()
    player.level.SetOffset(screenWidth/2-x, screenHeight/2-y)
    player.Entity.Draw(screen)
}

Surely there has to be a way to have a fixed position object or Text to create overlays for games?

chrisjd20 commented 3 years ago

Woops didn't mean to close.

JoelOtter commented 3 years ago

I think you probably want to be updating the position of your text as part of the Draw step, not the Tick step, and making it based entirely on the screen size, not on the player position.

JoelOtter commented 3 years ago

Maybe have a look at the Pyramid example for inspiration. :)

https://github.com/JoelOtter/termloop/blob/master/_examples/pyramid.go

I really need to rewrite this library at some point...

chrisjd20 commented 3 years ago

Oh ok that example helped. I was adding the text to the level when I should have been adding it to the screen after doing setlevel:

game.Screen().SetLevel(level)
GridText := tl.NewText(0, 0, "x0,y0", tl.ColorWhite, tl.ColorBlue)
coords = GridCoordinates{GridText}
game.Screen().AddEntity(&coords)

Then, like you said, I needed to put the changes in the Draw step:

func (m *GridCoordinates) Draw(screen *tl.Screen) {
    x, y := plr.Position()
    crd := "x" + strconv.Itoa(x) + ",y" + strconv.Itoa(y)
    if m.Text.Text() != crd {
        m.SetText(crd)
        m.SetPosition(0, 0)
    }
    m.Text.Draw(screen)
}

Results in:

image

JoelOtter commented 3 years ago

Glad you got sorted, thanks for using Termloop :)