Implement next and hold

This commit is contained in:
Pavle Portic 2024-01-28 02:16:03 +01:00
parent d22fa6e189
commit 545a76109e
Signed by: TheEdgeOfRage
GPG Key ID: 66AD4BA646FBC0D2
4 changed files with 116 additions and 48 deletions

View File

@ -8,7 +8,7 @@ type Piece struct {
Blocks []*Block Blocks []*Block
} }
var Pieces = []*Piece{ var Pieces = []Piece{
{ {
Blocks: []*Block{ Blocks: []*Block{
{rl.NewVector2(-1, 0), Cyan, false}, {rl.NewVector2(-1, 0), Cyan, false},
@ -67,8 +67,24 @@ var Pieces = []*Piece{
}, },
} }
func (p *Piece) Draw(pos rl.Vector2, scale rl.Vector2, offset rl.Vector2) { func (p Piece) Draw(pos rl.Vector2, scale rl.Vector2, offset rl.Vector2) {
for _, block := range p.Blocks { for _, block := range p.Blocks {
block.Draw(pos, scale, offset) block.Draw(pos, scale, offset)
} }
} }
func GetRandomPiece() *Piece {
base := Pieces[rl.GetRandomValue(0, int32(len(Pieces)-1))]
newPiece := &Piece{
Blocks: make([]*Block, 4),
}
for i, block := range base.Blocks {
newPiece.Blocks[i] = &Block{
Position: block.Position,
Color: block.Color,
LongBoi: block.LongBoi,
}
}
return newPiece
}

View File

@ -7,35 +7,30 @@ import (
"github.com/gen2brain/raylib-go/raylib" "github.com/gen2brain/raylib-go/raylib"
) )
type Board interface { type Board struct {
DescendActivePiece() bool
DropActivePiece() bool
MoveActivePiece(direction int)
RotateActivePiece(clockwise bool)
ClearLines()
Draw(offset, scale rl.Vector2)
}
type board struct {
Board [10][20]*elements.Block Board [10][20]*elements.Block
ActivePiece *elements.Piece ActivePiece *elements.Piece
ActivePiecePos rl.Vector2 ActivePiecePos rl.Vector2
NextPiece *elements.Piece NextPiece *elements.Piece
HeldPiece *elements.Piece
AlreadyHeld bool
} }
var _ Board = (*board)(nil) func InitBoard() *Board {
board := &Board{
func InitBoard() *board { NextPiece: elements.GetRandomPiece(),
board := &board{} }
board.newActivePiece() board.getNextPiece()
return board return board
} }
func (b *board) newActivePiece() bool { func (b *Board) getNextPiece() bool {
b.AlreadyHeld = false
b.ActivePiecePos = rl.NewVector2(5, 0) b.ActivePiecePos = rl.NewVector2(5, 0)
b.ActivePiece = elements.Pieces[rl.GetRandomValue(0, int32(len(elements.Pieces)-1))] b.ActivePiece = b.NextPiece
b.NextPiece = elements.GetRandomPiece()
for _, block := range b.ActivePiece.Blocks { for _, block := range b.ActivePiece.Blocks {
newX, newY := b.ActivePiecePos.X+block.Position.X, b.ActivePiecePos.Y+block.Position.Y newX, newY := b.ActivePiecePos.X+block.Position.X, b.ActivePiecePos.Y+block.Position.Y
if newY >= 0 && b.Board[int(newX)][int(newY)] != nil { if newY >= 0 && b.Board[int(newX)][int(newY)] != nil {
@ -45,7 +40,7 @@ func (b *board) newActivePiece() bool {
return false return false
} }
func (b *board) setBlocksFromActivePiece() { func (b *Board) setBlocksFromActivePiece() {
for _, block := range b.ActivePiece.Blocks { for _, block := range b.ActivePiece.Blocks {
newX, newY := b.ActivePiecePos.X+block.Position.X, b.ActivePiecePos.Y+block.Position.Y newX, newY := b.ActivePiecePos.X+block.Position.X, b.ActivePiecePos.Y+block.Position.Y
b.Board[int(newX)][int(newY)] = &elements.Block{ b.Board[int(newX)][int(newY)] = &elements.Block{
@ -55,7 +50,7 @@ func (b *board) setBlocksFromActivePiece() {
} }
} }
func (b *board) checkHorizontalCollision(left bool) bool { func (b *Board) checkHorizontalCollision(left bool) bool {
for _, activeBlock := range b.ActivePiece.Blocks { for _, activeBlock := range b.ActivePiece.Blocks {
xPos := int(b.ActivePiecePos.X + activeBlock.Position.X) xPos := int(b.ActivePiecePos.X + activeBlock.Position.X)
yPos := int(b.ActivePiecePos.Y + activeBlock.Position.Y) yPos := int(b.ActivePiecePos.Y + activeBlock.Position.Y)
@ -78,7 +73,7 @@ func (b *board) checkHorizontalCollision(left bool) bool {
return false return false
} }
func (b *board) descendActivePiece() bool { func (b *Board) descendActivePiece() bool {
b.ActivePiecePos.Y += 1 b.ActivePiecePos.Y += 1
for _, activeBlock := range b.ActivePiece.Blocks { for _, activeBlock := range b.ActivePiece.Blocks {
if b.ActivePiecePos.Y+activeBlock.Position.Y == 20 { if b.ActivePiecePos.Y+activeBlock.Position.Y == 20 {
@ -98,23 +93,23 @@ func (b *board) descendActivePiece() bool {
// DescendActivePiece moves the piece down by one block. If the piece cannot move down, it will be placed on the board. // DescendActivePiece moves the piece down by one block. If the piece cannot move down, it will be placed on the board.
// After that, a new piece will be generated. If the new piece cannot be placed, true is returned. // After that, a new piece will be generated. If the new piece cannot be placed, true is returned.
func (b *board) DescendActivePiece() bool { func (b *Board) DescendActivePiece() bool {
if b.descendActivePiece() { if b.descendActivePiece() {
return b.newActivePiece() return b.getNextPiece()
} }
return false return false
} }
// DropActivePiece moves the piece down until it cannot move down anymore. After that, a new piece will be generated. // DropActivePiece moves the piece down until it cannot move down anymore. After that, a new piece will be generated.
// If the new piece cannot be placed, true is returned. // If the new piece cannot be placed, true is returned.
func (b *board) DropActivePiece() bool { func (b *Board) DropActivePiece() bool {
for !b.descendActivePiece() { for !b.descendActivePiece() {
} }
return b.newActivePiece() return b.getNextPiece()
} }
// MoveActivePiece moves the piece left or right. If the piece cannot move in the specified direction, nothing happens. // MoveActivePiece moves the piece left or right. If the piece cannot move in the specified direction, nothing happens.
func (b *board) MoveActivePiece(direction int) { func (b *Board) MoveActivePiece(direction int) {
if !b.checkHorizontalCollision(direction == -1) { if !b.checkHorizontalCollision(direction == -1) {
b.ActivePiecePos.X += float32(direction) b.ActivePiecePos.X += float32(direction)
} }
@ -130,7 +125,7 @@ func getCollisionDepth(collisionDepth int, longBoi bool) int {
// RotateActivePiece rotates the piece clockwise or counter-clockwise. If the piece cannot rotate in the specified // RotateActivePiece rotates the piece clockwise or counter-clockwise. If the piece cannot rotate in the specified
// direction, nothing happens. // direction, nothing happens.
func (b *board) RotateActivePiece(clockwise bool) { func (b *Board) RotateActivePiece(clockwise bool) {
if b.ActivePiece.Blocks[0].Color == elements.Yellow { if b.ActivePiece.Blocks[0].Color == elements.Yellow {
return return
} }
@ -195,8 +190,22 @@ func (b *board) RotateActivePiece(clockwise bool) {
b.ActivePiece = tmpPiece b.ActivePiece = tmpPiece
} }
func (b *Board) HoldPiece() {
if b.AlreadyHeld {
return
}
b.AlreadyHeld = true
if b.HeldPiece == nil {
b.HeldPiece = b.ActivePiece
b.getNextPiece()
return
}
b.HeldPiece, b.ActivePiece = b.ActivePiece, b.HeldPiece
b.ActivePiecePos = rl.NewVector2(5, 0)
}
// ClearLines clears all lines that are completely filled. // ClearLines clears all lines that are completely filled.
func (g *board) ClearLines() { func (g *Board) ClearLines() {
for y := 19; y >= 0; { for y := 19; y >= 0; {
skip := false skip := false
for x := 0; x < 10; x++ { for x := 0; x < 10; x++ {
@ -225,7 +234,7 @@ func (g *board) ClearLines() {
} }
} }
func (b *board) drawGrid(offset, scale rl.Vector2) { func (b *Board) DrawGrid(offset, scale rl.Vector2) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
rl.DrawLine( rl.DrawLine(
int32(scale.X*float32(i)+offset.X), int32(scale.X*float32(i)+offset.X),
@ -246,9 +255,38 @@ func (b *board) drawGrid(offset, scale rl.Vector2) {
} }
} }
// Draw draws the board with placed blocks and the active piece. func (b *Board) drawUIPiece(piece *elements.Piece, position, scale rl.Vector2) {
func (b *board) Draw(offset rl.Vector2, scale rl.Vector2) { centerOffset := rl.NewVector2(0, 0)
b.drawGrid(offset, scale) for _, block := range piece.Blocks {
centerOffset = rl.Vector2Add(
centerOffset,
rl.Vector2Add(block.Position, rl.NewVector2(0.5, 0.5)),
)
}
centerOffset = rl.Vector2Divide(centerOffset, rl.NewVector2(4, 4))
centerOffset = rl.Vector2Add(centerOffset, rl.NewVector2(0, 1))
centerOffset = rl.Vector2Multiply(centerOffset, scale)
for _, block := range piece.Blocks {
block.Draw(rl.NewVector2(0, 1), scale, rl.Vector2Subtract(position, centerOffset))
}
}
// DrawNextPiece draws the next piece in the UI at the specified position.
func (b *Board) DrawNextPiece(position, scale rl.Vector2) {
b.drawUIPiece(b.NextPiece, position, scale)
}
// DrawHeldPiece draws the held piece in the UI at the specified position.
func (b *Board) DrawHeldPiece(position, scale rl.Vector2) {
if b.HeldPiece == nil {
return
}
b.drawUIPiece(b.HeldPiece, position, scale)
}
// DrawBoard draws the board with placed blocks and the active piece.
func (b *Board) DrawBoard(offset rl.Vector2, scale rl.Vector2) {
// b.DrawGrid(offset, scale)
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
for j := 0; j < 10; j++ { for j := 0; j < 10; j++ {
if b.Board[j][i] == nil { if b.Board[j][i] == nil {

View File

@ -16,7 +16,7 @@ type Game struct {
Scale rl.Vector2 Scale rl.Vector2
Board Board Board *Board
UI *UI UI *UI
} }
@ -49,6 +49,9 @@ func (g *Game) Update() {
return return
} }
if rl.IsKeyPressed(rl.KeyC) {
g.Board.HoldPiece()
}
if rl.IsKeyPressed(rl.KeyI) { if rl.IsKeyPressed(rl.KeyI) {
g.Board.MoveActivePiece(1) g.Board.MoveActivePiece(1)
} }
@ -77,7 +80,9 @@ func (g *Game) Draw() {
g.UI.Draw(g) g.UI.Draw(g)
if !g.GameOver { if !g.GameOver {
g.Board.Draw(g.UI.BoardOffset, g.Scale) g.Board.DrawBoard(g.UI.BoardOffset, g.Scale)
g.Board.DrawNextPiece(g.UI.NextPiecePosition, g.Scale)
g.Board.DrawHeldPiece(g.UI.HeldPiecePosition, g.Scale)
} else { } else {
rl.DrawText( rl.DrawText(
"PRESS [ENTER] TO PLAY AGAIN", "PRESS [ENTER] TO PLAY AGAIN",

View File

@ -1,19 +1,21 @@
package game package game
import ( import (
// "fmt" "fmt"
"gitea.theedgeofrage.com/theedgeofrage/yeetris/elements" "gitea.theedgeofrage.com/theedgeofrage/yeetris/elements"
"github.com/gen2brain/raylib-go/raylib" "github.com/gen2brain/raylib-go/raylib"
) )
type UI struct { type UI struct {
ScreenWidth int32 ScreenWidth int32
ScreenHeight int32 ScreenHeight int32
BoardWidth int32 BoardWidth int32
BoardHeight int32 BoardHeight int32
BoardOffset rl.Vector2 BoardOffset rl.Vector2
UIOffsetWidth int32 UIOffsetWidth int32
NextPiecePosition rl.Vector2
HeldPiecePosition rl.Vector2
Score int Score int
} }
@ -26,12 +28,14 @@ func InitUI(scale rl.Vector2) *UI {
rl.InitWindow(screenWidth, screenHeight, "Yeetris") rl.InitWindow(screenWidth, screenHeight, "Yeetris")
return &UI{ return &UI{
ScreenWidth: screenWidth, ScreenWidth: screenWidth,
ScreenHeight: screenHeight, ScreenHeight: screenHeight,
BoardWidth: boardWidth, BoardWidth: boardWidth,
BoardHeight: boardHeight, BoardHeight: boardHeight,
BoardOffset: rl.NewVector2(20, 20), BoardOffset: rl.NewVector2(20, 20),
UIOffsetWidth: boardWidth + 40 + 20, UIOffsetWidth: boardWidth + 40 + 20,
NextPiecePosition: rl.NewVector2(float32(boardWidth+40+20+110), 250),
HeldPiecePosition: rl.NewVector2(float32(boardWidth+40+20+110), 510),
} }
} }
@ -43,6 +47,11 @@ func drawRectangleBorder(x, y, width, height, border int32, color rl.Color) {
func (u *UI) Draw(g *Game) { func (u *UI) Draw(g *Game) {
drawRectangleBorder(int32(u.BoardOffset.X), int32(u.BoardOffset.Y), u.BoardWidth, u.BoardHeight, 20, elements.Gray) drawRectangleBorder(int32(u.BoardOffset.X), int32(u.BoardOffset.Y), u.BoardWidth, u.BoardHeight, 20, elements.Gray)
rl.DrawText("Yeetris", u.UIOffsetWidth, 20, 40, rl.White) rl.DrawText("Yeetris", u.UIOffsetWidth, 20, 40, rl.White)
rl.DrawText(fmt.Sprintf("Score: %d", u.Score), u.UIOffsetWidth, 70, 20, rl.White)
rl.DrawText("Next Piece:", u.UIOffsetWidth, 110, 20, rl.White)
drawRectangleBorder(u.UIOffsetWidth+10, 150, 200, 200, 10, elements.Gray)
rl.DrawText("Hold:", u.UIOffsetWidth, 370, 20, rl.White)
drawRectangleBorder(u.UIOffsetWidth+10, 410, 200, 200, 10, elements.Gray)
if g.Pause { if g.Pause {
rl.DrawText( rl.DrawText(