From 941c24e9fd7d49a0b92f6ca90de080fa572ab645 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 31 Jul 2016 17:25:39 +0900 Subject: [PATCH] examples/2048: Pop animation --- examples/2048/2048/board.go | 14 ++++-- examples/2048/2048/tile.go | 77 ++++++++++++++++++++++----------- examples/2048/2048/tile_test.go | 2 +- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/examples/2048/2048/board.go b/examples/2048/2048/board.go index 617558483..395fc48dc 100644 --- a/examples/2048/2048/board.go +++ b/examples/2048/2048/board.go @@ -75,7 +75,7 @@ func (b *Board) Move(dir Dir) error { } b.tasks = append(b.tasks, func() error { for t := range b.tiles { - if t.IsAnimating() { + if t.IsMoving() { return nil } } @@ -84,7 +84,7 @@ func (b *Board) Move(dir Dir) error { b.tasks = append(b.tasks, func() error { nextTiles := map[*Tile]struct{}{} for t := range b.tiles { - if t.IsAnimating() { + if t.IsMoving() { panic("not reach") } if t.next.value != 0 { @@ -101,6 +101,14 @@ func (b *Board) Move(dir Dir) error { } return taskTerminated }) + b.tasks = append(b.tasks, func() error { + for t := range b.tiles { + if t.isPopping() { + return nil + } + } + return taskTerminated + }) return nil } @@ -131,7 +139,7 @@ func (b *Board) Draw(boardImage *ebiten.Image) error { animatingTiles := map[*Tile]struct{}{} nonAnimatingTiles := map[*Tile]struct{}{} for t := range b.tiles { - if t.IsAnimating() { + if t.IsMoving() { animatingTiles[t] = struct{}{} } else { nonAnimatingTiles[t] = struct{}{} diff --git a/examples/2048/2048/tile.go b/examples/2048/2048/tile.go index 323f4db8c..33f613900 100644 --- a/examples/2048/2048/tile.go +++ b/examples/2048/2048/tile.go @@ -32,9 +32,10 @@ type TileData struct { } type Tile struct { - current TileData - next TileData - animationCount int + current TileData + next TileData + moveCount int + popCount int } func NewTile(value int, x, y int) *Tile { @@ -63,8 +64,12 @@ func (t *Tile) NextPos() (int, int) { return t.next.x, t.next.y } -func (t *Tile) IsAnimating() bool { - return 0 < t.animationCount +func (t *Tile) IsMoving() bool { + return 0 < t.moveCount +} + +func (t *Tile) isPopping() bool { + return 0 < t.popCount } func tileAt(tiles map[*Tile]struct{}, x, y int) *Tile { @@ -84,7 +89,7 @@ func tileAt(tiles map[*Tile]struct{}, x, y int) *Tile { func nextTileAt(tiles map[*Tile]struct{}, x, y int) *Tile { var result *Tile for t := range tiles { - if 0 < t.animationCount { + if 0 < t.moveCount { if t.next.x != x || t.next.y != y || t.next.value == 0 { continue } @@ -102,7 +107,8 @@ func nextTileAt(tiles map[*Tile]struct{}, x, y int) *Tile { } const ( - maxAnimationCount = 10 + maxMovingCount = 5 + maxPoppingCount = 6 ) func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) bool { @@ -130,7 +136,7 @@ func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) bool { if t.next != (TileData{}) { panic("not reach") } - if t.IsAnimating() { + if t.IsMoving() { panic("not reach") } ii := i @@ -151,7 +157,7 @@ func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) bool { if t.current.value != tt.current.value { break } - if 0 < tt.animationCount && tt.current.value != tt.next.value { + if 0 < tt.moveCount && tt.current.value != tt.next.value { // already merged break } @@ -167,20 +173,20 @@ func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) bool { tt.next.value = 0 tt.next.x = ii tt.next.y = jj - tt.animationCount = maxAnimationCount + tt.moveCount = maxMovingCount } next.x = ii next.y = jj if t.current != next { t.next = next - t.animationCount = maxAnimationCount + t.moveCount = maxMovingCount } } } if !moved { for t := range tiles { t.next = TileData{} - t.animationCount = 0 + t.moveCount = 0 } } return moved @@ -189,7 +195,7 @@ func MoveTiles(tiles map[*Tile]struct{}, size int, dir Dir) bool { func addRandomTile(tiles map[*Tile]struct{}, size int) error { cells := make([]bool, size*size) for t := range tiles { - if t.IsAnimating() { + if t.IsMoving() { panic("not reach") } i := t.current.x + t.current.y*size @@ -218,16 +224,18 @@ func addRandomTile(tiles map[*Tile]struct{}, size int) error { } func (t *Tile) Update() error { - if t.animationCount == 0 { - if t.next != (TileData{}) { - panic("not reach") + switch { + case 0 < t.moveCount: + t.moveCount-- + if t.moveCount == 0 { + if t.current.value != t.next.value && 0 < t.next.value { + t.popCount = maxPoppingCount + } + t.current = t.next + t.next = TileData{} } - return nil - } - t.animationCount-- - if t.animationCount == 0 { - t.current = t.next - t.next = TileData{} + case 0 < t.popCount: + t.popCount-- } return nil } @@ -248,7 +256,11 @@ func colorToScale(clr color.Color) (float64, float64, float64, float64) { } func mean(a, b int, rate float64) int { - return int(float64(a)*rate + float64(b)*(1-rate)) + return int(float64(a)*(1-rate) + float64(b)*rate) +} + +func meanF(a, b float64, rate float64) float64 { + return a*(1-rate) + b*rate } const ( @@ -283,11 +295,26 @@ func (t *Tile) Draw(boardImage *ebiten.Image) error { y := j*tileSize + (j+1)*tileMargin nx := ni*tileSize + (ni+1)*tileMargin ny := nj*tileSize + (nj+1)*tileMargin - if 0 < t.animationCount { - rate := float64(t.animationCount) / maxAnimationCount + if 0 < t.moveCount { + rate := 1 - float64(t.moveCount)/maxMovingCount x = mean(x, nx, rate) y = mean(y, ny, rate) } + if 0 < t.popCount { + const maxScale = 1.2 + rate := 0.0 + if maxPoppingCount*2/3 <= t.popCount { + // 0 to 1 + rate = 1 - float64(t.popCount-2*maxPoppingCount/3)/float64(maxPoppingCount/3) + } else { + // 1 to 0 + rate = float64(t.popCount) / float64(maxPoppingCount*2/3) + } + scale := meanF(1.0, maxScale, rate) + op.GeoM.Translate(float64(-tileSize/2), float64(-tileSize/2)) + op.GeoM.Scale(scale, scale) + op.GeoM.Translate(float64(tileSize/2), float64(tileSize/2)) + } op.GeoM.Translate(float64(x), float64(y)) r, g, b, a := colorToScale(tileBackgroundColor(v)) op.ColorM.Scale(r, g, b, a) diff --git a/examples/2048/2048/tile_test.go b/examples/2048/2048/tile_test.go index 2d2a6eeea..6b7201c18 100644 --- a/examples/2048/2048/tile_test.go +++ b/examples/2048/2048/tile_test.go @@ -42,7 +42,7 @@ func tilesToCells(tiles map[*Tile]struct{}, size int) ([]int, []int) { for t := range tiles { x, y := t.Pos() cells[x+y*size] = t.Value() - if t.IsAnimating() { + if t.IsMoving() { if t.NextValue() == 0 { continue }