添加退出机制,修复游戏结束重新开始按键绑定问题,修复游戏结束时显示文字的问题

main v1.0.4
huyinsong 7 days ago
parent c1ca21bdba
commit 9a8acbe126
  1. 184
      internal/game/game.go

@ -4,6 +4,7 @@ import (
"fmt"
"image/color"
"math/rand"
"os"
"time"
"tetris/internal/font"
@ -19,27 +20,33 @@ import (
// Game represents the main game state
type Game struct {
board [][]types.BlockType
currentPiece *tetromino.Tetromino
nextPiece *tetromino.Tetromino
dropCounter int
dropInterval int
score int
level int
gameOver bool
lastMoveDown time.Time
lastRotate time.Time
fontRenderer *font.FontRenderer
board [][]types.BlockType
currentPiece *tetromino.Tetromino
nextPiece *tetromino.Tetromino
dropCounter int
dropInterval int
score int
level int
gameOver bool
lastMoveDown time.Time
lastRotate time.Time
lastMoveLeft time.Time
lastMoveRight time.Time
fontRenderer *font.FontRenderer
hardDropping bool
hardDropCounter int
}
// New creates a new game instance
func New() *Game {
g := &Game{
board: make([][]types.BlockType, config.BoardHeight),
dropInterval: config.InitialDropInterval,
lastMoveDown: time.Now(),
lastRotate: time.Now(),
fontRenderer: font.NewFontRenderer(),
board: make([][]types.BlockType, config.BoardHeight),
dropInterval: config.InitialDropInterval,
lastMoveDown: time.Now(),
lastRotate: time.Now(),
lastMoveLeft: time.Now(),
lastMoveRight: time.Now(),
fontRenderer: font.NewFontRenderer(),
}
for i := range g.board {
@ -53,7 +60,7 @@ func New() *Game {
// Update handles game logic updates
func (g *Game) Update() error {
if g.gameOver {
if inpututil.IsKeyJustPressed(ebiten.KeySpace) {
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
*g = *New()
return nil
}
@ -114,10 +121,14 @@ func (g *Game) Draw(screen *ebiten.Image) {
}
}
// Draw actual piece
// Draw actual piece with special effect during hard drop
for _, pos := range g.currentPiece.GetAbsolutePositions() {
if pos[1] >= 0 {
g.drawBlock(screen, pos[0], pos[1], g.currentPiece.BlockType)
if g.hardDropping {
g.drawHardDropBlock(screen, pos[0], pos[1], g.currentPiece.BlockType)
} else {
g.drawBlock(screen, pos[0], pos[1], g.currentPiece.BlockType)
}
}
}
}
@ -151,8 +162,8 @@ func (g *Game) Draw(screen *ebiten.Image) {
if g.gameOver {
text := i18n.GetText()
g.fontRenderer.DrawText(screen, text.GameOver, float64(config.PreviewX-config.BlockSize), float64(config.ScreenHeight/2), color.RGBA{255, 255, 255, 255})
g.fontRenderer.DrawText(screen, text.Restart, float64(config.PreviewX-config.BlockSize), float64(config.ScreenHeight/2+20), color.RGBA{255, 255, 255, 255})
g.fontRenderer.DrawText(screen, text.GameOver, float64(config.ScreenWidth/2-20), float64(config.ScreenHeight/2-100), color.RGBA{255, 255, 255, 255})
g.fontRenderer.DrawText(screen, text.Restart, float64(config.ScreenWidth/2-20), float64(config.ScreenHeight/2-80), color.RGBA{255, 0, 0, 255})
}
}
@ -168,8 +179,8 @@ func (g *Game) handleInput() {
i18n.SwitchLanguage()
}
// Restart game when game over
if g.gameOver && inpututil.IsKeyJustPressed(ebiten.KeyR) {
// Restart game anytime
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
g.restart()
return
}
@ -179,12 +190,37 @@ func (g *Game) handleInput() {
return
}
// Move left/right
if inpututil.IsKeyJustPressed(ebiten.KeyLeft) {
g.tryMove(-1, 0)
// Hard drop
if inpututil.IsKeyJustPressed(ebiten.KeySpace) {
g.hardDrop()
}
if inpututil.IsKeyJustPressed(ebiten.KeyRight) {
g.tryMove(1, 0)
// Skip movement inputs during hard drop animation
if g.hardDropping {
return
}
// Move left/right - support continuous movement when holding keys
if ebiten.IsKeyPressed(ebiten.KeyLeft) {
// First press moves immediately, then add delay for continuous movement
if inpututil.IsKeyJustPressed(ebiten.KeyLeft) {
g.tryMove(-1, 0)
g.lastMoveLeft = time.Now()
} else if time.Since(g.lastMoveLeft) > time.Millisecond*120 {
g.tryMove(-1, 0)
g.lastMoveLeft = time.Now()
}
}
if ebiten.IsKeyPressed(ebiten.KeyRight) {
// First press moves immediately, then add delay for continuous movement
if inpututil.IsKeyJustPressed(ebiten.KeyRight) {
g.tryMove(1, 0)
g.lastMoveRight = time.Now()
} else if time.Since(g.lastMoveRight) > time.Millisecond*120 {
g.tryMove(1, 0)
g.lastMoveRight = time.Now()
}
}
// Rotate
@ -202,20 +238,32 @@ func (g *Game) handleInput() {
g.lastMoveDown = time.Now()
}
}
// Hard drop
if inpututil.IsKeyJustPressed(ebiten.KeySpace) {
g.hardDrop()
// Exit game
if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
os.Exit(0)
}
}
// updateDropCounter handles automatic piece dropping
// updateDropCounter handles automatic piece dropping and hard drop animation
func (g *Game) updateDropCounter() {
g.dropCounter++
if g.dropCounter >= g.dropInterval {
g.dropCounter = 0
if !g.tryMove(0, 1) {
g.lockPiece()
if g.hardDropping {
// Hard drop animation - move faster
g.hardDropCounter++
if g.hardDropCounter >= 2 { // Move every 2 frames for visible animation
g.hardDropCounter = 0
if !g.tryMove(0, 1) {
g.hardDropping = false
g.lockPiece()
}
}
} else {
// Normal drop
g.dropCounter++
if g.dropCounter >= g.dropInterval {
g.dropCounter = 0
if !g.tryMove(0, 1) {
g.lockPiece()
}
}
}
}
@ -275,24 +323,14 @@ func (g *Game) tryRotate() bool {
return false
}
// hardDrop drops the piece instantly to the bottom
// hardDrop starts the hard drop animation
func (g *Game) hardDrop() {
if g.currentPiece == nil {
if g.currentPiece == nil || g.hardDropping {
return
}
dropDistance := 0
for {
if !g.tryMove(0, 1) {
break
}
dropDistance++
}
// Award extra points for hard drop
g.score += dropDistance * 2
g.lockPiece()
g.hardDropping = true
g.hardDropCounter = 0
}
// isColliding checks if the current piece is colliding with the board or boundaries
@ -454,6 +492,40 @@ func (g *Game) drawBlock(screen *ebiten.Image, x, y int, blockType types.BlockTy
borderColor, false)
}
// drawHardDropBlock draws a block with special hard drop effect
func (g *Game) drawHardDropBlock(screen *ebiten.Image, x, y int, blockType types.BlockType) {
// Get original color and make it brighter for hard drop effect
originalColor := types.BlockColors[blockType].(color.RGBA)
hardDropColor := color.RGBA{
min(255, originalColor.R+50),
min(255, originalColor.G+50),
min(255, originalColor.B+50),
255,
}
vector.DrawFilledRect(screen,
float32(x*config.BlockSize),
float32(y*config.BlockSize),
float32(config.BlockSize-1),
float32(config.BlockSize-1),
hardDropColor, false)
// Add bright white border for hard drop effect
borderColor := color.RGBA{255, 255, 255, 200}
vector.DrawFilledRect(screen,
float32(x*config.BlockSize),
float32(y*config.BlockSize),
float32(config.BlockSize-1),
3,
borderColor, false)
vector.DrawFilledRect(screen,
float32(x*config.BlockSize),
float32(y*config.BlockSize),
3,
float32(config.BlockSize-1),
borderColor, false)
}
// max returns the maximum of two integers
func max(a, b int) int {
if a > b {
@ -462,6 +534,14 @@ func max(a, b int) int {
return b
}
// min returns the minimum of two uint8 values
func min(a, b uint8) uint8 {
if a < b {
return a
}
return b
}
// drawControls renders the control instructions on the right side of the screen
func (g *Game) drawControls(screen *ebiten.Image) {
// Starting position for controls display

Loading…
Cancel
Save