Example #1
0
func (m *Menu) moveRight() {
	item := m.Items[m.FocusedIndex]
	switch {
	case item.Selector != nil:
		item.Selector.selectedIndex = (item.Selector.selectedIndex + 1) % len(item.Selector.Choices)
		audio.Play(audio.SoundMove)

	case item.Slider != nil:
		if item.Slider.Value++; item.Slider.Value > item.Slider.Max {
			item.Slider.Value = item.Slider.Min
		}
		audio.Play(audio.SoundMove)
	}
}
Example #2
0
func (m *Menu) moveUp() {
	if m.FocusedIndex -= 1; m.FocusedIndex < 0 {
		m.FocusedIndex = len(m.Items) - 1
		m.Selected = false
	}
	audio.Play(audio.SoundMove)
}
Example #3
0
func (m *Menu) moveLeft() {
	item := m.Items[m.FocusedIndex]
	switch {
	case item.Selector != nil:
		if item.Selector.selectedIndex--; item.Selector.selectedIndex < 0 {
			item.Selector.selectedIndex = len(item.Selector.Choices) - 1
		}
		audio.Play(audio.SoundMove)

	case item.Slider != nil:
		if item.Slider.Value--; item.Slider.Value < item.Slider.Min {
			item.Slider.Value = item.Slider.Max
		}
		audio.Play(audio.SoundMove)
	}
}
Example #4
0
func (b *Board) updateMatches() {
	// Update each match - clearing one block at a time.
	for i := 0; i < len(b.matches); i++ {
		m := b.matches[i]
		finished := true

	loop:
		// Animate each block one at a time. Break if it is still animating.
		for _, mc := range m.cells {
			block := b.blockAt(mc.x, mc.y)
			switch {
			case block.State == BlockCracked:
				block.State = BlockExploding
				audio.Play(audio.SoundClear)
				finished = false
				break loop

			case block.State != BlockExploded:
				finished = false
				break loop
			}
		}

		// Clear the blocks and remove the chain once all animations are done.
		if finished {
			for _, mc := range m.cells {
				b.blockAt(mc.x, mc.y).State = BlockClearPausing
			}
			b.matches = append(b.matches[:i], b.matches[i+1:]...)
			i--
		}
	}
}
Example #5
0
// swap swaps the left block with the right block.
func (l *Block) swap(r *Block, swapID int) {
	if blockStateSwappable[l.State] && blockStateSwappable[r.State] {
		l.State, r.State = r.State, l.State
		l.Color, r.Color = r.Color, l.Color
		l.swapID, r.swapID = swapID, swapID
		l.Dropping, r.Dropping = false, false

		numBlocks := 0

		switch l.State {
		case BlockStatic:
			l.setState(BlockSwappingFromRight)
			numBlocks++
		case BlockClearPausing, BlockCleared:
			l.setState(BlockCleared)
		}

		switch r.State {
		case BlockStatic:
			r.setState(BlockSwappingFromLeft)
			numBlocks++
		case BlockClearPausing, BlockCleared:
			r.setState(BlockCleared)
		}

		if numBlocks > 0 {
			audio.Play(audio.SoundSwap)
		}
	}
}
Example #6
0
func (b *Board) addNewMatches() {
	// Find new matches and append them to the overall list.
	matches := findGroupedMatches(b)
	b.matches = append(b.matches, matches...)

	var dirtyLinks []*chainLink

	for _, m := range matches {
		hasDroppedBlock := false
		for _, c := range m.cells {
			block := b.blockAt(c.x, c.y)
			block.State = BlockFlashing

			hasDroppedBlock = hasDroppedBlock || block.Dropping
			if block.Dropping {
				block.Dropping = false
				audio.Play(audio.SoundThud)
			}

			b.numUpdateBlocksCleared++
			b.numSpeedBlocksCleared++
		}

		var link *chainLink
		if hasDroppedBlock {
		linkLoop:
			for _, l := range b.chainLinks {
				for _, lm := range l.matches {
					for _, lc := range lm.cells {
						for _, mc := range m.cells {
							if lc.x == mc.x && lc.y <= mc.y {
								link = l
								break linkLoop
							}
						}
					}
				}
			}
		}

		if link == nil {
			link = &chainLink{}
			b.chainLinks = append(b.chainLinks, link)
		} else {
			link.level++
		}

		link.nextMatches = append(link.nextMatches, m)
		dirtyLinks = append(dirtyLinks, link)
		b.markerAt(m.cells[0].x, m.cells[0].y).show(len(m.cells), link.level)
	}

	for _, link := range dirtyLinks {
		link.matches = link.nextMatches
		link.nextMatches = nil
	}
}
Example #7
0
func (m *Menu) selectItem() {
	m.Selected = true
	audio.Play(audio.SoundSelect)
}
Example #8
0
func (m *Menu) moveDown() {
	m.FocusedIndex = (m.FocusedIndex + 1) % len(m.Items)
	m.Selected = false
	audio.Play(audio.SoundMove)
}
Example #9
0
func (s *Selector) moveRight() {
	if s.State == SelectorStatic {
		s.setState(SelectorMovingRight)
		audio.Play(audio.SoundMove)
	}
}
Example #10
0
func (s *Selector) moveDown() {
	if s.State == SelectorStatic && s.Y < s.ringCount-1 {
		s.setState(SelectorMovingDown)
		audio.Play(audio.SoundMove)
	}
}
Example #11
0
func (s *Selector) moveUp() {
	if s.State == SelectorStatic && s.Y > 0 {
		s.setState(SelectorMovingUp)
		audio.Play(audio.SoundMove)
	}
}
Example #12
0
func (b *Board) update() {
	b.numUpdateBlocksCleared = 0

	advance := func(nextState BoardState) {
		if b.step++; b.step >= boardStateSteps[b.State] {
			b.setState(nextState)
		}
	}

	switch b.State {
	case BoardEntering:
		advance(BoardLive)

	case BoardLive:
		b.Selector.update()
		for _, r := range b.Rings {
			for _, c := range r.Cells {
				c.Block.update()
				c.Marker.update()
			}
		}

		// Find droppable blocks before matches to prevent mid-air matches.
		b.dropBlocks()

		b.addNewMatches()
		b.updateMatches()

		// Reset swap IDs for stationary blocks after new matches have been found.
		for _, r := range b.Rings {
			for _, c := range r.Cells {
				if c.Block.State == BlockStatic && c.Block.swapID != 0 {
					c.Block.swapID = 0
				}
			}
		}

		if b.numSpeedBlocksCleared > requiredBlocksCleared {
			if b.speed++; b.speed > maxSpeed {
				b.speed = maxSpeed
			}
			b.numSpeedBlocksCleared = 0
		}

		// Don't rise if there are pending matches.
		if len(b.matches) > 0 {
			return
		}

		// Don't rise if there are blocks with certain states.
		for _, r := range b.Rings {
			for _, c := range r.Cells {
				if !blockStateRiseable[c.Block.State] {
					return
				}
			}
		}

		// Reset the chain links since we are rising again.
		b.chainLinks = nil

		// Reset dropping flag since we are rising again.
		for _, r := range b.Rings {
			for _, c := range r.Cells {
				if c.Block.Dropping {
					c.Block.Dropping = false
					audio.Play(audio.SoundThud)
				}
			}
		}

		// Determine the rise rate.
		var riseRate float32
		if b.useManualRiseRate {
			riseRate = manualRiseRate
		} else {
			riseRate = minRiseRate + riseRateDelta*float32(b.speed)
		}

		if b.Y += riseRate; b.Y > 1 {
			// Check that topmost ring is empty, so that it can be removed.
			for _, c := range b.Rings[0].Cells {
				if c.Block.State != BlockCleared {
					b.setState(BoardGameOver)
					return
				}
			}

			b.Y = 0

			// Trim off the topmost ring and add a new spare ring.
			b.Rings = append(b.Rings[1:], b.SpareRings[0])

			// Add a new spare ring, since one was taken away.
			b.SpareRings = append(b.SpareRings[1:], newRing(b.CellCount, b.numBlockColors, false))

			// Adjust the selector down in case it was at the removed top ring.
			if b.Selector.Y--; b.Selector.Y < 0 {
				b.Selector.Y = 0
			}
		}

	case BoardGameOver:
		b.step++

	case BoardExiting:
		b.step++
	}
}
Example #13
0
func (g *Game) KeyCallback(key glfw.Key, action glfw.Action) {
	if action != glfw.Press && action != glfw.Repeat {
		// Handle any release triggers.
		if key == glfw.KeyLeftAlt {
			g.Board.useManualRiseRate = false
		}
		return
	}

	if g.StateProgress(0) < 1 {
		return
	}

	switch g.State {
	case GamePlaying:
		switch key {
		case glfw.KeyLeft:
			g.Board.moveLeft()

		case glfw.KeyRight:
			g.Board.moveRight()

		case glfw.KeyDown:
			g.Board.moveDown()

		case glfw.KeyUp:
			g.Board.moveUp()

		case glfw.KeySpace:
			g.Board.swap()

		case glfw.KeyLeftAlt:
			g.Board.useManualRiseRate = true

		case glfw.KeyEscape:
			g.setState(GamePaused)
			g.Menu = pausedMenu
			g.Menu.reset()
			audio.Play(audio.SoundSelect)
		}

	case GameInitial, GamePaused:
		switch key {
		case glfw.KeyLeft:
			g.Menu.moveLeft()

		case glfw.KeyRight:
			g.Menu.moveRight()

		case glfw.KeyDown:
			g.Menu.moveDown()

		case glfw.KeyUp:
			g.Menu.moveUp()

		case glfw.KeyEnter, glfw.KeySpace:
			switch g.Menu.focused() {
			case MenuNewGameItem:
				g.Menu.selectItem()
				g.Menu = newGameMenu
				g.Menu.reset()

			case MenuExit:
				g.Menu.selectItem()
				g.setState(GameExiting)

			case MenuOK:
				g.Menu.selectItem()
				g.setState(GamePlaying)

				var numBlockColors int
				switch difficultyItem.Selector.Value() {
				case MenuEasy:
					numBlockColors = maxBlockColors - 2

				case MenuMedium:
					numBlockColors = maxBlockColors - 1

				default:
					numBlockColors = maxBlockColors
				}

				speed := speedItem.Slider.Value

				b := newBoard(numBlockColors, speed)
				h := newHUD(speed)
				if g.Board == nil {
					g.Board = b
					g.HUD = h
				} else {
					g.nextBoard = b
					g.nextHUD = h
					g.Board.exit()
				}

			case MenuContinueGame:
				g.Menu.selectItem()
				g.setState(GamePlaying)

			case MenuQuit:
				g.Menu.selectItem()
				g.Menu = mainMenu
				g.Menu.reset()
			}

		case glfw.KeyEscape:
			switch g.State {
			case GamePaused:
				g.setState(GamePlaying)
				audio.Play(audio.SoundSelect)
			}
		}
	}
}