Hatena::ブログ(Diary)

しんさんの出張所 はてな編 このページをアンテナに追加 RSSフィード

カレンダー
2007 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 08 | 09 | 10 | 11 | 12 |
2015 | 02 | 03 | 04 | 05 | 06 | 07 | 09 | 10 | 11 |
2016 | 05 | 08 | 10 | 11 | 12 |
2017 | 01 | 02 | 06 | 08 | 11 |
2018 | 02 |

2013-07-21

[][]WiiU ピクミン3クリア

ゲームパッドオンリープレイが9割です。

これだと布団の上で寝っ転がりながら寝る前に軽くやるといったことができます。非常にいいですね。あとはスリープ機能があったら完璧です。3DSではやれてるんだからWiiUでもやってほしいところ。


プレイ時間

ストーリークリアには初めてのプレイで45日。時間は16時間弱。ボリューム的には1よりやや多めといったところでしょうか。

入手できるものが目の前にあるのを確認してそれをあえて回収しない、クリア重視で進めてこれですから。

2の洞窟とかボリューム増やすには便利なものもあるのでしょうけど、自分はアレ嫌いなのでなくてよかったです。地上メインにしてるのはよいと思います。


よいところ

さすがにGC版と比べると画面はきれいです。とはいえ、被写界深度が設定されたのとテクスチャが多少きれいになった程度ですが。



白と紫のストーリーでリストラ。この2つはやはり特徴としてかなりいまいちでした。色から特徴がイメージしにくいのもありますし、白はかわいくないし。代わりに入った羽と岩は色ではないですが、非常にイメージしやすくてよいと思います。

とはいえ、5種類はやはり使い分けるのが面倒です。初代の3つはともかく、4つくらいがちょうどよいのではないでしょうか。

パッドのみプレイはいいですね。実際TVはつけないでプレイするようになりました。


ダメなところ

橋を作るところがピクミンの往復運動があって回収が結構しにくいです。そういうルールだとわかればいいのですが、せめて完成後は橋の上に待機するとかであってほしかった。従来は結果的には橋の上で待機となっていたのでこの差が大きい。橋を完成させたらふつうはその橋の上を素直に通ります。その通るときに回収できるかどうかはかなり影響すると思うのです。


そのほかポインティングGC版と比べて非常にしにくい気がします。ロックもありますけど、ロックの解除をし忘れてカメラが動かないとかが多発します。あと、どこをロックしているかなどもわかりにくい。おそらくカメラの高さが自動になっているのが原因ですね。奥行きがつかみにくいです。

隊列をいじれなくしたのはどういう意図があるんでしょうか。あれがないおかげで蜜を吸うのが絶望的です。敵と敵の間をすり抜けて歩くとか戦うとか細かい操作がしにくい気がします。ただし、ロック後の突撃は多少使いやすいとは思いました。


3キャラの同時操作。なれればいいのでしょうけど、3人を使ってキャラを高いところに投げていくところとか全然面白くない。橋を挟んで投げ合うところがピークでした。つまり、せいぜい2人いればそれでよかった。同時3人となるとかなり難易度は上がりますし、2人までにおさえておいてほしかった。できれば1人のままがやっぱりいですけどね。操作キャラの切り替えではなく、ピクミンを配置してピクミンの行動がいつくらいに終わるのかを予想しながらその時間に合わせて回収などといったほうが戦略性が高い気がします。人数を増やすのではなく、プレイヤーキャラクターをワープさせたり移動スピードを上げたりする方向のアイテムなどで調整はできなかったのか。


そして最大の問題点はこれです。雰囲気などが大幅に劣化しています。大水源系マップがないのもいまいちですが、とにかくマップが狭いところをひたすら歩く感じになっています。個々の仕掛けを壊して先に進むエリアを徐々に広げていく、そんなマップだらけです。

実はピクミンはわりと自由度が高くて、とにかく歩くだけならかなりの場所をいきなり歩けることができるものも多いのです。アイテム入手するためにポイントポイントで壁などを壊さないといけなかったりはしますが、3ではとにかくなんかやらないと先に進めないというのが多い。おまけにフィールドが狭い。マップそのものが狭いというわけではなくて、歩く道となる場所が狭い。広い場所で敵と戦うなどといったところがまったくないです。

狭い部分と広い部分とメリハリが必要だとは思うのですが、すべて狭い。

この開放感のなさがかなり圧迫感を感じて辛い感じになります。圧迫感を感じるのはリアルだけでいい。東京コンクリートジャングルだけでいいのですよ。ピクミンの世界は自然が豊かでキャラクターがとても小さく、好き勝手にピクミンを増やしたり戦ったりするところだと思っていましたが、一気にパズルとかそんな感じのゲームになりました。1や2とはわりと別物なんですね。

連れて歩いているピクミンが一瞬で全滅、もしくはひどい被害をするようなそういうのはほとんどなくなりました。そのかわり、増やすということを意識することも大幅に減りました。つまり、ストーリーモードはミッションモードと同じ感覚になりやすいです。


総合評価

以下いつもの5段階評価。

 評価
システム★★★★−
シナリオ★−−−−
サウンド★★★−−
グラフィック★★★★−
総合評価★★★★−

というわけで、基本システムは同じ感じなんですが、3は1や2とはだいぶ違うゲームです。

1や2が受け入れられた人は楽しめるとは思いますが、あの独特の雰囲気を期待すると肩すかしを食うと思います。

どうも、3は1や2をプレイ済みの人だけをターゲットにしている感じなんですよ。1と2でやったのはやらない、方向性を変えないと飽きられる、そう思っているのでしょうか。1と2もそこまで売れたソフトではない上に出たのはかなり前です。同じの繰り返したっていいじゃない。特に操作に慣れる序盤くらいは。

ピクミンはシステムもありますが、あの独特の世界観や雰囲気を楽しむゲームでもあったはずです。タイムアタックはクリア後の楽しみとしてとっておけばよいのですが、それがどうもストーリーの初回プレイでもやらされている感じがします。

どうも、ミッションモードを先に作って基本システムを完成させてそれにストーリーをつけた感じというか。マップの方向はがらっとかえなきゃあかんと思うんだけど。皮は確かにきれいだけれども、大水源のような池や海のようなのを感じさせるマップがほしかったですね。


というわけで繰り返しますが、3は1とも2とも全くプレイ感覚は違います。2と違うのは当たり前ですが、1ともかなり違いますので騙されませんよう。

ただし、ゲームそのものは面白いです。ボリュームも全部回収したりチャレンジやったりすると結構行くでしょう。そうでなくとも、アクションゲームとして1週が16時間というのは妥当な範囲だとは思います。

逆に3が初めての人は初代をぜひやってほしいですね。画面は汚いですけど、なぜピクミンが愛されるかわかると思います。Wiiで遊ぶもでていますので、WiiUでも遊べますし。

2013-07-20

[][]SoftBank 203SHがアップデートで一気にダメ端末に

203SHはバッテリは持つし安定しているし、デザインはいいし、持ちやすいし、クイック起動キー超便利だしとまさに神端末でした。ブラウザも指に吸い付く感じで操作感覚もiOSに引けを取らない。通信も安定して30Mbps以上でるので非常に高速。


だったのですが。


最近きたアップデートで一気にダメ端末になりました。勝手に再起動が入るようになります。

はやくシャープアップデートしてほしいですね。通常の操作で支障をきたすレベルです。

2013-07-08

[][]JavaEE 7 JPA 2.1の新機能ストアドプロシージャ

JPA 2.1ではついにストアドプロシージャも標準で使えるようになった。

今までは実装依存のコードで使ってはいたが。

今回もストアドを簡単にJavaのコードで作れるDerbyのストアドで。ストアドになるともう組み込みモードだと意味がないレベルだけど。

引数に文字列、戻り値に文字列を渡すストアドの設定をする。コード全部見たほうが早いと思うので一気にのせる。Derbyのoutなどは配列を使っているのが注意する点か。引数で渡して戻り値を複数返す方法ということで割り切り方としてはまぁいいのだろう。

public class DerbyEmbedded3 {
    //ストアドの実装
    public static void hello(String in1, String[] out1) {
        out1[0] = "Hello " + in1;
    }

    //main実行
    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatestPU3");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        //ストアドの作成
        String sql = "create procedure hello ("
                + "in in1 varchar(255) ,"
                + "out out1 varchar(255)"
                + ") "
                + " language java "
                + " parameter style java "
                + " no sql "
                + " external name 'embedded.DerbyEmbedded3.hello'";
        em.createNativeQuery(sql).executeUpdate();

        
        //ストアドの呼び出し
        StoredProcedureQuery spq = em.createStoredProcedureQuery("hello");
        spq.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);
        spq.registerStoredProcedureParameter(2, String.class, ParameterMode.OUT);

        spq.setParameter(1, "world");//パラメータわたし
        spq.execute();//実行
        
        //戻り値の取得
        String result = (String) spq.getOutputParameterValue(2);
        System.out.println("result=" + result);

        em.getTransaction().rollback();

        em.close();
        emf.close();
    }
}

パラメータのIN/OUTなどをあらかじめ設定しておいて(registerStoredProcedureParameter)それに対してパラメータを設定(setParameter)する。

その後実行(execute)し、結果を(getOutputParameterValue)取り出す。


よくあるJPA2.1のストアドのサンプルはNamedQueryにしていると思う。実際ストアドを動的に作ることは少ないと思うのでこれこそNamedQuery向きではある。

でも、それじゃ面白くないので、Entityなしでコードのみで実装してみた。とはいえ上記の通りそれも難しいものではなく、非常に簡単。

2013-07-07

[][]JavaEE 7 JPA 2.1の新機能 FUNCTION 句

JPQLなどJPAの機能ではカバーできない、RDB固有の機能として関数がある。countやsumなど基本的なものはあるが、それから離れるとダメだ。かといって無駄に関数を増やしたところでユーザー定義関数などもありとてもカバーしきれない。

というわけで、JPA2.1ではついにユーザー定義を含めて関数を自由に呼び出せるようになった。

Entity

@Entity
@Access(AccessType.FIELD)
public class JoinEntity implements Serializable {
    @Id
    public int id;
    public String name;

    public JoinEntity() {
    }

    public JoinEntity(int id, String name) {
        this.id = id;
        this.name = name;
    }
    
}

idとnameのカラムを持つ。


利用例

Derbyの組み込みモードで利用している。同一JVMなため、ユーザー定義関数を簡単に扱えるためだ。ネットワークモードの場合はそちらのVMに設定が必要なのでそこそこ面倒なので注意。

public class DerbyEmbedded2 {

    public static String join(int in1, String in2) {
        return String.format("%03d:%s", in1, in2);
    }

    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatestPU2");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        //ユーザー定義関数を設定。
        em.createNativeQuery("create function "
                + "func_join( in1 integer, in2 varchar(256)) returns varchar(256)"
                + "language java "
                + "external name 'embedded.DerbyEmbedded2.join'"
                + "parameter style java").executeUpdate();

        //サンプルデータ追加
        em.persist(new JoinEntity(1, "はろー"));
        em.persist(new JoinEntity(20, "関数"));
        em.persist(new JoinEntity(300, "わーるど"));

        {
            String jpql = "select function('func_join', je.id , je.name) from JoinEntity je order by je.id";
            TypedQuery<String> query = em.createQuery(jpql, String.class);
            for (String text : query.getResultList()) {
                System.out.println(text);
            }
        }
    
        em.getTransaction().rollback();

        em.close();
        emf.close();
    }
}

上のコードはfunc_joinという名前のユーザー定義関数を作成している。実装はjoinメソッド

Derbyのユーザー定義関数Javaのコードで書けるため、とっても楽。public staticなメソッドをユーザー定義関数にできるのだ。


JPQLでの使い方も簡単。function(関数名 , パラメータ...)となっている。

実行結果

001:はろー
020:関数
300:わーるど

joinメソッドが各行で呼ばれているのがわかる。


そのほか

ユーザー定義でない関数ももちろんOK。以下は文字列の長さを返すlength関数

{
    String jpql = "select function('length', je.name) from JoinEntity je order by je.id";
    TypedQuery<Integer> query = em.createQuery(jpql, Integer.class);
    for (Integer len : query.getResultList()) {
        System.out.println(len);
    }
}

JPQLの関数との組み合わせもOK。

{
    String jpql = "select sum(function('length', je.name)) from JoinEntity je";
    Integer result = em.createQuery(jpql, Integer.class).getSingleResult();
    System.out.println(result);
}

sum関数をJPQLのsum関数ではなくてRDBの本来のsum関数で呼ぶこともできる。意味はないと思うけど。

{
    String jpql = "select function('sum', function('length', je.name)) from JoinEntity je";
    Integer result = em.createQuery(jpql, Integer.class).getSingleResult();
    System.out.println(result);
}


これにより、JPAだけでかなりの範囲がカバーされる。定型的なことには強かったJPAだが、その例外的なRDB固有の関数にアクセスできるようになったのは大きな進歩だ。これならばたしかにJPQLの言語拡張を最小限で済む。Criteriaももちろん対応しているので調べてみるとよいだろう。

2013-07-06

[][]RDBXMLを扱う

http://kikutaro777.hatenablog.com/entry/2013/07/05/211817

RDBXMLがいまいちわからないということなのでかるく書いてみる。


使うのはDerbyJDBCリファレンスとして、JavaDBという名前で利用されているため。ちなみにJava6のJDBC4にいち早く対応はしたものの、Java6のSQLXMLは使えない。文字列を利用して転送する。


JDBCでもいいけど、たるいのでDB接続情報はpersistence.xmlに記述。JPAでNativeQueryのみを使う。Entityは作らない。


まぁいわゆるJPAらしさはゼロ。Javaである必要性も低いレベル。


テーブルはint型のidとXML型のxml_valueという項目をもつ。

public static void main(String[] args) throws SQLException {
    
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatestPU2");
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    
    //テーブル作成
    em.createNativeQuery("create table hoge ( id integer, xml_value XML)").executeUpdate();
    
    //サンプルデータ3件作成
    String insert = "insert into hoge (id, xml_value)values(?, XMLPARSE(document CAST (? as varchar(32000)) PRESERVE WHITESPACE))";
    Query insertQuery = em.createNativeQuery(insert);
    insertQuery.
            setParameter(1, 1).
            setParameter(2, "<html><head><title>aaa</title></head><body>あ</body></html>").
            executeUpdate();

    insertQuery.
            setParameter(1, 2).
            setParameter(2, "<html><head><title>bbb</title></head><body>い</body></html>").
            executeUpdate();

    insertQuery.
            setParameter(1, 3).
            setParameter(2, "<html><head><title>aaa</title></head><body>う</body></html>").
            executeUpdate();
    
    
    String sql = "select id , XMLSERIALIZE(XMLQUERY('/html/body/text()' PASSING BY REF xml_value EMPTY ON EMPTY)as varchar(255)) "
            + "from hoge "
            + "where XMLEXISTS('/html/head/title[text()=\"aaa\"] ' PASSING BY REF xml_value)";
    List<Object[]> list = em.createNativeQuery(sql).getResultList();
    for(Object[] row : list){
        System.out.printf("%d/%s%n", row[0], row[1]);
    }

    
    
    em.getTransaction().rollback();

    em.close();
    emf.close();
}

Connectionすら取り出さず扱っている。Queryというのは生JDBCでいうとPreparedStatement相当だということがわかる。


内容はHTMLのtitleタグのテキストが「aaa」のものを検索し、bodyのテキストを取得するというもの。あとidも。


実行結果は以下の通り

1/あ
3/う

複雑な構造を格納したいという場合はまぁありだろう。条件として使いたい場合はパフォーマンスを見てからのほうがよいかもしれない。RDBの苦手な階層の構造を持つというのは結構便利なのはわかってもらえると思う。

ただし、DerbyJDBCドライバではXMLPARSEしかパラメータが使えないようなので注意。また、XMLの一部のみを取り出したいという場合はEntityやNamedQueryと相性も悪い。更新はいいとして、JPQLでも扱えないわけで。

おそらくこういうのをJPQLで扱いたい場合はストアドやユーザー関数などにして呼び出すというのがスマートだろうか。


ちなみにDerbyでは使わないがSQLXMLという型が登場して便利になったのはJava6から。そのほか、LOB関連も満足に標準APIで使えるようになったのもJava6から。Java5以前はとっくにサポート切れてるし、気にしなくてもよさそうだけどね。

2013-07-02

[][]JavaEE 7 JPA 2.1の新機能 動的なNamedQuery作成

JPAは基本的なCRUDは標準で使え(データマッパーパターンなので当たり前)、定型的なクエリはNamedQueryとしてあらかじめ静的に設定しておくことができる。

しかし、完全に静的ではなく、起動時に少しいじりたいなどほんの少し動的な性的静的なクエリを作りたいこともあるはずだ。


というわけで、2.1ではNamedQueryをコードで作れるようになった。

定義

EntityManager em = emf.createEntityManager();

String sql = "select address , count(*) as count from customer group by address";
Query q = em.createNativeQuery(sql,"address_count");
em.getEntityManagerFactory().addNamedQuery("native", q);

String jpql = "select NEW jpatest.Hoge(c.address, count(c)) from Customer c group by c.address";
TypedQuery q2 = em.createQuery(jpql, Hoge.class);
em.getEntityManagerFactory().addNamedQuery("jpql", q2);
            
em.close();

注意するのはEntityManagerではなくEntityManagerFactoryであること。

また、渡すのはJPQLなど文字列ではなくQueryであること。引数はQueryなのでQuery以外にもそれを継承しているTypedQueryやNativeQuery、ストアドプロシージャのクエリであるStoredProcedureQueryを渡せる。

ただし、addはできても、removeはできないようなので、アプリの中でどうてきにつくるというたぐいのものではないようだ。起動時に環境に合わせて1度設定する、ような使い方だろう。

2013-07-01

[][]JavaEE 7 JPA 2.1の新機能 ネイティブクエリの改善

JPAは1.0からネイティブクエリに対してEntityにマッピングする機能はあった。

面倒ではあるけど、まぁ使いたい場合もあるのだろう。

あくまでもObjectとマッピングするのが目的と考えるとこれでいいのだろうが、実際Entityと素直にマッピングするような用途ならJPQLで足りることが多いはずだ。

JPQLでは1.0からEntity以外にマッピングする方法が用意されている。

NEW句だ。様々なクエリを作る場合これが活躍する。というか、これが一番大事な機能だったりする。


と、JPQLを利用する場合、Entityを利用する場合はいいのだが、それから外れると一気にサポートがなくなっていた。


JPAは2.1でやっとネイティブクエリへのサポートが強化された。

一言で表すとネイティブクエリに対してNEW句が使えるようになった。


では、サンプルを作成してみる。Entityやテーブルの構成は前々回と変わらず(コンバータ適用前に戻す)。


やりたいことは住所でグループ化してその件数を数えるというもの。これだけならJPQLでいいのだがネイティブクエリであえてやってみる。

データベース

customer

idnameaddress
1A北海道
2B青森県
3C北海道

これからグループ化するための文字列address、件数の数値型countの2つを返すようにする。

発行するSQLは以下のもの

select address , count(*) as count
  from customer
  group by address

実行結果は以下になる。

addresscount
北海道2
青森県1

検索結果を格納するもの

public class Hoge {
    public final String address;
    public final int count;

    public Hoge(String address, int count) {
        this.address = address;
        this.count = count;
    }
}

必要なのはコンストラクタ。ここにSQLの結果をマッピングさせる。

つまり、ロジックを入れ込みたい場合はここで処理を書けばよろしい。


Entity

@SqlResultSetMapping(
        name = "address_count",
        classes = {
            @ConstructorResult(targetClass = Hoge.class,
            columns = {
                @ColumnResult(name="address"),
                @ColumnResult(name="count")
            })
        })

@Entity
@Access(AccessType.FIELD)
public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    public Long id;
    public String name;
    public String address;
    
}

必要なのは@SqlResultSetMapping。classes 属性がJPA 2.1で追加されていてここにマッピングする。

ColumnResultにはコンストラクタに渡す型を指定することもできる。

たとえば上のcountはInteger型であるが、ここのコンストラクタがLongの場合Longの指定が必要。


実行するコード

public static void main(String[] args) throws SQLException {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatestPU");
        
        EntityManager em = emf.createEntityManager();

        String sql = "select address , count(*) as count from customer group by address";
        Query q = em.createNativeQuery(sql, "address_count");
        List<Hoge> result = q.getResultList();
        for(Hoge h : result){
            System.out.printf("%s=%d件%n",
                    h.address, h.count);
        }
        
        em.close();
        
        emf.close();
        
}

createNativeQueryでEntityの@SqlResultSetMappingに設定した名前を渡す。それだけ。


まぁ、手間は手間であるが多少は前進はした。

マッピングを静的に設定することからNamedNativeQueryも登録しておくのがいいのだろうか。


順調にJPAは使いやすくはなっていってるが、ネイティブクエリは他と比べるとやはり弱い。基本ネイティブクエリは使わないもの、どうしても必要がある時の最終手段として仕方なく使うもの、と考えればさほど問題はないのかもしれない。生Connectionからの処理も普通に書けるし、それは別ライブラリ使えばいいという割り切り方もありだろう。

JPA 2.1ではストアドプロシージャやネイティブのファンクションを使えるのでDB固有のガリガリ処理するものはそちらにまかせるというのがいいのだろう。Entityからデータベースを作成するというのも正式に実装されたわけで、ますます新規アプリではDBありき、よりEntityクラスありきで設計するのが正しい、となるだろう。

SQLというネイティブクエリ中心ではO/Rマッパを扱いきれないため、仕方がないところ。