Esempio n. 1
0
func main() {
	if err := glfw.Init(); err != nil {
		fmt.Println("glfw.Init():", err)
		return
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.Decorated, glfw.True)
	glfw.WindowHint(glfw.ContextVersionMajor, 1)
	glfw.WindowHint(glfw.ContextVersionMinor, 0)
	glfw.WindowHint(glfw.Resizable, glfw.True)

	window, err := glfw.CreateWindow(10, 10, "Settlers", nil, nil)
	if err != nil {
		fmt.Println("glfw.CreateWindow():", err)
		return
	}
	window.MakeContextCurrent()

	if err := gl.Init(); err != nil {
		fmt.Println("gl.Init():", err)
		return
	}

	stash := fontstash.New(512, 512)
	fontID, err := stash.AddFont(resourcePath("MorrisRoman-Black.ttf"))
	if err != nil {
		fmt.Println(err)
		return
	}
	stash.SetYInverted(true)
	font := &font{stash, fontID, 35}

	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	gl.MatrixMode(gl.MODELVIEW)
	gl.LoadIdentity()

	rand.Seed(time.Now().UnixNano())
	g := game.New([]game.Color{game.Red, game.White, game.Blue}, rand.Int())

	var lines []string
	window.SetCharCallback(func(_ *glfw.Window, r rune) {
		if len(lines) == 0 {
			lines = []string{""}
		}
		lines[len(lines)-1] += string(r)
	})
	window.SetCharModsCallback(func(_ *glfw.Window, r rune, _ glfw.ModifierKey) {
	})
	window.SetKeyCallback(func(_ *glfw.Window, key glfw.Key, _ int, action glfw.Action, _ glfw.ModifierKey) {
		if action == glfw.Release {
			return
		}
		if key == glfw.KeyEscape {
			window.SetShouldClose(true)
		}
		if key == glfw.Key1 {
			g.CurrentPlayer = 0
		}
		if key == glfw.Key2 {
			g.CurrentPlayer = 1
		}
		if key == glfw.Key3 {
			g.CurrentPlayer = 2
		}
		if key == glfw.Key4 {
			g.CurrentPlayer = 3
		}
		if key == glfw.KeyR {
			state = buildingRoad
		}
		if key == glfw.KeyS {
			state = buildingSettlement
		}
		if key == glfw.KeyKP2 {
			g.DealResources(2)
		}
		if key == glfw.KeyKP3 {
			g.DealResources(3)
		}
		if key == glfw.KeyKP4 {
			g.DealResources(4)
		}
		if key == glfw.KeyKP5 {
			g.DealResources(5)
		}
		if key == glfw.KeyKP6 {
			g.DealResources(6)
		}
		if key == glfw.KeyKP8 {
			g.DealResources(8)
		}
		if key == glfw.KeyKP9 {
			g.DealResources(9)
		}
		if key == glfw.KeyKP0 {
			g.DealResources(10)
		}
		if key == glfw.KeyKP1 {
			g.DealResources(11)
		}
		if key == glfw.KeyKP7 {
			g.DealResources(12)
		}
		if len(lines) > 0 && key == glfw.KeyBackspace && (action == glfw.Press || action == glfw.Repeat) {
			if len(lines[len(lines)-1]) == 0 {
				lines = lines[:len(lines)-1]
			} else {
				lines[len(lines)-1] = removeLastRune(lines[len(lines)-1])
			}
		}
		if (action == glfw.Press || action == glfw.Repeat) &&
			(key == glfw.KeyEnter || key == glfw.KeyKPEnter) {
			lines = append(lines, "")
		}
	})
	window.SetInputMode(glfw.CursorMode, glfw.CursorHidden)
	window.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
	window.SetSizeCallback(func(_ *glfw.Window, w, h int) {
		windowW, windowH = w, h
		cam.WindowWidth, cam.WindowHeight = w, h
		gl.Viewport(0, 0, int32(w), int32(h))
	})

	if err := loadImages(); err != nil {
		fmt.Println(err)
		return
	}

	var background image.Image
	var backImg *glImage
	go func() {
		gameW, gameH := 7*200, 7*tileYOffset+tileSlopeHeight
		back := image.NewRGBA(image.Rect(0, 0, gameW, gameH))
		clearToTransparent(back)
		drawGameBackgroundIntoImage(back, g)
		background = back
	}()

	gameColorToString := func(c game.Color) string {
		switch c {
		case game.Red:
			return "red"
		case game.Orange:
			return "orange"
		case game.Blue:
			return "blue"
		default:
			return "white"
		}
	}

	roadImage := func(pos game.TileEdge, c game.Color) *glImage {
		color := gameColorToString(c)
		dir := "up"
		if isEdgeVertical(pos) {
			dir = "vertical"
		}
		if isEdgeGoingDown(pos) {
			dir = "down"
		}
		return glImages["road_"+color+"_"+dir]
	}

	settlementImage := func(c game.Color) *glImage {
		return glImages["settlement_"+gameColorToString(c)]
	}

	cityImage := func(c game.Color) *glImage {
		return glImages["city_"+gameColorToString(c)]
	}

	// TODO this is for showing the road/settlement being built currently
	var movingSettlementCorner game.TileCorner
	var movingSettlementVisible bool
	var movingRoadEdge game.TileEdge
	var movingRoadVisible bool
	window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) {
		mouseX, mouseY = x, y
		gameX, gameY := cam.screenToGame(x, y)
		movingSettlementCorner, movingSettlementVisible = screenToCorner(gameX, gameY)
		movingRoadEdge, movingRoadVisible = screenToEdge(gameX, gameY)
	})
	window.SetCursorEnterCallback(func(_ *glfw.Window, entered bool) {
		mouseIn = entered
		if entered == false {
			movingSettlementVisible = false
			movingRoadVisible = true
		}
	})
	//////////////////////////////////////////////////////////////////

	drawGame := func() {
		if backImg == nil && background != nil {
			backImg, _ = NewGLImageFromImage(background)
		}
		if backImg != nil {
			backImg.DrawAtXY(0, 0)

			for _, p := range g.GetPlayers() {
				for _, r := range p.GetBuiltRoads() {
					x, y := edgeToScreen(r.Position)
					img := roadImage(r.Position, p.Color)
					img.DrawAtXY(x-img.Width/2, y-img.Height/2)
				}
				for _, s := range p.GetBuiltSettlements() {
					x, y := cornerToScreen(s.Position)
					img := settlementImage(p.Color)
					img.DrawAtXY(x-img.Width/2, y-(5*img.Height/8))
				}
				for _, c := range p.GetBuiltCities() {
					x, y := cornerToScreen(c.Position)
					img := cityImage(p.Color)
					img.DrawAtXY(x-img.Width/2, y-(5*img.Height/8))
				}
			}

			if state == buildingSettlement && movingSettlementVisible && mouseIn {
				color := [4]float32{1, 1, 1, 1}
				x, y := cornerToScreen(movingSettlementCorner)
				if !movingSettlementVisible || !g.CanBuildSettlementAt(movingSettlementCorner) {
					color = [4]float32{0.7, 0.7, 0.7, 0.7}
					x, y = cam.screenToGame(mouseX, mouseY)
				}
				img := settlementImage(g.GetCurrentPlayer().Color)
				// TODO duplicate code:
				img.DrawColoredAtXY(x-img.Width/2, y-(5*img.Height/8), color)
			}
			if state == buildingRoad && movingRoadVisible && mouseIn {
				color := [4]float32{1, 1, 1, 1}
				x, y := edgeToScreen(movingRoadEdge)
				if !(!movingRoadVisible || !g.CanBuildRoadAt(movingRoadEdge)) {
					img := roadImage(movingRoadEdge, g.GetCurrentPlayer().Color)
					// TODO duplicate code:
					img.DrawColoredAtXY(x-img.Width/2, y-(5*img.Height/8), color)
				}
			}

			x, y, w, h := tileToScreen(g.Robber.Position)
			robber := glImages["robber"]
			robber.DrawAtXY(x+(w-robber.Width)/2, y+(h-robber.Height)/2)
		}
	}

	buildMenu := &menu{color{0.5, 0.4, 0.8, 0.9}, rect{0, 500, 800, 250}}

	showCursor := 0
	start := time.Now()
	frames := 0

	window.SetSize(windowW, windowH)

	for !window.ShouldClose() {
		glfw.PollEvents()

		gl.MatrixMode(gl.PROJECTION)
		gl.LoadIdentity()
		const controlsHeight = 0 // TODO reserve are for stats and menus
		gameW, gameH := 7.0*200, 7.0*tileYOffset+tileSlopeHeight+controlsHeight
		gameRatio := gameW / gameH
		windowRatio := float64(windowW) / float64(windowH)
		var left, right, bottom, top float64
		if windowRatio > gameRatio {
			// window is wider than game => borders left and right
			border := (windowRatio*gameH - gameW) / 2
			left, right = -border, border+gameW
			bottom, top = gameH, 0
		} else {
			// window is higher than game => borders on top and bottom
			border := (gameW/windowRatio - gameH) / 2
			left, right = 0, gameW
			bottom, top = gameH+border, -border
		}
		gl.Ortho(left, right, bottom, top, -1, 1)
		cam.Left, cam.Right, cam.Bottom, cam.Top = left, right, bottom, top
		gl.ClearColor(0, 0, 1, 1)
		gl.Clear(gl.COLOR_BUFFER_BIT)

		drawGame()

		lines = make([]string, g.PlayerCount*6)
		for i, player := range g.GetPlayers() {
			lines[i*6+0] = fmt.Sprintf("player %v has %v ore", i+1, player.Resources[game.Ore])
			lines[i*6+1] = fmt.Sprintf("player %v has %v grain", i+1, player.Resources[game.Grain])
			lines[i*6+2] = fmt.Sprintf("player %v has %v lumber", i+1, player.Resources[game.Lumber])
			lines[i*6+3] = fmt.Sprintf("player %v has %v wool", i+1, player.Resources[game.Wool])
			lines[i*6+4] = fmt.Sprintf("player %v has %v brick", i+1, player.Resources[game.Brick])
		}

		if len(lines) > 0 {
			stash.BeginDraw()
			const fontSize = 35
			const cursorText = "" //"_"
			cursor := ""
			if showCursor > 60 {
				cursor = cursorText
			}
			for i, line := range lines {
				output := line
				if i == len(lines)-1 {
					output += cursor
				}
				font.Write(output, 0, float64(i+1)*fontSize)
			}
			if len(lines) == 0 {
				font.Write(cursor, 0, fontSize)
			}
			stash.EndDraw()
		}

		buildMenu.draw()

		window.SwapBuffers()

		showCursor = (showCursor + 1) % 120
		frames++
		if time.Now().Sub(start).Seconds() >= 1.0 {
			fmt.Println(frames, "fps")
			frames = 0
			start = time.Now()
		}
	}
}
Esempio n. 2
0
func NewGameUI(win Window) (*gameUI, error) {
	if err := settings.Settings.Load(); err != nil {
		fmt.Println("cannot load last settings:", err)
	}

	graphics, err := newGraphics()
	if err != nil {
		return nil, err
	}
	g := game.New([]game.Color{game.Red, game.Blue, game.White}, 1)

	// main menu
	size := func(w, h int) rect { return rect{w: w, h: h} }
	newGame := newButton(lang.NewGame, size(500, 80), NewGameOption)
	joinRemoteGame := newButton(lang.JoinRemoteGame, size(500, 80), JoinRemoteGameOption)
	chooseLanguage := newButton(lang.LanguageWord, size(500, 80), ChooseLanguageOption)
	quit := newButton(lang.Quit, size(500, 80), QuitOption)
	mainMenu := newWindow(
		rect{0, 0, gameW, gameH},
		newVerticalFlowLayout(20),
		newGame,
		joinRemoteGame,
		chooseLanguage,
		quit,
	)

	// language menu
	var langBoxes []*checkBox
	for language := lang.Language(0); language < lang.LastLanguage; language++ {
		action := LanguageOptionOffset + int(language)
		cb := newCheckBox(lang.Item(language), size(300, 80), action)
		cb.setChecked(settings.Settings.Language == int(language))
		langBoxes = append(langBoxes, cb)
	}
	languageMenu := newWindow(
		rect{0, 0, gameW, gameH},
		newVerticalFlowLayout(0),
		newCheckBoxGroup(langBoxes...),
		newSpacer(size(0, 20)),
		newButton(lang.OK, size(300, 80), LanguageOKOption),
	)
	languageMenu.setVisible(false)

	// new game menu
	threePlayers := newCheckBox(lang.ThreePlayers, size(350, 80), ThreePlayersOption)
	threePlayers.checked = settings.Settings.PlayerCount == 3
	fourPlayers := newCheckBox(lang.FourPlayers, size(350, 80), FourPlayersOption)
	fourPlayers.checked = settings.Settings.PlayerCount == 4
	var playerMenus [4]*window
	for i := range playerMenus {
		playerIndex := i // need to copy this for use in closures
		nameText := newTextBox(lang.Name, rect{0, 0, 500, 80}, graphics.font)
		nameText.text = settings.Settings.PlayerNames[i]
		nameText.onTextChange(func(text string) {
			settings.Settings.PlayerNames[playerIndex] = text
		})
		playHere := newCheckBox(lang.PlayHere, rect{0, 0, 500, 80}, -1)
		playHere.onCheckChange(func(checked bool) {
			if checked {
				settings.Settings.PlayerTypes[playerIndex] = settings.Human
			}
		})
		playHere.checked = settings.Settings.PlayerTypes[i] == settings.Human
		playAI := newCheckBox(lang.AIPlayer, rect{0, 0, 500, 80}, -1)
		playAI.onCheckChange(func(checked bool) {
			if checked {
				settings.Settings.PlayerTypes[playerIndex] = settings.AI
			}
		})
		playAI.checked = settings.Settings.PlayerTypes[i] == settings.AI
		ipText := newTextBox(lang.IP, rect{0, 0, 500, 80}, graphics.font)
		ipText.text = settings.Settings.IPs[i]
		ipText.onTextChange(func(text string) {
			settings.Settings.IPs[playerIndex] = text
		})
		portText := newTextBox(lang.Port, rect{0, 0, 500, 80}, graphics.font)
		portText.text = settings.Settings.Ports[i]
		portText.onTextChange(func(text string) {
			settings.Settings.Ports[playerIndex] = text
		})
		connectButton := newButton(lang.Connect, size(500, 80), -1)
		playNetwork := newCheckBox(lang.NetworkPlayer, rect{0, 0, 500, 80}, -1)
		playNetwork.onCheckChange(func(checked bool) {
			ipText.setEnabled(checked)
			portText.setEnabled(checked)
			connectButton.setEnabled(checked)
			if checked {
				settings.Settings.PlayerTypes[playerIndex] = settings.NetworkPlayer
			}
		})
		playNetwork.setChecked(settings.Settings.PlayerTypes[i] == settings.NetworkPlayer)

		playerMenus[i] = newWindow(
			rect{},
			newVerticalFlowLayout(0),
			newSpacer(rect{0, 0, 620, 30}),
			nameText,
			newCheckBoxGroup(
				playHere,
				playAI,
				playNetwork,
			),
			ipText,
			portText,
			connectButton,
			newSpacer(rect{0, 0, 0, 30}),
		)
	}
	var playerTabs [4]*tab
	for i := range playerTabs {
		col := game.Color(i)
		playerTabs[i] = newTab(fullPlayerColor(col), playerMenus[i], i < settings.Settings.PlayerCount)
	}
	playersSheet := newTabSheet(60, playerTabs[:]...)

	newGameMenu := newWindow(
		rect{0, 0, gameW, gameH},
		newVerticalFlowLayout(20),
		newCheckBoxGroup(threePlayers, fourPlayers),
		playersSheet,
		newButton(lang.StartGame, rect{0, 0, 400, 80}, StartGameOption),
		newButton(lang.Back, rect{0, 0, 400, 80}, NewGameBackOption),
	)
	newGameMenu.setVisible(false)

	ui := &gameUI{
		game:           g,
		window:         win,
		camera:         newCamera(),
		graphics:       graphics,
		mainMenu:       mainMenu,
		newGameMenu:    newGameMenu,
		languageMenu:   languageMenu,
		playerTabSheet: playersSheet,
		lastPlayerTab:  playerTabs[3],
	}
	ui.buyMenu = newBuyMenu(graphics, ui)
	ui.gui = newComposite(ui.mainMenu, ui.newGameMenu, ui.languageMenu)
	if err := ui.init(); err != nil {
		return nil, err
	}
	ui.setLanguage(lang.Language(settings.Settings.Language))
	//ui.DEBUG_initGame()
	return ui, nil
}
Esempio n. 3
0
func main() {
	g := game.New([]game.Color{game.Red, game.Blue, game.White}, rand.Int)
	state := buildingSettlement
	g.Players[0].Roads[0].Position = game.TileEdge{9, 2}

	draw.RunWindow("Settlers", 1400, 1000, draw.Resizable, func(window draw.Window) {
		if window.WasKeyPressed("escape") {
			window.Close()
		}

		if window.WasKeyPressed("s") {
			state = buildingSettlement
		}
		if window.WasKeyPressed("r") {
			state = buildingRoad
		}
		if window.WasKeyPressed("c") {
			state = buildingCity
		}

		for i := 1; i <= 4; i++ {
			if window.WasKeyPressed(strconv.Itoa(i)) {
				fmt.Println(g.CurrentPlayer, "->", i)
				g.CurrentPlayer = i - 1
			}
		}

		if state == buildingSettlement || state == buildingCity || state == buildingRoad {
			canBuild := g.CanPlayerBuildSettlement
			build := g.BuildSettlement
			screenToTile := screenToCorner
			if state == buildingCity {
				canBuild = g.CanPlayerBuildCity
				build = g.BuildCity
			}
			if state == buildingRoad {
				canBuild = g.CanPlayerBuildRoad
				build = g.BuildRoad
				screenToTile = screenToEdge
			}
			if canBuild() {
				for _, click := range window.Clicks() {
					if click.Button == draw.LeftButton {
						corner, ok := screenToTile(click.X, click.Y, 40)
						if ok {
							build(corner)
						} else {
							fmt.Println("miss")
						}
					}
				}
			}
		}

		for i := 2; i <= 12; i++ {
			// TODO what about 7?
			if window.WasKeyPressed(strconv.Itoa(i)) {
				g.DealResources(i)
			}
		}

		drawGame(g, window)
		if state == buildingSettlement || state == buildingCity {
			mx, my := window.MousePosition()
			corner, hit := screenToCorner(mx, my, 40)
			if hit {
				x, y := cornerToScreen(corner)
				color := currentPlayerColor(g)
				color.A = 0.75
				window.FillEllipse(x-40, y-40, 80, 80, color)
				if state == buildingSettlement && !g.CanBuildSettlementAt(game.TileCorner(corner)) {
					color.A = 1
					window.DrawLine(x-50, y-50, x+50, y+50, color)
					window.DrawLine(x-50, y+50, x+50, y-50, color)
				}
			}
		}
		if state == buildingRoad {
			mx, my := window.MousePosition()
			edge, hit := screenToEdge(mx, my, 40)
			if hit {
				x, y := edgeToScreen(game.TileEdge(edge))
				color := currentPlayerColor(g)
				color.A = 0.75
				window.FillEllipse(x-40, y-40, 80, 80, color)
				if !g.CanBuildRoadAt(game.TileEdge(edge)) {
					color.A = 1
					window.DrawLine(x-50, y-50, x+50, y+50, color)
					window.DrawLine(x-50, y+50, x+50, y-50, color)
				}
			}
		}
	})
}
Esempio n. 4
0
func (ui *gameUI) MouseButtonDown(button glfw.MouseButton) {
	if button != glfw.MouseButtonLeft {
		return // TODO handle right click when building to undo both buying and build
	}

	gameX, gameY := ui.camera.windowToGame(ui.mouseX, ui.mouseY)

	if ui.game.State == game.NotStarted {
		if action := ui.gui.click(gameX, gameY); action != -1 {
			switch action {
			case NewGameOption:
				ui.mainMenu.visible = false
				ui.newGameMenu.visible = true
			case ChooseLanguageOption:
				ui.mainMenu.visible = false
				ui.languageMenu.visible = true
			case QuitOption:
				ui.window.Close()
			case LanguageOKOption:
				ui.languageMenu.visible = false
				ui.mainMenu.visible = true
			case NewGameBackOption:
				ui.newGameMenu.visible = false
				ui.mainMenu.visible = true
			case StartGameOption:
				ui.game = game.New([]game.Color{game.Red, game.Blue, game.White}, rand.Int())
				ui.game = game.New([]game.Color{game.Red, game.Blue, game.White}, 0) // TODO remove
				ui.init()
				ui.game.Start()
			case ThreePlayersOption:
				ui.lastPlayerTab.visible = false
				ui.playerTabSheet.relayout()
				settings.Settings.PlayerCount = 3
			case FourPlayersOption:
				ui.lastPlayerTab.visible = true
				ui.playerTabSheet.relayout()
				settings.Settings.PlayerCount = 4
			}
			if action >= LanguageOptionOffset {
				language := lang.Language(action - LanguageOptionOffset)
				ui.setLanguage(language)
			}
		}
	} else if ui.game.State == game.ChoosingNextAction {
		ui.buyMenu.click(gameX, gameY)
	} else if ui.game.State == game.BuildingFirstSettlement ||
		ui.game.State == game.BuildingSecondSettlement ||
		ui.game.State == game.BuildingNewSettlement {
		corner, hit := screenToCorner(gameX, gameY)
		if hit && ui.game.CanBuildSettlementAt(corner) {
			ui.game.BuildSettlement(corner)
		}
	} else if ui.game.State == game.BuildingFirstRoad ||
		ui.game.State == game.BuildingSecondRoad ||
		ui.game.State == game.BuildingNewRoad {
		edge, hit := screenToEdge(gameX, gameY)
		if hit && ui.game.CanBuildRoadAt(edge) {
			ui.game.BuildRoad(edge)
		}
	} else if ui.game.State == game.BuildingNewCity {
		corner, hit := screenToCorner(gameX, gameY)
		if hit && ui.game.CanBuildCityAt(corner) {
			ui.game.BuildCity(corner)
		}
	} else if ui.game.State == game.RollingDice {
		center := rect{gameW/2 - 100, gameH/2 - 50, 200, 100}
		if center.contains(gameX, gameY) {
			ui.game.RollTheDice()
		}
	}
}