ebiten/examples/blocks/blocks/piece.go
2016-02-21 01:35:45 +09:00

264 lines
5.1 KiB
Go

// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package blocks
import (
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil"
)
var imageBlocks *ebiten.Image
func init() {
var err error
imageBlocks, _, err = ebitenutil.NewImageFromFile("_resources/images/blocks/blocks.png", ebiten.FilterNearest)
if err != nil {
panic(err)
}
}
type Angle int
const (
Angle0 Angle = iota
Angle90
Angle180
Angle270
)
func (a Angle) RotateRight() Angle {
if a == Angle270 {
return Angle0
}
return a + 1
}
func (a Angle) RotateLeft() Angle {
if a == Angle0 {
return Angle270
}
return a - 1
}
type BlockType int
const (
BlockTypeNone BlockType = iota
BlockType1
BlockType2
BlockType3
BlockType4
BlockType5
BlockType6
BlockType7
BlockTypeMax = BlockType7
)
type Piece struct {
blockType BlockType
blocks [][]bool
}
func toBlocks(ints [][]int) [][]bool {
blocks := make([][]bool, len(ints))
for j, row := range ints {
blocks[j] = make([]bool, len(row))
}
// Tranpose the argument matrix.
for i, col := range ints {
for j, v := range col {
blocks[j][i] = v != 0
}
}
return blocks
}
var Pieces = map[BlockType]*Piece{
BlockType1: {
blockType: BlockType1,
blocks: toBlocks([][]int{
{0, 0, 0, 0},
{1, 1, 1, 1},
{0, 0, 0, 0},
{0, 0, 0, 0},
}),
},
BlockType2: {
blockType: BlockType2,
blocks: toBlocks([][]int{
{1, 0, 0},
{1, 1, 1},
{0, 0, 0},
}),
},
BlockType3: {
blockType: BlockType3,
blocks: toBlocks([][]int{
{0, 1, 0},
{1, 1, 1},
{0, 0, 0},
}),
},
BlockType4: {
blockType: BlockType4,
blocks: toBlocks([][]int{
{0, 0, 1},
{1, 1, 1},
{0, 0, 0},
}),
},
BlockType5: {
blockType: BlockType5,
blocks: toBlocks([][]int{
{1, 1, 0},
{0, 1, 1},
{0, 0, 0},
}),
},
BlockType6: {
blockType: BlockType6,
blocks: toBlocks([][]int{
{0, 1, 1},
{1, 1, 0},
{0, 0, 0},
}),
},
BlockType7: {
blockType: BlockType7,
blocks: toBlocks([][]int{
{1, 1},
{1, 1},
}),
},
}
const blockWidth = 10
const blockHeight = 10
const fieldBlockNumX = 10
const fieldBlockNumY = 20
type blocksImageParts [][]BlockType
func (b blocksImageParts) Len() int {
return len(b) * len(b[0])
}
func (b blocksImageParts) Dst(i int) (x0, y0, x1, y1 int) {
i, j := i%len(b), i/len(b)
x := i * blockWidth
y := j * blockHeight
return x, y, x + blockWidth, y + blockHeight
}
func (b blocksImageParts) Src(i int) (x0, y0, x1, y1 int) {
i, j := i%len(b), i/len(b)
block := b[i][j]
if block == BlockTypeNone {
return 0, 0, 0, 0
}
x := (int(block) - 1) * blockWidth
return x, 0, x + blockWidth, blockHeight
}
func drawBlocks(r *ebiten.Image, blocks [][]BlockType, x, y int, clr ebiten.ColorM) error {
op := &ebiten.DrawImageOptions{
ImageParts: blocksImageParts(blocks),
ColorM: clr,
}
op.GeoM.Translate(float64(x), float64(y))
return r.DrawImage(imageBlocks, op)
}
func (p *Piece) InitialPosition() (int, int) {
size := len(p.blocks)
x := (fieldBlockNumX - size) / 2
y := 0
Loop:
for j := 0; j < size; j++ {
for i := 0; i < size; i++ {
if p.blocks[i][j] {
break Loop
}
}
y--
}
return x, y
}
func (p *Piece) isBlocked(i, j int, angle Angle) bool {
size := len(p.blocks)
i2, j2 := i, j
switch angle {
case Angle0:
case Angle90:
i2 = j
j2 = size - 1 - i
case Angle180:
i2 = size - 1 - i
j2 = size - 1 - j
case Angle270:
i2 = size - 1 - j
j2 = i
}
return p.blocks[i2][j2]
}
func (p *Piece) collides(field *Field, x, y int, angle Angle) bool {
size := len(p.blocks)
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
if field.IsBlocked(x+i, y+j) && p.isBlocked(i, j, angle) {
return true
}
}
}
return false
}
func (p *Piece) Collides(field *Field, x, y int, angle Angle) bool {
return p.collides(field, x, y, angle)
}
func (p *Piece) AbsorbInto(field *Field, x, y int, angle Angle) {
size := len(p.blocks)
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
if p.isBlocked(i, j, angle) {
field.setBlock(x+i, y+j, p.blockType)
}
}
}
}
func (p *Piece) DrawAtCenter(r *ebiten.Image, x, y, width, height int, angle Angle) error {
x += (width - len(p.blocks[0])*blockWidth) / 2
y += (height - len(p.blocks)*blockHeight) / 2
return p.Draw(r, x, y, angle)
}
func (p *Piece) Draw(r *ebiten.Image, x, y int, angle Angle) error {
size := len(p.blocks)
blocks := make([][]BlockType, size)
for i := range p.blocks {
blocks[i] = make([]BlockType, size)
for j := range blocks[i] {
if p.isBlocked(i, j, angle) {
blocks[i][j] = p.blockType
}
}
}
return drawBlocks(r, blocks, x, y, ebiten.ColorM{})
}