人生、気合いと具合 - blog

タグ:ScalaFX

TreeViewのCellFactoryをScalaFXでやろうと思ったら、どうも上手くいかない。
TreeCellのupdateItemをオーバーライドしたいわけだが、コンパイルの時点で怒られる。

override_error



いやそんなこといわれても。
ちなみにJavaFXのTreeCellならちゃんとオーバーライドできる。(当たり前)

しょうがないのでソースを見てみると、TreeCell(の親クラスのIndexedCell)が、Cellを継承してないよ...?
JavaFXだと、Labeled <- Cell <- IndexedCell <- TreeCell
ScalaFXは、Labeled <- IndexedCell <- TreeCell 

updateItemを持ってるのはCellだからそりゃ怒られる。
じゃあローカルで修正して使ってみるか?ということで、TreeCell/IndexedCell/Cellを調べてみたら、そもそもCellにもupdateItemが実装されてない。
で、Cellのソースの最後にTODOが。
  // TODO: implement updateItem(T item, boolean empty)
  // might be difficult since updateItem is a protected method which needs to be defined in the delegate's class

ああ...そうか、updateItemはprotectedか...。

ScalaFXのクラスはJavaFXのクラスを直接継承しているわけじゃないから、こういうケースを上手くラップするのは確かに難しそうだなぁ。
とりあえず現時点ではJavaFXのクラスを使わざるを得ないか。しょうがないんだけど、なんかいい方法がないもんだろうか...。

初参加がいきなり100回記念、ということでScala勉強会(rpscala)100回記念ハッカソンに参加してきました。

自己紹介のあともくもくとハッカソン。せっかくなので、自分が作ってたものを一応以下に公開。(少し当日から修正あり)
といっても、scalafxが使えて、タッチパネルがある(実質、ほぼWindows8専用みたいなもの?)という条件なので、著しく実行環境が制限されるけども。

画面下部の白い円にタッチしてフリック(?)すると、その方向に赤い円が飛んで行きます。緑の円に当ててください。
単なるサンプルなのでスコアとかゲームオーバーとかはありません。

rpscala100



















package com.bugworm.rpscala100

import scalafx.application.JFXApp
import scalafx.stage.StageStyle
import scalafx.scene.Scene
import scalafx.scene.layout.Pane
import scalafx.scene.input.TouchEvent
import scalafx.scene.paint.Color
import scalafx.scene.shape.Circle
import scalafx.Includes._
import scalafx.animation.{KeyFrame, Timeline}
import scalafx.event.ActionEvent
import collection.immutable.List

object Sample extends JFXApp{

    var startBall : Option[Circle] = None
    var myBalls = List.empty[Circle]
    var targets = List.empty[Circle]

    val base = Circle(512, 700, 64, Color.WHITE)
    val rootPane = new Pane{
        prefWidth = 1024
        prefHeight = 768
        content = base
    }

    new JFXApp.PrimaryStage{

        initStyle(StageStyle.UNDECORATED)

        scene = new Scene(rootPane){

            fill = Color.DARKBLUE

            onTouchPressed = {e : TouchEvent =>
                val p = e.touchPoint
                startBall = if(base.contains(p.getX, p.getY))
                    Some(Circle(p.getX, p.getY, 32, Color.RED)) else None
                startBall.foreach(rootPane.children.add(_))
            }

            //onTouchReleasedじゃないのはscalafxのバグ回避
            delegate.onTouchReleasedProperty().setValue({e : TouchEvent =>
                startBall.foreach{ball =>
                    val end = e.touchPoint
                    val dx = end.getX() - ball.centerX()
                    val dy = end.getY() - ball.centerY()
                    if(math.abs(dx) > 5 || math.abs(dy) > 5){
                        myBalls = ball :: myBalls
                        val tx = if(dx == 0) 1000 else 600 / math.abs(dx)
                        val ty = if(dy == 0) 1000 else 800 / math.abs(dy)
                        val time = math.min(tx, ty)
                        new Timeline{
                            keyFrames = at (time * 200 ms) {Set(
                                ball.centerX -> (ball.centerX() + dx * time),
                                ball.centerY -> (ball.centerY() + dy * time)
                            )}
                            onFinished = {e : ActionEvent =>
                                rootPane.children.remove(ball)
                                myBalls = myBalls.filterNot(_ == ball)
                            }
                        }.play
                    }else{
                        rootPane.children.remove(ball)
                    }
                    startBall = None
                }
            })

            onRotate = close
            onKeyPressed = close
        }
    }

    new Timeline{
        cycleCount = Timeline.INDEFINITE
        keyFrames = KeyFrame(50 ms, "main", {e : ActionEvent =>
            myBalls.foreach{b =>
                targets.filter{t =>
                    math.pow(b.centerX() - t.centerX(), 2) + math.pow(b.centerY() - t.centerY(), 2) < 4000
                }.foreach{hit =>
                    rootPane.children.remove(hit)
                    targets = targets.filterNot(_ == hit)
                }
            }
            if(math.random > 0.95){
                val target = Circle(math.random * 896 + 64, -64, 64, Color.LIGHTGREEN)
                targets = target :: targets
                rootPane.children.add(target)
                new Timeline{
                    keyFrames = at ((6 + math.random * 3) s) {target.centerY -> 832}
                    onFinished = {e : ActionEvent =>
                        rootPane.children.remove(target)
                        targets = targets.filterNot(_ == target)
                    }
                }.play
            }
        })
    }.play
}


会場はチームラボさんに提供していただきました。
ちょっとオシャレ?な感じで開放感のある部屋、ハッカソンするのにとてもよい感じでした。ありがとうございます。
 

This post is written as 23rd in irof Advent Calendar and JavaFX Advent Calendar.

Regardless of the Mayan calendar, I'm glad you are safe.
We are not interested in it, however, irof-san saved the Earth.

unzip and double click irof.jar



irof_screen_shot


When hold down the left mouse button, the balloon(?) is fired towards the mouse cursor, using the balloon to destroy the meteor.
Boss will appear over time, shoot and destroy it. Done right, you can save the Earth.
Meter at the bottom will be green to destroy the meteor, be red meteor reaches the Earth. If the meter is red all, game is over.

This is a sample that making a game with ScalaFX is easy.

Incidentally, game screen is using Canvas, and start button, text and meter are using Label and Rectangle in BorderPane.

このエントリは、いろふ Advent Calendar、およびJavaFX Advent Calendarの23日目のエントリです。

さて、マヤ暦がどーのこーので地球が滅亡するのしないの、なんて話がありましたが、みなさま無事でなによりです。
しかし、我々が「滅びるわけねーだろ、ふふーん」とか余裕ぶっこいてる裏で、実はいろふさんが地球を守ってくれたのです!!!

ダウンロード
解凍してirof.jarをダブルクリックで起動するはず?

アプレット/Web Start


ソースとかはこちらで


irof_screen_shot


マウスの左ボタンを押しっぱなしにすると、マウスカーソルに向かってふきだし(?)が発射されるので、迫りくる隕石(うめぼしではない)を破壊しましょう。
一定時間耐えると、ボスが出現するので目いっぱい打ち込んでください。うまくいけば地球は救われるでしょう。
画面下のメーターは隕石を破壊すると増えて、隕石が地球に到達すると減っていきます。オールレッドになるとゲームオーバーです。
また、ボスが地球に到達した場合、無条件にゲームオーバーです。

まあ、要はScalaFXでゲームっぽいものを実装してみたというわけですが、ゲームとして成立はしてないですな。バランスもなにもないw
これくらいなら結構簡単にできますよーというサンプル的なものと思ってもらえば。

ちなみに、ゲームのメイン画面はCanvasにイメージを描画しています。
スタートボタンやゲームオーバーなどの文字とメーターはBorderPaneにLabelやRectangleを設定して使用。

てか、もうちょっと改良したいよ!
 

11/30に第8回JavaFX勉強会に行ってきた。

今回は30分枠をいただいたので、またScalaFXで発表。1年くらい前にもScalaFXで発表したのだが、そのころに比べてだいぶ「使える」状態になっているので、そのあたりを含めて基本的な構造などを発表。
30分枠なのに結局22分くらいで終わってしまった。やはり本番は早口になったり、言おうと思ってたこと忘れたりとかあるなー。
まあ最終的に勉強会全体が30分近くオーバーしたので、早い分にはよかったか。

とりあえず資料(をOpenOffice化したもの)をSlideShareにアップロードしてみた。
ScalaFXのしくみをまなぶ

 そして懇親会でなぜか、あのAdventCalendarに参加することになった...なにを書けばいいんだろう?

このページのトップヘ