Initial commit
This commit is contained in:
commit
d22fa6e189
|
@ -0,0 +1,21 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/gen2brain/raylib-go/raylib"
|
||||
|
||||
"gitea.theedgeofrage.com/theedgeofrage/yeetris/game"
|
||||
)
|
||||
|
||||
func main() {
|
||||
game := game.Game{}
|
||||
game.Init()
|
||||
|
||||
rl.SetTargetFPS(60)
|
||||
|
||||
for !rl.WindowShouldClose() {
|
||||
game.Update()
|
||||
game.Draw()
|
||||
}
|
||||
|
||||
rl.CloseWindow()
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package elements
|
||||
|
||||
import "github.com/gen2brain/raylib-go/raylib"
|
||||
|
||||
type Block struct {
|
||||
Position rl.Vector2
|
||||
Color rl.Color
|
||||
LongBoi bool
|
||||
}
|
||||
|
||||
func (b *Block) Draw(piecePosition rl.Vector2, scale rl.Vector2, offset rl.Vector2) {
|
||||
basePos := rl.Vector2Add(b.Position, piecePosition)
|
||||
if basePos.Y < 0 {
|
||||
return
|
||||
}
|
||||
pos := rl.Vector2Add(rl.Vector2Multiply(basePos, scale), offset)
|
||||
rl.DrawRectangleV(pos, scale, b.Color)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package elements
|
||||
|
||||
import "github.com/gen2brain/raylib-go/raylib"
|
||||
|
||||
var (
|
||||
Red = rl.GetColor(0xcc241dff)
|
||||
Blue = rl.GetColor(0x458588ff)
|
||||
Green = rl.GetColor(0x98971aff)
|
||||
Yellow = rl.GetColor(0xfabd2fff)
|
||||
Purple = rl.GetColor(0xb16286ff)
|
||||
Orange = rl.GetColor(0xd65d0eff)
|
||||
Cyan = rl.GetColor(0x689d6aff)
|
||||
Black = rl.GetColor(0x282828ff)
|
||||
Gray = rl.GetColor(0x928374ff)
|
||||
LightGray = rl.GetColor(0xa89984ff)
|
||||
White = rl.GetColor(0xebdbb2ff)
|
||||
)
|
|
@ -0,0 +1,74 @@
|
|||
package elements
|
||||
|
||||
import (
|
||||
"github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
type Piece struct {
|
||||
Blocks []*Block
|
||||
}
|
||||
|
||||
var Pieces = []*Piece{
|
||||
{
|
||||
Blocks: []*Block{
|
||||
{rl.NewVector2(-1, 0), Cyan, false},
|
||||
{rl.NewVector2(0, 0), Cyan, false},
|
||||
{rl.NewVector2(1, 0), Cyan, true},
|
||||
{rl.NewVector2(2, 0), Cyan, false},
|
||||
},
|
||||
},
|
||||
{
|
||||
Blocks: []*Block{
|
||||
{rl.NewVector2(-1, 0), Blue, false},
|
||||
{rl.NewVector2(-1, -1), Blue, false},
|
||||
{rl.NewVector2(0, 0), Blue, false},
|
||||
{rl.NewVector2(1, 0), Blue, false},
|
||||
},
|
||||
},
|
||||
{
|
||||
Blocks: []*Block{
|
||||
{rl.NewVector2(-1, 0), Orange, false},
|
||||
{rl.NewVector2(0, 0), Orange, false},
|
||||
{rl.NewVector2(1, 0), Orange, false},
|
||||
{rl.NewVector2(1, -1), Orange, false},
|
||||
},
|
||||
},
|
||||
{
|
||||
Blocks: []*Block{
|
||||
{rl.NewVector2(-1, 0), Purple, false},
|
||||
{rl.NewVector2(0, 0), Purple, false},
|
||||
{rl.NewVector2(1, 0), Purple, false},
|
||||
{rl.NewVector2(0, -1), Purple, false},
|
||||
},
|
||||
},
|
||||
{
|
||||
Blocks: []*Block{
|
||||
{rl.NewVector2(-1, -1), Red, false},
|
||||
{rl.NewVector2(0, -1), Red, false},
|
||||
{rl.NewVector2(0, 0), Red, false},
|
||||
{rl.NewVector2(1, 0), Red, false},
|
||||
},
|
||||
},
|
||||
{
|
||||
Blocks: []*Block{
|
||||
{rl.NewVector2(-1, 0), Green, false},
|
||||
{rl.NewVector2(0, 0), Green, false},
|
||||
{rl.NewVector2(0, -1), Green, false},
|
||||
{rl.NewVector2(1, -1), Green, false},
|
||||
},
|
||||
},
|
||||
{
|
||||
Blocks: []*Block{
|
||||
{rl.NewVector2(0, -1), Yellow, false},
|
||||
{rl.NewVector2(1, -1), Yellow, false},
|
||||
{rl.NewVector2(0, 0), Yellow, false},
|
||||
{rl.NewVector2(1, 0), Yellow, false},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func (p *Piece) Draw(pos rl.Vector2, scale rl.Vector2, offset rl.Vector2) {
|
||||
for _, block := range p.Blocks {
|
||||
block.Draw(pos, scale, offset)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
package game
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"gitea.theedgeofrage.com/theedgeofrage/yeetris/elements"
|
||||
"github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
type Board interface {
|
||||
DescendActivePiece() bool
|
||||
DropActivePiece() bool
|
||||
MoveActivePiece(direction int)
|
||||
RotateActivePiece(clockwise bool)
|
||||
ClearLines()
|
||||
Draw(offset, scale rl.Vector2)
|
||||
}
|
||||
|
||||
type board struct {
|
||||
Board [10][20]*elements.Block
|
||||
|
||||
ActivePiece *elements.Piece
|
||||
ActivePiecePos rl.Vector2
|
||||
NextPiece *elements.Piece
|
||||
}
|
||||
|
||||
var _ Board = (*board)(nil)
|
||||
|
||||
func InitBoard() *board {
|
||||
board := &board{}
|
||||
board.newActivePiece()
|
||||
|
||||
return board
|
||||
}
|
||||
|
||||
func (b *board) newActivePiece() bool {
|
||||
b.ActivePiecePos = rl.NewVector2(5, 0)
|
||||
b.ActivePiece = elements.Pieces[rl.GetRandomValue(0, int32(len(elements.Pieces)-1))]
|
||||
for _, block := range b.ActivePiece.Blocks {
|
||||
newX, newY := b.ActivePiecePos.X+block.Position.X, b.ActivePiecePos.Y+block.Position.Y
|
||||
if newY >= 0 && b.Board[int(newX)][int(newY)] != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *board) setBlocksFromActivePiece() {
|
||||
for _, block := range b.ActivePiece.Blocks {
|
||||
newX, newY := b.ActivePiecePos.X+block.Position.X, b.ActivePiecePos.Y+block.Position.Y
|
||||
b.Board[int(newX)][int(newY)] = &elements.Block{
|
||||
Position: rl.NewVector2(newX, newY),
|
||||
Color: b.ActivePiece.Blocks[0].Color,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *board) checkHorizontalCollision(left bool) bool {
|
||||
for _, activeBlock := range b.ActivePiece.Blocks {
|
||||
xPos := int(b.ActivePiecePos.X + activeBlock.Position.X)
|
||||
yPos := int(b.ActivePiecePos.Y + activeBlock.Position.Y)
|
||||
if left {
|
||||
if xPos == 0 {
|
||||
return true
|
||||
}
|
||||
if yPos >= 0 && b.Board[xPos-1][yPos] != nil {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if xPos == 9 {
|
||||
return true
|
||||
}
|
||||
if yPos >= 0 && b.Board[xPos+1][yPos] != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *board) descendActivePiece() bool {
|
||||
b.ActivePiecePos.Y += 1
|
||||
for _, activeBlock := range b.ActivePiece.Blocks {
|
||||
if b.ActivePiecePos.Y+activeBlock.Position.Y == 20 {
|
||||
b.ActivePiecePos.Y -= 1
|
||||
b.setBlocksFromActivePiece()
|
||||
return true
|
||||
}
|
||||
|
||||
if b.Board[int(b.ActivePiecePos.X+activeBlock.Position.X)][int(b.ActivePiecePos.Y+activeBlock.Position.Y)] != nil {
|
||||
b.ActivePiecePos.Y -= 1
|
||||
b.setBlocksFromActivePiece()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (b *board) DescendActivePiece() bool {
|
||||
if b.descendActivePiece() {
|
||||
return b.newActivePiece()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (b *board) DropActivePiece() bool {
|
||||
for !b.descendActivePiece() {
|
||||
}
|
||||
return b.newActivePiece()
|
||||
}
|
||||
|
||||
// MoveActivePiece moves the piece left or right. If the piece cannot move in the specified direction, nothing happens.
|
||||
func (b *board) MoveActivePiece(direction int) {
|
||||
if !b.checkHorizontalCollision(direction == -1) {
|
||||
b.ActivePiecePos.X += float32(direction)
|
||||
}
|
||||
}
|
||||
|
||||
func getCollisionDepth(collisionDepth int, longBoi bool) int {
|
||||
if longBoi || collisionDepth == 2 {
|
||||
return 2
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// RotateActivePiece rotates the piece clockwise or counter-clockwise. If the piece cannot rotate in the specified
|
||||
// direction, nothing happens.
|
||||
func (b *board) RotateActivePiece(clockwise bool) {
|
||||
if b.ActivePiece.Blocks[0].Color == elements.Yellow {
|
||||
return
|
||||
}
|
||||
|
||||
angle := rl.Deg2rad * 90
|
||||
if !clockwise {
|
||||
angle = -angle
|
||||
}
|
||||
|
||||
tmpPiece := &elements.Piece{
|
||||
Blocks: make([]*elements.Block, 4),
|
||||
}
|
||||
for i := 0; i < 4; i++ {
|
||||
newPos := rl.Vector2Rotate(b.ActivePiece.Blocks[i].Position, float32(angle))
|
||||
newPos.X = float32(math.Round(float64(newPos.X)))
|
||||
newPos.Y = float32(math.Round(float64(newPos.Y)))
|
||||
tmpPiece.Blocks[i] = &elements.Block{
|
||||
Position: newPos,
|
||||
Color: b.ActivePiece.Blocks[i].Color,
|
||||
LongBoi: b.ActivePiece.Blocks[i].LongBoi,
|
||||
}
|
||||
}
|
||||
collisionLeft := 0
|
||||
collisionRight := 0
|
||||
collisionBottom := 0
|
||||
for _, block := range tmpPiece.Blocks {
|
||||
newX, newY := b.ActivePiecePos.X+block.Position.X, b.ActivePiecePos.Y+block.Position.Y
|
||||
if newY < 0 {
|
||||
continue
|
||||
}
|
||||
if newX < 0 && collisionLeft == 0 {
|
||||
collisionLeft = getCollisionDepth(collisionLeft, block.LongBoi)
|
||||
}
|
||||
if newX > 9 && collisionRight == 0 {
|
||||
collisionRight = getCollisionDepth(collisionRight, block.LongBoi)
|
||||
}
|
||||
if newY > 19 && collisionBottom == 0 {
|
||||
collisionBottom = getCollisionDepth(collisionBottom, block.LongBoi)
|
||||
}
|
||||
if collisionLeft != 0 || collisionRight != 0 || collisionBottom != 0 {
|
||||
continue
|
||||
}
|
||||
if b.Board[int(newX)][int(newY)] != nil {
|
||||
if newX < b.ActivePiecePos.X && collisionLeft == 0 {
|
||||
collisionLeft = getCollisionDepth(collisionLeft, block.LongBoi)
|
||||
}
|
||||
if newX > b.ActivePiecePos.X && collisionRight == 0 {
|
||||
collisionRight = getCollisionDepth(collisionRight, block.LongBoi)
|
||||
}
|
||||
if newY > b.ActivePiecePos.Y && collisionBottom == 0 {
|
||||
collisionBottom = getCollisionDepth(collisionBottom, block.LongBoi)
|
||||
}
|
||||
}
|
||||
}
|
||||
if collisionLeft != 0 && collisionRight != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
b.ActivePiecePos.Y -= float32(collisionBottom)
|
||||
b.ActivePiecePos.X += float32(collisionLeft)
|
||||
b.ActivePiecePos.X -= float32(collisionRight)
|
||||
b.ActivePiece = tmpPiece
|
||||
}
|
||||
|
||||
// ClearLines clears all lines that are completely filled.
|
||||
func (g *board) ClearLines() {
|
||||
for y := 19; y >= 0; {
|
||||
skip := false
|
||||
for x := 0; x < 10; x++ {
|
||||
if g.Board[x][y] == nil {
|
||||
skip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if skip {
|
||||
y--
|
||||
continue
|
||||
}
|
||||
for ty := y; ty > 0; ty-- {
|
||||
for x := 0; x < 10; x++ {
|
||||
if g.Board[x][ty-1] != nil {
|
||||
g.Board[x][ty] = g.Board[x][ty-1]
|
||||
g.Board[x][ty].Position.Y++
|
||||
} else {
|
||||
g.Board[x][ty] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
for x := 0; x < 10; x++ {
|
||||
g.Board[x][0] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *board) drawGrid(offset, scale rl.Vector2) {
|
||||
for i := 0; i < 10; i++ {
|
||||
rl.DrawLine(
|
||||
int32(scale.X*float32(i)+offset.X),
|
||||
int32(offset.Y),
|
||||
int32(scale.X*float32(i)+offset.X),
|
||||
int32(20*scale.Y+offset.Y),
|
||||
elements.Gray,
|
||||
)
|
||||
}
|
||||
for i := 0; i < 20; i++ {
|
||||
rl.DrawLine(
|
||||
int32(offset.X),
|
||||
int32(scale.Y*float32(i)+offset.Y),
|
||||
int32(10*scale.X+offset.X),
|
||||
int32(scale.Y*float32(i)+offset.Y),
|
||||
elements.Gray,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Draw draws the board with placed blocks and the active piece.
|
||||
func (b *board) Draw(offset rl.Vector2, scale rl.Vector2) {
|
||||
b.drawGrid(offset, scale)
|
||||
for i := 0; i < 20; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
if b.Board[j][i] == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
b.Board[j][i].Draw(rl.NewVector2(0, 0), scale, offset)
|
||||
}
|
||||
}
|
||||
b.ActivePiece.Draw(b.ActivePiecePos, scale, offset)
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package game
|
||||
|
||||
import (
|
||||
"gitea.theedgeofrage.com/theedgeofrage/yeetris/elements"
|
||||
"github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
const DEBUG = false
|
||||
|
||||
// Game type
|
||||
type Game struct {
|
||||
FramesCounter int32
|
||||
TickRate int32
|
||||
GameOver bool
|
||||
Pause bool
|
||||
|
||||
Scale rl.Vector2
|
||||
|
||||
Board Board
|
||||
UI *UI
|
||||
}
|
||||
|
||||
// Init - Initialize game
|
||||
func (g *Game) Init() {
|
||||
g.Scale = rl.NewVector2(40, 40)
|
||||
|
||||
g.FramesCounter = 0
|
||||
g.TickRate = 30
|
||||
g.GameOver = false
|
||||
g.Pause = false
|
||||
g.Board = InitBoard()
|
||||
g.UI = InitUI(g.Scale)
|
||||
}
|
||||
|
||||
func (g *Game) Update() {
|
||||
defer g.Board.ClearLines()
|
||||
if g.GameOver {
|
||||
if rl.IsKeyPressed(rl.KeyEnter) {
|
||||
g.Init()
|
||||
g.GameOver = false
|
||||
}
|
||||
return
|
||||
}
|
||||
if rl.IsKeyPressed(rl.KeyP) {
|
||||
g.Pause = !g.Pause
|
||||
}
|
||||
|
||||
if g.Pause {
|
||||
return
|
||||
}
|
||||
|
||||
if rl.IsKeyPressed(rl.KeyI) {
|
||||
g.Board.MoveActivePiece(1)
|
||||
}
|
||||
if rl.IsKeyPressed(rl.KeyH) {
|
||||
g.Board.MoveActivePiece(-1)
|
||||
}
|
||||
if rl.IsKeyPressed(rl.KeyE) {
|
||||
g.Board.RotateActivePiece(true)
|
||||
}
|
||||
if rl.IsKeyPressed(rl.KeyN) {
|
||||
g.Board.DescendActivePiece()
|
||||
}
|
||||
if rl.IsKeyPressed(rl.KeySpace) {
|
||||
g.Board.DropActivePiece()
|
||||
}
|
||||
if g.FramesCounter%g.TickRate == 0 && !DEBUG {
|
||||
g.Board.DescendActivePiece()
|
||||
}
|
||||
g.FramesCounter++
|
||||
}
|
||||
|
||||
func (g *Game) Draw() {
|
||||
rl.BeginDrawing()
|
||||
rl.ClearBackground(elements.Black)
|
||||
|
||||
g.UI.Draw(g)
|
||||
|
||||
if !g.GameOver {
|
||||
g.Board.Draw(g.UI.BoardOffset, g.Scale)
|
||||
} else {
|
||||
rl.DrawText(
|
||||
"PRESS [ENTER] TO PLAY AGAIN",
|
||||
int32(rl.GetScreenWidth())/2-rl.MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2,
|
||||
int32(rl.GetScreenHeight())/2-50,
|
||||
20,
|
||||
elements.LightGray,
|
||||
)
|
||||
}
|
||||
|
||||
rl.EndDrawing()
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package game
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
|
||||
"gitea.theedgeofrage.com/theedgeofrage/yeetris/elements"
|
||||
"github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
type UI struct {
|
||||
ScreenWidth int32
|
||||
ScreenHeight int32
|
||||
BoardWidth int32
|
||||
BoardHeight int32
|
||||
BoardOffset rl.Vector2
|
||||
UIOffsetWidth int32
|
||||
|
||||
Score int
|
||||
}
|
||||
|
||||
func InitUI(scale rl.Vector2) *UI {
|
||||
boardWidth := 10 * int32(scale.X)
|
||||
boardHeight := 20 * int32(scale.Y)
|
||||
screenWidth := boardWidth + 40 + 300
|
||||
screenHeight := boardHeight + 40
|
||||
rl.InitWindow(screenWidth, screenHeight, "Yeetris")
|
||||
|
||||
return &UI{
|
||||
ScreenWidth: screenWidth,
|
||||
ScreenHeight: screenHeight,
|
||||
BoardWidth: boardWidth,
|
||||
BoardHeight: boardHeight,
|
||||
BoardOffset: rl.NewVector2(20, 20),
|
||||
UIOffsetWidth: boardWidth + 40 + 20,
|
||||
}
|
||||
}
|
||||
|
||||
func drawRectangleBorder(x, y, width, height, border int32, color rl.Color) {
|
||||
rl.DrawRectangle(x-border, y-border, width+2*border, height+2*border, color)
|
||||
rl.DrawRectangle(x, y, width, height, elements.Black)
|
||||
}
|
||||
|
||||
func (u *UI) Draw(g *Game) {
|
||||
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)
|
||||
|
||||
if g.Pause {
|
||||
rl.DrawText(
|
||||
"GAME PAUSED",
|
||||
u.ScreenWidth/2-rl.MeasureText("GAME PAUSED", 40)/2,
|
||||
u.ScreenHeight/2-40,
|
||||
40,
|
||||
elements.LightGray,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
module gitea.theedgeofrage.com/theedgeofrage/yeetris
|
||||
|
||||
go 1.21.6
|
||||
|
||||
require github.com/gen2brain/raylib-go/raylib v0.0.0-20240125111008-83d871a38f28
|
||||
|
||||
require (
|
||||
github.com/ebitengine/purego v0.6.0-alpha.1.0.20231122024802-192c5e846faa // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
github.com/ebitengine/purego v0.6.0-alpha.1.0.20231122024802-192c5e846faa h1:Ik7QikRgeH+bFOfAcMpttCbs6XxWXxCLXMm4awxtOXk=
|
||||
github.com/ebitengine/purego v0.6.0-alpha.1.0.20231122024802-192c5e846faa/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
|
||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20240125111008-83d871a38f28 h1:e0HOaKlvsdC0ZtfWbEaaWAxYTSxUZoCAFS36jLfsVRA=
|
||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20240125111008-83d871a38f28/go.mod h1:P/hDjVwz/9fhR0ww3+umzDpDA7Bf7Tce4xNChHIEFqE=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
Loading…
Reference in New Issue