Skip to content

Commit

Permalink
Dynamically initialise multiplayer host screen
Browse files Browse the repository at this point in the history
  • Loading branch information
z-riley committed Oct 13, 2024
1 parent 9671bdd commit c2e36dd
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 81 deletions.
155 changes: 80 additions & 75 deletions screen/multiplayer_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,99 +21,84 @@ type MultiplayerHostScreen struct {
win *turdgl.Window

title *turdgl.Text
labels []*turdgl.TextBox
buttons []*common.MenuButton
entries []*common.EntryBox
ipHeading *turdgl.TextBox
ipBody *turdgl.TextBox
nameHeading *common.MenuButton
nameEntry *common.EntryBox
start *common.MenuButton
back *common.MenuButton
playerCards []*playerCard

server *turdserve.Server
}

// NewTitle Screen constructs a new multiplayer host screen in the given window.
// NewMultiplayerHostScreen constructs an uninitialised multiplayer host screen.
func NewMultiplayerHostScreen(win *turdgl.Window) *MultiplayerHostScreen {
ipAddr := func() string {
if comms.IsWSL() {
return "check WSL host"
}
conn, err := comms.LocalIP()
if err != nil {
panic(err)
}
return conn.String()
}()
return &MultiplayerHostScreen{win: win}
}

title := turdgl.NewText("Host game", turdgl.Vec{X: 600, Y: 120}, common.FontPathMedium).
// Init initialises the screen.
func (s *MultiplayerHostScreen) Init(_ InitData) {
s.title = turdgl.NewText("Host game", turdgl.Vec{X: 600, Y: 120}, common.FontPathMedium).
SetColour(common.ArenaBackgroundColour).
SetAlignment(turdgl.AlignCentre).
SetSize(40)

nameHeading := common.NewMenuButton(400, 60, turdgl.Vec{X: 200 - 20, Y: 200}, func() {})
nameHeading.SetLabelOffset(turdgl.Vec{X: 0, Y: 32}).SetLabelText("Your name:")
nameEntry := common.NewEntryBox(400, 60, turdgl.Vec{X: 600 + 20, Y: 200})

ipHeading := common.NewTextBox(400, 60, turdgl.Vec{X: 200 - 20, Y: 300})
ipHeading.Text.SetOffset(turdgl.Vec{X: 0, Y: 32}).SetText("Your IP:")
ipBody := common.NewTextBox(400, 60, turdgl.Vec{X: 600 + 20, Y: 300})
ipBody.Text.SetOffset(turdgl.Vec{X: 0, Y: 32}).SetText(ipAddr)

var cards []*playerCard
for i := range 1 {
pos := turdgl.Vec{X: 300, Y: 450 + float64(i)*80}
cards = append(cards, newPlayerCard(pos, i))
}
s.ipHeading = common.NewTextBox(400, 60, turdgl.Vec{X: 200 - 20, Y: 300}).
SetTextOffset(turdgl.Vec{X: 0, Y: 32}).SetText("Your IP:")
s.ipBody = common.NewTextBox(400, 60, turdgl.Vec{X: 600 + 20, Y: 300}).
SetTextOffset(turdgl.Vec{X: 0, Y: 32}).SetText(s.getIPAddr())

start := common.NewMenuButton(400, 60, turdgl.Vec{X: 200 - 20, Y: 650}, func() {})
start.SetLabelOffset(turdgl.Vec{X: 0, Y: 32}).SetLabelText("Start game")

back := common.NewMenuButton(400, 60, turdgl.Vec{X: 600 + 20, Y: 650}, func() { SetScreen(MultiplayerMenu, nil) })
back.SetLabelAlignment(turdgl.AlignCustom).
SetLabelOffset(turdgl.Vec{X: 0, Y: 32}).SetLabelText("Back")

s := MultiplayerHostScreen{
win: win,
title: title,
labels: []*turdgl.TextBox{ipHeading, ipBody},
buttons: []*common.MenuButton{nameHeading, start, back},
entries: []*common.EntryBox{nameEntry},
playerCards: cards,
server: turdserve.NewServer(maxPlayers - 1),
}
s.nameHeading = common.NewMenuButton(400, 60, turdgl.Vec{X: 200 - 20, Y: 200}, func() {})
s.nameHeading.SetLabelOffset(turdgl.Vec{X: 0, Y: 32}).SetLabelText("Your name:")
s.nameEntry = common.NewEntryBox(400, 60, turdgl.Vec{X: 600 + 20, Y: 200})

start.SetCallback(func(_ turdgl.MouseState) {
s.start = common.NewMenuButton(400, 60, turdgl.Vec{X: 200 - 20, Y: 650}, func() {})
s.start.SetLabelOffset(turdgl.Vec{X: 0, Y: 32}).SetLabelText("Start game")
s.start.SetCallback(func(_ turdgl.MouseState) {
if err := s.startGame(); err != nil {
fmt.Println("Failed to start game:", err)
}
})

return &s
}
s.back = common.NewMenuButton(400, 60, turdgl.Vec{X: 600 + 20, Y: 650},
func() { SetScreen(MultiplayerMenu, nil) },
)
s.back.SetLabelAlignment(turdgl.AlignCustom).SetLabelOffset(turdgl.Vec{X: 0, Y: 32}).SetLabelText("Back")

s.playerCards = make([]*playerCard, maxPlayers-1)
for i := range s.playerCards {
pos := turdgl.Vec{X: 300, Y: 450 + float64(i)*80}
s.playerCards[i] = newPlayerCard(pos, i)
}

// Init initialises the screen.
func (s *MultiplayerHostScreen) Init(_ InitData) {
s.win.RegisterKeybind(turdgl.KeyEscape, turdgl.KeyRelease, func() {
SetScreen(MultiplayerMenu, nil)
})

// Set up server
s.server.SetCallback(func(id int, b []byte) {
if err := s.handleClientData(id, b); err != nil {
fmt.Println("Failed to handle data from client:", err)
}
}).SetDisconnectCallback(func(id int) {
s.handleClientDisconnect(id)
})
{
s.server = turdserve.NewServer(maxPlayers - 1).
SetCallback(func(id int, b []byte) {
if err := s.handleClientData(id, b); err != nil {
fmt.Println("Failed to handle data from client:", err)
}
}).SetDisconnectCallback(func(id int) {
s.handleClientDisconnect(id)
})

// Start server to allow other players to connect
errCh := make(chan error)
go func() {
for err := range errCh {
if err != nil {
panic("server crashed: " + err.Error())
// Start server to allow other players to connect
errCh := make(chan error)
go func() {
for err := range errCh {
if err != nil {
panic("server crashed: " + err.Error())
}
}
}()
if err := s.server.Start("0.0.0.0", serverPort, errCh); err != nil {
panic(err)
}
}()
if err := s.server.Start("0.0.0.0", serverPort, errCh); err != nil {
panic(err)
}
}

Expand All @@ -128,29 +113,32 @@ func (s *MultiplayerHostScreen) Update() {

s.win.Draw(s.title)

for _, l := range s.labels {
for _, l := range []*turdgl.TextBox{
s.ipHeading,
s.ipBody,
} {
s.win.Draw(l)
}

for _, b := range s.buttons {
for _, b := range []*common.MenuButton{
s.nameHeading,
s.start,
s.back,
} {
b.Update(s.win)
s.win.Draw(b)
}

for _, e := range s.entries {
s.win.Draw(e)
e.Update(s.win)
}
s.win.Draw(s.nameEntry)
s.nameEntry.Update(s.win)

for _, p := range s.playerCards {
s.win.Draw(p)
}

}

// handleClientData handles all data received from a client.
func (s *MultiplayerHostScreen) handleClientData(id int, b []byte) error {

fmt.Println("Received from client", id, ":", string(b))

var msg comms.Message
Expand Down Expand Up @@ -184,10 +172,22 @@ func (s *MultiplayerHostScreen) handlePlayerData(id int, data comms.PlayerData)
}

func (s *MultiplayerHostScreen) handleClientDisconnect(id int) {
// Remove data from player card
s.playerCards[id].setNotReady()
}

// getIPAddr returns the IP address of the host.
func (s *MultiplayerHostScreen) getIPAddr() string {
if comms.IsWSL() {
// If using WSL, the host IP address must be used
return "check WSL host"
}
conn, err := comms.LocalIP()
if err != nil {
panic(err)
}
return conn.String()
}

// serverKey is used for indentifying the server in InitData.
const serverKey = "server"

Expand Down Expand Up @@ -240,6 +240,7 @@ type playerCard struct {
light *turdgl.Circle
}

// newPlayerCard constructs a new player card. The ID must be unique.
func newPlayerCard(pos turdgl.Vec, id int) *playerCard {
const (
width = 400
Expand All @@ -264,23 +265,27 @@ func newPlayerCard(pos turdgl.Vec, id int) *playerCard {
}
}

// Draw draws a player card to the supplied framebuffer.
func (p *playerCard) Draw(buf *turdgl.FrameBuffer) {
p.name.Draw(buf)
p.light.Draw(buf)
}

// setReady sets a player's card to ready.
func (p *playerCard) setReady(username string) {
p.ready = true
p.name.Text.SetText(username)
p.light.SetStyle(styleReady)
}

// setNotReady removes player data from card and sets the status to not connected.
func (p *playerCard) setNotReady() {
p.ready = false
p.name.Text.SetText(fmt.Sprintf("Waiting for player %d", p.id+2))
p.light.SetStyle(styleNotReady)
}

// isReady returns whether the player is ready.
func (p *playerCard) isReady() bool {
return p.ready
}
9 changes: 3 additions & 6 deletions screen/multiplayer_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,8 @@ func (s *MultiplayerJoinScreen) Init(_ InitData) {

s.nameEntry = common.NewEntryBox(400, 60, turdgl.Vec{X: 600 + 20, Y: 300})

s.join = common.NewMenuButton(400, 60, turdgl.Vec{X: 400, Y: 400}, func() {
// Set callback in Init()
})
s.join.SetLabelOffset(turdgl.Vec{X: 0, Y: 32}).SetLabelText("Join")
s.join.SetCallback(
func(_ turdgl.MouseState) {
s.join = common.NewMenuButton(400, 60, turdgl.Vec{X: 400, Y: 400},
func() {
if err := s.joinGame(); err != nil {
fmt.Println("Failed to join game:", err)
return
Expand All @@ -74,6 +70,7 @@ func (s *MultiplayerJoinScreen) Init(_ InitData) {
}()
},
)
s.join.SetLabelOffset(turdgl.Vec{X: 0, Y: 32}).SetLabelText("Join")

s.back = common.NewMenuButton(400, 60, turdgl.Vec{X: 400, Y: 500}, func() {})
s.back.SetLabelAlignment(turdgl.AlignCustom).
Expand Down

0 comments on commit c2e36dd

Please sign in to comment.