[GroovyとProcessing]まいんくらふと２Dのブロック選択を改造

選択中のブロックを見えるように改造する
マウスカーソルの重なっているブロック上に選択中のブロックを透過して表示する
あと上下左右キーで透過ブロックが移動する

動画リスト：[LWJGLのチュートリアル](http://www.youtube.com/playlist?list=PL19F2453814E0E315)
動画は[ココ](http://www.youtube.com/watch?v=rSPnmFJyzqs)

```groovy
package episode013

import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
import processing.core.PApplet
import processing.event.Event

class DisplayTest extends PApplet {

    def grid
    def selection = BlockType.STONE
    def selector_x = 0
    def selector_y = 0
    def mouseEnabled = true

    def void setup() {
        size(640, 480)
        frameRate(60)

        grid = new BlockGrid(this)
    }

    def void draw() {
        background(0, 0, 0)

        if (mouseEnabled) setSelectorPoint()

        grid.draw()
        drawSelectionBox()
    }

    def void keyPressed() {
        switch (key) {
            case 's':
                grid.save(new File('save.json'))
                break
            case 'l':
                grid.load(new File('save.json'))
                break
            case '1':
                selection = BlockType.STONE
                break
            case '2':
                selection = BlockType.DIRT
                break
            case '3':
                selection = BlockType.GRASS
                break
            case '4':
                selection = BlockType.AIR
                break
            case 'c':
                grid.clear()
                break
        }
        switch (keyCode) {
            case RIGHT:
                mouseEnabled = false
                if (!(selector_x + 1 > World.BLOCKS_WIDTH - 1)) {
                    selector_x += 1;
                }
                break
            case LEFT:
                mouseEnabled = false
                if (!(selector_x - 1 < 0)) {
                    selector_x -= 1;
                }
                break
            case UP:
                mouseEnabled = false
                if (!(selector_y - 1 < 0)) {
                    selector_y -= 1;
                }
                break
            case DOWN:
                mouseEnabled = false
                if (!(selector_y + 1 > World.BLOCKS_HEIGHT - 1)) {
                    selector_y += 1;
                }
                break
        }
    }

    def void mouseClicked() {
        mouseEnabled = true
        setSelectorPoint()
        setBlock()
    }

    def void mouseDragged() {
        mouseEnabled = true
        setSelectorPoint()
        setBlock()
    }

    def setBlock() {
        if (selector_x >= 0 && selector_x < World.BLOCKS_WIDTH
                && selector_y >= 0 && selector_y < World.BLOCKS_HEIGHT) {
            grid.setAt(selector_x, selector_y, selection)
        }
    }

    def setSelectorPoint() {
        selector_x = floor(mouseX / World.BLOCK_SIZE)
        selector_y = floor(mouseY / World.BLOCK_SIZE)
    }

    def drawSelectionBox() {
        if (grid.getAt(selector_x, selector_y).type != BlockType.AIR || selection == BlockType.AIR) {
            // 白い透過ブロックを表示
            noStroke()
            fill(255, 255, 255, 150)
            rect(selector_x * World.BLOCK_SIZE, selector_y * World.BLOCK_SIZE, World.BLOCK_SIZE, World.BLOCK_SIZE)
        } else {
            // 選択しているブロックを透過表示
            tint(255, 200)
            new Block(this, selection, selector_x * World.BLOCK_SIZE, selector_y * World.BLOCK_SIZE).draw()
            noTint()
        }
    }

    def static void main(args) {
        PApplet.main('episode013.DisplayTest')
    }
}

enum BlockType {
    STONE('stone.png'), AIR('air.png'), GRASS('grass.png'), DIRT('dirt.png')

    def location

    def BlockType(location) {
        this.location = location
    }
}

class Block {
    def type = BlockType.AIR
    def x, y
    def img
    def display

    def Block(display, type, x, y) {
        this.display = display
        this.type = type
        this.x = x
        this.y = y
        this.img = display.loadImage(type.location)
    }

    def draw() {
        display.image(img, x, y)
    }
}

class BlockGrid {
    def Block[][] blocks = new Block[World.BLOCKS_WIDTH][World.BLOCKS_HEIGHT];
    def display

    def BlockGrid(display) {
        this.display = display
        World.BLOCKS_WIDTH.times { x ->
            World.BLOCKS_HEIGHT.times { y ->
                blocks[x][y] = new Block(display, BlockType.AIR, x * World.BLOCK_SIZE, y * World.BLOCK_SIZE)
            }
        }
    }

    def load(loadFile) {
        def list = new JsonSlurper().parse(loadFile.newReader())
        list.each { block ->
            blocks[block.x][block.y] = new Block(
                    display,
                    BlockType.valueOf(block.type),
                    block.x * World.BLOCK_SIZE,
                    block.y * World.BLOCK_SIZE)
        }
    }

    def save(saveFile) {
        def list = []
        World.BLOCKS_WIDTH.times { x ->
            World.BLOCKS_HEIGHT.times { y ->
                list << [
                    x: blocks[x][y].x / World.BLOCK_SIZE,
                    y: blocks[x][y].y / World.BLOCK_SIZE,
                    type: blocks[x][y].type
                ]
            }
        }
        saveFile.write(new JsonBuilder(list).toString())
    }

    def setAt(x , y, type) {
        blocks[x][y] = new Block(display, type, x * World.BLOCK_SIZE, y * World.BLOCK_SIZE)
    }

    def getAt(x , y) {
        blocks[x][y]
    }

    def draw() {
        World.BLOCKS_WIDTH.times { x ->
            World.BLOCKS_HEIGHT.times { y ->
                blocks[x][y].draw()
            }
        }
    }

    def clear() {
        World.BLOCKS_WIDTH.times { x ->
            World.BLOCKS_HEIGHT.times { y ->
                blocks[x][y] = new Block(display, BlockType.AIR, x * World.BLOCK_SIZE, y * World.BLOCK_SIZE)
                blocks[x][y].draw()
            }
        }
    }
}

class World {
    public static final int BLOCK_SIZE = 32
    public static final int BLOCKS_WIDTH = 20
    public static final int BLOCKS_HEIGHT = 15
}
```
![grocessingGL013.png](https://qiita-image-store.s3.amazonaws.com/0/17179/7fb41f63-a0c5-43c6-5039-3f1d4a234dff.png)