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 |

2016-12-07

[][]超高速に初めるJAX-RS + Guice

JAX-RSの起動は前回さくっと終わらせた。

http://d.hatena.ne.jp/shin/20161204/p1

あとはロジック回り。今回はGoogle Guiceを使う。CDIを使うならWeldSEは使わずpayara microなどEEコンテナをちゃんと立ち上げたほうが良い。

Guiceとのコネクタは用意されているのでそれを使おう。


依存ライブラリの追加

前回の状態からさらに依存関係に以下の1行を追加する

compile "org.glassfish.hk2:guice-bridge:2.5+"

おわり。JAX-RSの依存も前回の1行だけだったのであわせて2行だけ。


やること

前回作ったCalcというリソースクラスにFormatLogicという文字列を返すクラスのシングルトンのインスタンスを注入する。

そのクラスを使い、結果を返す。


プログラム

今回もソースコード一つ。

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import java.net.URI;
import java.util.Scanner;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.ServiceLocatorProvider;
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;

public class Main {

    //--------------------------------------------------------------------------
    //サーバー起動
    //--------------------------------------------------------------------------
    public static void main(String[] args) {
        
        URI uri = UriBuilder.fromUri("http://localhost/").port(8080).build();
        ResourceConfig config = new ResourceConfig(GuiceFeature.class, Calc.class);
        JdkHttpServerFactory.createHttpServer(uri, config);

        //Enter押すまで待つ
        new Scanner(System.in).nextLine();

        System.exit(0);
    }
    
    //--------------------------------------------------------------------------
    //JAX-RSリソースクラス
    //--------------------------------------------------------------------------
    @Path("calc")
    public static class Calc {
        @Inject
        FormatLogic logic;
        

        //http://localhost:8080/calc?a=1&b=2
        @GET
        @Produces(MediaType.TEXT_PLAIN)
        public String add(@QueryParam("a") int a, @QueryParam("b") int b) {
//            System.out.println("calc:"+this);
            return logic.format(a, b);
        }
        
    }
    
    //--------------------------------------------------------------------------
    //GUICEのセットアップ
    //--------------------------------------------------------------------------
    public static class GuiceFeature implements Feature {
        @Override
        public boolean configure(FeatureContext context) {
            ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
            GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
            final Injector injector = Guice.createInjector(new AbstractModule() {
                @Override
                protected void configure() {
                }
            });
            GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
            guiceBridge.bridgeGuiceInjector(injector);
            return true;
        }
    }
    
    //--------------------------------------------------------------------------
    //注入される
    //--------------------------------------------------------------------------
    @Singleton
    public static class FormatLogic{
        public String format(int a, int b){
//            System.out.println("logic:"+this);
            return String.format("%d + %d = %d", a, b, a+b);
        }
    }

}

実行

http://localhost:8080/calc?a=1&b=2

というURLブラウザで表示すると

1 + 2 = 3

と表示される。

2016-12-04

[][][]超高速に初めるJAX-RS

ソースコードは一つだけ。設定ファイルは1行追加するだけ。それですぐにJAX-RSを動かせる。

JAX-RSはわからなくても大丈夫。JavaSEなのですぐ確認できる。

GradleまたはMaven環境さえあればよいのでNetBeansに限らないけど一応NetBeansで説明していく。


Gradleまたはmavenの環境を用意する

NetBeansであればGradleはプラグインを入れる必要がある。今回はGradleでやってみる。

メニューの「ツール」−「プラグイン」から入れる。


プロジェクトの新規作成

メニューから「ファイル」−「新規プロジェクト」を選ぶ。

カテゴリで「Gradle」を選びプロジェクトは「Single Gradle Project」を選ぶ。


依存ライブラリの追加

プロジェクトツリーからBuilde Scripts/Project/build.gradleを開く。

以下の部分があるので

dependencies {
    // TODO: Add dependencies here ...
    // You can read more about how to add dependency here:
    //   http://www.gradle.org/docs/current/userguide/dependency_management.html#sec:how_to_declare_your_dependencies
    testCompile group: 'junit', name: 'junit', version: '4.10'
}

dependencies の中に

compile "org.glassfish.jersey.containers:jersey-container-jdk-http:2.24.1"

の1行を加える。

プロジェクトのリロード

プロジェクトツリーのルートアイコンを右クリックして「Reload Project」を選ぶ。


インクラスを作る

import java.net.URI;
import java.util.Scanner;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

public class Main {

    //サーバー起動
    public static void main(String[] args) {
        
        URI uri = UriBuilder.fromUri("http://localhost/").port(8080).build();
        ResourceConfig config = new ResourceConfig(Calc.class);
        JdkHttpServerFactory.createHttpServer(uri, config);

        //Enter押すまで待つ
        new Scanner(System.in).nextLine();

        System.exit(0);
    }

    //JAX-RSのコードをここに書く
    @Path("calc")
    public static class Calc {

        //http://localhost:8080/calc?a=1&b=2
        @GET
        @Produces(MediaType.TEXT_PLAIN)
        public int add(@QueryParam("a") int a, @QueryParam("b") int b) {
            return a + b;
        }
    }
}

サーバー起動

プロジェクトを実行する。F6でよい。


ブラウザ起動

上記のコードのコメント部分

        //http://localhost:8080/calc?a=1&b=2

ここをCTRL+クリックする。

ブラウザが起動して結果が表示される。

NetBeansでは文字列やコメントでURLぽいものがあればブラウザで開けるのでコメントで描いておくと楽。

2016-08-21

[][]libGDXの基礎15 NinePatchを使う

今回はNinePatch(ナインパッチ)の使い方です。

原理的には難しくなくて、ただ引き延ばす場所を指定するだけです。ナインパッチという名前は知らなくても大昔にHTMLのテーブルでレイアウトして使っていた人は多いのではないでしょうか。

http://qiita.com/shinsan68k/items/5b9c9981fbcdbb49a8af

qiitaで前回から1年以上たってしまいましたが、少しずつでも書いていけたらと。

横線入れると一区切りになるというスライドモードにも章単位で対応してみました。

完全にスライド用にはしていないです。というか文字の大きさ固定とかコード全部載せてるやつなので無理です。

一部分のみではなく、完全なソースコードがあるので従来通り下にスクロールして読む方がいいとは思いますが。

2016-05-12

[][]Thymeleaf 3.0を試す その3 ユーティリティを作る

Thymeleaf 3.0を試す

Thymeleaf 3.0を試す その2 エスケープの有無

の続き。

今までパラメータとして文字列しか渡していませんでしたが、もちろん数値も扱えます。

〜
        String template = "[[${a}]] + [[${b}]] = [[${a+b}]]";

〜

        Map<String, Object> params = new HashMap<>();
        params.put("a", 1000);
        params.put("b", 20000);
〜

計算もView側でできるのがわかりますね。

実行結果

1000 + 20000 = 21000

3桁区切り

3ケタごとに区切り文字を入れたいというのはよくあることです。もちろんそれも標準で用意はされてはいます。一応。

〜
        String template = "[[${#numbers.formatInteger(a+b, 1, 'DEFAULT')}]]";
〜

実行結果

21,000

一応と書いたのは、見てわかる通りあほみたいに長いのが原因です。

実行しないとこのミスはわからないしこんなのいちいち書いてられないと思います。書いていたらおかしいと思わないといけませんよね。


オレオレutil

というわけで作ります。まずシンプルに何も考えず現在できる仕組みの中で考えてみましょう。

        //----------------------------------------------------------------------
        //追加したいユーティリティ
        //----------------------------------------------------------------------
        class OreOreUtil {
            public String num(int num){
                NumberFormat nf = NumberFormat.getInstance();
                return nf.format(num);
            }
        }
〜
        String template = "[[${oreore.num(a+b)}]]";
〜
        Map<String, Object> params = new HashMap<>();
        params.put("a", 1000);
        params.put("b", 20000);
        params.put("oreore", new OreOreUtil());
〜

実行結果

21,000

まずはこれで十分だと思います。しいて言えばユーティリティなのかパラメータなのかどうかがわかりにくいです。パラメータとして渡していますので。「#」は予約されていてパラメータの名前として使えないのでこうなります。

が、命名規則でどうにでもなるとは思いますので気になる人だけ次に進むとよいでしょう。

複雑化させる仕組みは必須ではないと思います。


まじめに実装する

dialectという拡張する仕組みがどうやらあるぽいです。全ソースコードを載せます。

import java.text.NumberFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.context.IContext;
import org.thymeleaf.context.IExpressionContext;
import org.thymeleaf.dialect.IExpressionObjectDialect;
import org.thymeleaf.expression.IExpressionObjectFactory;

public class Thymeleaf3 {

    public static void main(String[] args) {

        //----------------------------------------------------------------------
        //追加したいユーティリティ
        //----------------------------------------------------------------------
        class OreOreUtil {
            public String num(int param){
                NumberFormat nf = NumberFormat.getInstance();
                return nf.format(param);
            }
        }
        
        //----------------------------------------------------------------------
        //「#oreore」という名前でOreOreUtilにアクセスさせるためのしくみ
        //----------------------------------------------------------------------
        class OreOreDialect implements IExpressionObjectDialect{
            
            final static String KEY = "oreore";
            
            final Set<String> names = new HashSet<String>(){
                {add(KEY);}
            };
            
            @Override
            public IExpressionObjectFactory getExpressionObjectFactory() {
                return new IExpressionObjectFactory() {
                    
                    @Override
                    public Set<String> getAllExpressionObjectNames() {
                        return names;
                    }

                    @Override
                    public Object buildObject(IExpressionContext context, String expressionObjectName) {
                        if(KEY.equals(expressionObjectName)){//名前が一致したなら
                            return new OreOreUtil();
                        }
                        return null;
                    }

                    @Override
                    public boolean isCacheable(String expressionObjectName) {
                        return true;
                    }
                };
            }

            @Override
            public String getName() {
                return "OreOreUtilDialect";
            }
        }
        
        //----------------------------------------------------------------------
        //ここから下が実行
        //----------------------------------------------------------------------
        
        
        //準備
        TemplateEngine engine = new TemplateEngine();
        //オレオレ設定追加
        engine.addDialect(new OreOreDialect());


        String template = "[[${#oreore.num(a+b)}]]";


        Map<String, Object> params = new HashMap<>();
        params.put("a", 1000);
        params.put("b", 20000);

        IContext context = new Context(Locale.getDefault(), params);

        //生成
        String result = engine.process(template, context);

        //出力
        System.out.println(result);
    }
}

実行結果は同じです。

21,000

#oreore.num()でアクセスできているのがわかりますね。

2014-05-21

[][][][]JavaしかかけないおいらがiPhoneアプリをリリースするまで

今回の内容は前回よりだいぶましだぞ・・・。

の続きになります。

正直実装的にはmixiアプリ第2弾のエントリ(GWT+Flash+JavaSEとの互換レイヤでサクサク開発)が飛びぬけていると思いますが、それ以来くらいのインパクトはあると思います。


長文です。


iOS版を開発するぞ

マモノバスター2のAndroid版は無事だせました。読んでない人は上に並んでる過去のエントリを読んでみてください。

AndroidはJavaSEと同じJava言語ということで、JavaSEと互換のレイヤーを作成して、JavaSE上で開発、そのままアプリのソースは変えずにAndroid版を生成するというものでした。

やはり、Androidと並ぶプラットフォームであるiOS版もださないと片手落ちだろうと。ゲーム機と違ってAndroidとiPhoneを同時に所有している人は少ないはずです。ガラケー時代もそれが理由で遊べないゲームはたくさんありましたし。

問題は開発プラットフォーム選択だけでした。

ObjectiveCは短期的に習得できる状態ではなく、Unityは自分との相性は最悪です。cocos2d-xは触るならver3かなぁ、ver2は触りたくないなぁということで、なかなかいいのがありません。

そこで、思い出します。急激に成長をしているiOS向けの開発環境を。


RoboVM、君に決めた!

そう、RoboVMです。

http://www.robovm.org/

Javaで描いたコードがiOS向けに動きます。シミュレータ用にx86ももちろん出力できます。

パフォーマンスもかなり良好で、iPhone4s/iPod touch5(Apple A5搭載。初代miniもおそらく)でAndroidの現行のハイエンド並のなめらかさ。ただし、負荷が高い部分では差が出ますが、60fpsが安定して出たりします。

RoboVMのいいところはGWTと違い、ソースコードからのジェネレートではなく、コンパイルしたあとのclassファイルから生成されるという点です。したがってjarファイルの既存のライブラリをRoboVMに食わせるとそのまま動きます。びびるくらい動きます。

RoboVMのサンプルコードを書いてみましょう。iOSの開発者は多分、これが何をしているかすぐにわかると思います。

UIButton button = new UIButton(new CGRect(0, 0, 160, 50));

button.setTitle("ぼたん", UIControlState.Normal);
button.setBackgroundColor(UIColor.colorDarkGray());
button.addOnTouchUpInsideListener(new UIControl.OnTouchUpInsideListener() {
  @Override
  public void onTouchUpInside(UIControl uic, UIEvent uie) {
    System.out.println("くりっくした!");
  }
});
window.addSubview(button);

JavaのIDEは非常に優れているため、さくさく補完だけでホイホイ進んでいけますね。

また、サポートされている範囲はGWTの比ではなく、まず問題にならないレベルでサポートされています。恐らくびっくりすると思います。

生成されたipaにjarファイルがありますが、ここにクラスファイルは一切入っていません。たんなるリソース参照用にディレクトリなどがそのままの構造で彫ってあるみたいです。便利ですね。Androidもassets使わず、自動でやってくれるといいのにね。

ちなみにあの有名なJavaFX for iPadもRoboVMを利用しています。サンプルプロジェクトを作るとわかりますが。自分が見たやつはかなり古いバージョンだったと記憶しています。



libGDX、が勝利のカギだ!

RoboVMはいいのですが、JavaSEで実行できる開発環境がなくてはいけません。いちいちシミュレータとか実機起動などたるいことはやっていられないのです。そんな環境で開発している人はいないとは思いますが。

とはいえ、クロスプラットフォームの環境を今、しかも慣れない環境で作るには限界があります。

そこで、クロスプラットフォームで有名なプロダクトに手を出します。

みなさんご存じlibGDXですね。歴史もそこそこあります。最近ぽっと出てきたわけではありません。

http://libgdx.badlogicgames.com/

libGDXはもともとWindows/Mac/Linux/Android/HTMLに対応しています。

iOSも以前はXamarin経由で出力できていたのですが、お金が勿論かかりますし、パフォーマンスもよいとは言えませんでした。

それが去年の夏くらいからRoboVMに対応していきました。こちらも恐ろしいスピードで。昨年末には十分使い物になる感じでした。これでいきます。


libGDXはゲームエンジンや統合開発環境とかいった御大層なものではなく、ただのフレームワーク、ライブラリです。Jarファイル(や環境によってはsoファイル)を配備するだけで環境が整います。クロスプラットフォーム系でこれほど簡単に開発環境が整うのも珍しいと思います。JavaSE版はjarを4ついれるだけの超簡単なものですので試してみてもよいでしょう。AndroidやiOS版(RoboVM)もほんの少しのファイルをクラスパスに入れるだけです。


普段はこのようにJavaSEでそのまま動くので、コードを修正したら一瞬でアプリ起動でさくさく動作確認。

http://shinsan.s3.amazonaws.com/diary/2014/0520-01.png

トライアンドエラーがやりやすいので便利ですね。


HTML5出力というのはGWTを利用しているようです。細かく動かして確認したわけではないのですが、GWTはそれなりに長く追っていたので使い勝手はわかっているため、大体想像はできます。PC向けでWebで出したいのなら少しはありかもしれません。ただし、言語的にRoboVMやAndroidのように気軽にJavaSEという感覚で使えるほどサポートされていませんので、HTML5版を含めて完全にクロスで出力できるとは思わないほうがいいでしょう。


バージョンについて

RoboVM、libGDXともに活発なのでどんどんバージョンアップしていきます。

まずは安定バージョンで開発しました。

当時の安定板はlibGDXが0.9.9、RoboVMが0.0.9でした。Xcodeは5.0です。


ナイトリーでは便利な機能がどんどん追加されていくのがわかっていましたが、互換性も失うところもありました。そのため、リリース間近までこのまま開発していきます。

libGDXの次の正式版が出ました。しかし、ぎりぎりまでひっぱります。開発がほぼ終わった段階で移行しました。1.0.0です。それに合わせて対応しているRoboVMもあげました。0.0.11です。Xcodeは5.1です。

このバージョンに上げることによる変更点は自分はメソッド名が多少変更したという程度ですみました。が、OpenGL ESのデフォルトバージョンが1から2に変更になり、従来は設定で2がつかえたのが今は設定で3が使えるようになりました。OpenGLのコードをがりがり書いていた場合は致命傷でしたが、中/高レベルAPIを利用していたため助かりました。

RoboVMもバージョンが変わることによって大幅に変わっています。iOSへのアクセスするクラスのパッケージがごっそりかわっていました。ですが、このへんからObjectiveCのライブラリ呼び出すブリッジが非常に簡単に扱えるようになり、iOSのAPIサポートも加速していきます。

BROという仕組みなのですが、Javaのコードにアノテーションを付けることによってObjectiveCの呼び出しにマッピングします。ドキュメントが追い付いていないのでバインディングプロジェクトを参考にするとよいでしょう。


で、1.0.0に差し替えて動作を確認した翌日に1.0.1がでました。対応するRoboVMも0.0.12にあがっています。こちらも差し替えましたが、コードの修正はありませんでした。それなりに機能が増えているのも確認しました。




libGDXはプロジェクトをセットアップするツールがついているのが伝統ですが、0.0.9まではEclipseプロジェクトベース、1.0.0以降はGradleベースです。これらはRoboVMのセットアップもしてくれますので(特に後者)試してみたいと思った人はすぐに試すことができます。

NetBeansでJavaSE環境でのGradleはあまりよくないため(Mavenとかと同じ。JavaEEなどのコンテナ系だと気にならないが)、おそらく真面目に開発しようと思うならrobovmコマンドをたたいた方がわかりやすくはるかに幸せになれるかと思います。AndroidやJavaSE版もAntのほうがおそらくよいでしょう。


macのNetBeans上からビルド、シミュレータを起動可能。実機やIPA作成も。デフォルトのセットアッププログラムで生成したものをベースにGradle利用している例。

http://shinsan.s3.amazonaws.com/diary/2014/0520-02.png



ちなみに、Android版はすでにリリース済みのため、このRoboVM + libGDXではiOS版のみ出力しています。もちろん、開発はJavaSEで行っていますので、Windows/Mac/Linux上でもそのまま動きますし、出力しようと思えばAndroidもすぐにはだせます。


libGDXのバランスの良さ

アプリを書くのはlibGDXであって、RoboVMかどうかは全く意識しません。

libGDXは単なるライブラリのため、すきなように利用できるのもポイントです。

GLを取得してそのままガリガリ低レベルに書くこともできるし、高レベルの2Dのシーングラフ、ウィジェットAPIもあります。その一部の高レベルAPIであるノード部分の描画だけを低レベルなGL直で処理してもいいですし、中レベルAPI?(勝手に命名。ウィジェットとGL直の間)で描画することもできます。中レベルAPIはラッピングをしていて、GLを知らずに基本的な描画が可能です。たとえば中レベルAPIのTextureクラスもGLのテクスチャIDをダイレクトに取得可能にしてあるあたり、ボトルネックができたら逃げる道がある、という考え方なのでしょう。

こういった柔軟なことができるバランスの良さが広く支持されている理由だと思います。

あ、そういやなぜか日本だけ知名度ないですね。トレンドみるとcocos2d系は中国韓国(大きく離れてアジア)だけ突出しているっぽい(というか中国が多すぎてなんでも圧倒するけど)のに対して、libGDXはエリアが割とばらけていてアメリカやヨーロッパが多い感じですね。


個人的にはシーングラフを利用しつつ、高レベルコンポーネントの使用をほとんどしない、というのが一番良いと思っています。拡張はいくらでも可能なので、思い切って利用するActor(シーングラフのノードの基本単位)を大きく絞るとよいでしょう。

個人的なベストはベースとなるクラスのActorのほかは以下の3種類のみに絞ることだと思います。

  • Group系(Actorを載せる他のAPIでいうPanel系)
  • ScrollPane
  • Image(癖があると思うのでActorを継承して自前でテクスチャを描画したほうがわかりやすい可能性も大)

多言語化とかスタイルとか闇がありそうなそのへんに振り回されないもの、という意味で。ゲーム用途ならこれで十分でしょう。


とりあえず、8bit時代のBASICとか16bit時代のC言語とかでガリガリゲーム作れた、ソースコードを打ち込んだことがある、という人はlibGDXを利用すれば簡単に当時の感覚でゲームが作れますよ。それもiOS、Android、Mac、Windows、Linuxで60fpsでさくっと動かせるものが。基本的にOpenGLとかは知る必要はありません。


自分がどれだけlibGDXに惚れこんでいるかといえば、スマホ向けに出力する予定が全くない、PCでのみ動けばよいアプリを開発する場合もlibGDXを採用するだろう、といえばわかるでしょうか。


今回は移植という形でしたが(それでもロジック部分は同じJava言語のため6割はもってこれてる)、次からは最初からAndroidとiOSを同時にリリースするつもりで作っていきます。

2012-02-28

[][][]PCエンジンイース1/2の製作秘話本

PCエンジン版イース1/2の制作秘話の同人本。レトロゲーム・PCに興味がある人にオススメの同人本である。

PCエンジンCDROMのソフトで代表的なものは?ときいたら10人中8人はイース1/2と答えるだろう。


それだけ有名なソフトの開発秘話。開発者である岩崎啓眞氏自身の手で書いてある。


電子書籍版、イースの同人誌を出しました


一部のページを読むことが出来るのでよんでみるといい。お試し読みも上記リンクにある。

レトロPCが好きな人にもオススメと書いてあるとおり、当時はわりとPCもコンシューマも近かったと思う。ハードに興味がある人も呼んでおいて孫はない。もちろん、PCエンジンのイース1/2を知っているほうがいいけど。

お試しの一部を転載してみる。

イースの製作が始まるほんの少し前。

1989年1月ごろ。ハドソンの技術部も、そして外注で仕事をした会社も、みんなCDROMに絶望していた。

なぜなら、どうしようもなくメモリが足りなかったからだ。メインメモリはたったの64キロバイト。当時良く使われたビット表現をすると0.5メガビットだ。

これでは、なにも出来ない。

雑誌では540メガバイトの無限の容量を誇る夢のメディアと宣伝されてはいたけれど、ハドソン技術部では「オチョコで海の水をすくうようなモノ」と揶揄されていた。

CDROMの大容量といううたい文句とは裏腹に、バッファとして読み込む領域が狭いことによるつらさがよくわかる。

でも、今にして思うと少ない容量だからこそPCエンジンのCDROMはロード時間が短かったものが多かった。PSとか後の時代になると倍速にはなっていたものの、非常にロード時間が長いソフトが多かった。PCエンジンCDROM2並の快適さを期待すると裏切られることが多かったのだ。

この流れはPC88版のソースコードを読んだ人間には明らかな事実だが、そんなものを見る術のない普通のユーザーも、この驚きの事実をファミコン(FC)版イースのダルク・ファクトによって知ることが出来る。

というのもFC版のダルク・ファクトはオリジナルではソースにしかなく、ゲームでは表示されないメッセージを復活させて、どのようなストーリーなのか明白にネタバレするからだ。

オリジナルのソースをよんだことがある人だけがわかるネタだ。こういうのがあるから面白い。


購入はAmeroadがオススメ。

Googleアカウントを持っている場合はGoogleウォレットでの購入のほうがいいだろう。手数料も安いし。Androidを持っている人はみんなGoogleのアカウント持っているはずなのですごく手軽に買えるぞ。

2011-12-04

[][]Javaしかかけないおいらがmixiアプリ第4弾をリリースするまで

やっとマモノバスターが公開されました。

http://shin.cside.com/diary/2011/1119-03.png

マモノバスター

マモノバスターの開発にまつわるお話をお聞かせしましょう。長文です。


開発の始まり

このプロダクト、もともとはmixiアプリ第2弾のPONPONが開発完了した後から取り掛かっています。

http://shin.cside.com/diary/2011/0209-01.png

PONPON


つまり2月ぐらいから。それが11月末になってやっと出来上がったわけです。


間にはmixiアプリ第3弾のコレオススメ!を挟んでいますが、それは予定にありませんでした。


本来マモノバスターが第3弾になるはずだったのです。

震災・・・そして方向を見失う

開発中の3月に震災が起こりました。この後急激にやる気を喪失していましたが、開発はだらだら続けていました。

進みは遅いものの、モックはそれなりに完成していました。フォントを1から作成しておりかなり気合が入っていたのがわかります。

http://shin.cside.com/diary/2011/0611-01.png

開発中のRPG


が、もともと完成していた内容をイメージし切れておらず、昔のRPGのようなもの、という漠然とした内容、なにがうりになるのかそういうものがすっぽりと抜け落ちていました。RPGを作る、以外は何も考えられていなかったのです。

そのくせスマホに初対応するということで、機種ごとのレンダリングや動作の差異に悩まされました。PCだけだったらすぐに完成していたのですが、それをPCとスマホに対応させてそれぞれ同じような動作となるとかなり難易度が高かったです。

スマホとPCと両対応するということはサーバーを自分で持つことも必要になります。サーバー側の実装コストも膨らむでしょう。


クラス数は膨大になり、何も考えずつくっていったのでどこを削るか、といったことも判断できず、まとめきれなくなっていきました。一番売り出したいものがしっかりあれば、それ以外を削るといったことも出来たでしょうが、そうではありませんでした。

これはいったん止めないと収拾がつかなくなる、と思いました。


開発をいったん停止、第3弾を差し替え

そこでいったんRPGの開発をストップさせることにしました。

一人で開発している場合、問題はないのですが、モンスターデザインはイラストレーターの名無子氏にお願いしている以上、一時停止でも勇気のいることでした。

そこでまず名無子氏のデザインをアピールできるシンプルなアプリを用意しようということにしました。それがコレオススメ!です。

http://shin.cside.com/diary/2011/0930-01.png

コレオススメ!

このアプリはRPGで技術的にも一気に飛ぶのではなく、クッションをはさむという目的でもありました。

それはPONPONまでやっていなかったこと、つまりスマホとサーバーの処理の実装です。

クライアントサイドはGWTで問題がなく、ストレージもmixiのサーバーを利用することで自分のサーバーの負担をほぼなしで運用することが出来ますが、スマホを扱うとそういったことは不可能になります。

ここで利用した技術/製品は以下の通りです。

  • GWT 2.4
  • EJB 3.1 lite
  • JAX-RS 1.1
  • JPA 2.0
  • JerseyClient
  • Glassfish 3.1
  • PostgreSQL 9
  • AWS EC2
  • AWS CloudFront

GWTもPONPONまではガジェットプラグインというGWTのプラグインを利用していましたが、これをやめました。不具合も多くGWTの細かいバージョンアップについていけなくなっていたためです。これも結構厄介でした。

EJB3.1やJPA、JAX-RSは問題ありませんでした。これらの製品が開発効率でもすぐれているのはわかっていたからです。OAuthはやっつけでサーブレットフィルターで実装しています。本当はJAX-RSつかっているならこれはだめな設計です。

JerseyClientはHTTPのクライアントです。非常にシンプルでこれ以外はもうありえないというレベル。Oauthプラグインを入れることによってmixi鯖への問い合わせも簡単に出来るようになります。

CloudFrontはPONPONで利用しており、ColorBlockも後に利用するように修正したので問題はありませんでした。

などなど、内容は比重にシンプルなアプリではありますが、技術一つ一つをクリアしていきました。

そして9月に公開されます。本当は8月の予定でしたが、体調不良の時期があり、その分伸びてしまいました。


RPG開発再開

そして次こそRPG!ということで開発をはじめます。

まず従来のソースや画像等をすべてないものとしてゼロから開発しました。

システムもすべて一新。スマホに特化したシステムにし、PC版はそのべた移植とすることに決めました。

やりたいことがしっかりと決まっていたので開発は楽でした。なにせ前回の開発時にほとんどの技術はすでにクリアされており、実装のみに集中できたからです。

その結果、マモノバスターは一ヶ月ちょっとでスマホの開発がほぼ終わります。震災がありながらも4ヶ月がたっても実装できていない前回とはあきらかにスピードが違いました。

その後バランス調整やアニメーション等の調整が続きました。3週間くらいでしょうか。結果、すべてこみこみで2ヶ月で開発が完了しました。PCへの移植は3日だけでした。

タイトルをマモノバスターに決めました。

これは前から決めていたのですが、id:Florian氏のRPGでケモノ学園というものがあります。これはグラフィックは同じ名無子氏が担当しており、それに対抗すべくこちらもRPGを持ち出したという経緯があります。なのでタイトルもそれっぽくということでケモノ=>マモノときまりました。

マモノという単語だけではどうしようもないので、適当につなげてそれっぽいものということでマモノバスターになりました。マモノとつく作品は割と多く、まものクエストというMSXでは有名なRPGがあったのでクエストはだめだな・・・とかまものスレイヤーはたしかあったな・・・とか考えてマモノバスターはたぶん大丈夫だな、という安易な考え方でした。ドラゴンバスターの影響を受けてるのは間違いないかもです。

ほかにも影響を受けている作品は多く、それはダンジョン名や武器名にでています。失われた宮殿はハイドライド3のですし、どくろのつえやこれから出るであろうドリームスタッフはハイドライド2の影響です。


技術的には今回はEJB3.1を利用するのをやめてCDIを利用しました。通常CDIと併用することが多いと思いますが、CDI+UserTransactionで実装しました。OAuthのフィルターはJAX-RSのFilter(正確にはJerseyか)を利用しました。

また、CanvasのAndroidの不具合のため、すべてHTML4ベースに修正しました。結果、IE6でも多少の手直しだけで動いたので結果オーライですが、座標系はそれなりに崩れます。


そして公開されました。ゲームとして面白いように調整した結果、サーバーの負荷は大幅に増えていますが、まぁ仕方がないでしょう。


そしてスマホ版は先月末、PC版は1日に公開されました。


すべてはGWT

いまのところすべてのmixiアプリはGWTを利用しています。今後も利用する予定で、ロジックをきっちり作る場合に威力を発揮します。

GWTというのはJavaソースコードからJavaScriptを生成する仕組みです。出来上がるのはJavascriptなため、ApacheやAWSのS3など静的ファイルをおくことさえ出来ればどこでも利用できます。このJavaScriptや画像などをAWSの高速なCloudFrontで配信しています。S3と比べても高速なのでぜひ利用したほうがいいです。

「動的なページ」ではなく「Webアプリ」を作るうえでは最高の環境だと思います。ブラウザごとの差異や最適化を自動でしてくれるのも特徴です。ファイルそのものが分割されており、自分のブラウザにあったものが自動でロードされます。また、遅延ロード等もコードで簡単に作ることも出来ます。Java言語を使いこなせる人はぜひとも習得しておきたい技術です。

なんせ、ColorBlockやPONPONはJavaアプリ版(Swing)で作ったのをそのままもってきています。特にPONPONはSwing版と1文字もゲーム部分はコードが変わっていません。Javaでプロトタイプからコンバート後の製品出力まで出来るのは強みですね。

一方、コレオススメ!やマモノバスターではそういったことをしていません。ゲームにmixiのAPIに絡む部分が入りやすいってのもありますが、スマホ版をメインとしており、パフォーマンスや出来ないことも多いので単純に移植が出来ないため試行錯誤が多かったという理由もあります。

次回作がPC専用アプリの場合Swingで動くスタンドアロンなJavaアプリで作成しつつ、コンバートという方向になると思います。サーバーサイドはJAX-RSですので通信含めてJavaのみで開発を完了させておくといったこともありかもしれません。また、スマホもある程度はわかってきたのでそれを考慮してのコンバートも出来るかもしれません。


開発時間としては目安としてColorBlockが20時間、PONPONが40時間、コレオススメ!が40時間。

マモノバスターは60時間といったところです。未完成だったRPGは80時間は越えていたと思います。趣味プログラムとしては規模は80時間くらいが限界かなという感じです。

2011-02-17

[][][]ゲーム製作雑誌がまぐ!2号登場!

これかくのわすれてたわー。

https://sites.google.com/site/gamagreader/


今回もid:Florian氏の圧力により投稿しています。しかもおいらがまともなゲームを作るはずもなく。

ゲームとしてはよっぱらい系というスタンダードなものですが、操作にマウスホイールのみを利用します。この独特のアナログ感をお楽しみください。Swingの標準APIのみでマウスホイールの処理取れますのでそこを参考にしてもらえれば。

ソース的には前回よりはややオブジェクト指向よりになっています。クラス名の先頭にプリフィックスがついているのはデフォルトパッケージ縛りがあるためです。もともとは前作もパッケージが別だったのでした。


ホイールのグリップが強めのマイクロソフト形のマウスがお勧めです。ホイールが使いにくいIBM系とかだときついでしょう。スライド系はもうお手上げです。

このように環境に激しく依存するソフトです。


ソースコードを打ち込むのはいやだが、ゲームだけは遊びたいという方はこっそりここから落としてください。JRE6があればダブルクリックで起動できます。


力の1号、技の2号ときたので次はダブルタイフーンの強力な3号が来ること間違いなしですね。

2010-12-28

[][]がまぐの強み

雑誌ってのは毎号買う人もいれば買わない人も多いですよね。

となると連載にはついていけない人も多いというわけです。毎号かってもらうために連載というものがあるのでしょうげ、前提となる知識が持っていない号にあるばあい、読者は興味のない記事としてマークします。そして記事に魅力がないのが多くなると雑誌そのものを買わなくなる理由にもつながります。

前号を前提とする連載記事だけでは成り立たないのです。実際今発売している雑誌のほとんどは特集がメインのはずです。ページ数もかなり取っていることと思います。

また、たいてい入門記事は春を基準に書かれます。次の年の春が近づくとまた入門記事を書きます。内容がダブることも珍しくありません。



で、がまぐですが、無料です。

ということは前号を見逃していても大丈夫ということです。かならず古い号を参照できます。連載があっても問題が少ないということです。

そして、同じネタは書かなくてもよいということでもあります。もちろん、新しい年を迎えることによって新しい技術なども出てきますので単純にはいえませんし、書き手によってかなり違う内容になることも珍しくありませんが、これ数年前の入門記事の焼き直しだよ、といったことをする必要がないです。

特に連載は積極的に狙っていったほうがいいのではないでしょうか。そのかわり1つの号の記事はかなり短くすることを念頭において。ボリュームを増やすよりも適度にぶつ切りにして次の号に積極的にまわすとよいでしょうね。号数が増えると作っているという感覚が強いですし。

何より創刊号はかなりスピーディーでした。最初の呟きが10月下旬。まさかの2ヵ月たっていません。こういうのは鉄は熱いうちに打て、ということで勢いのあるうちにさっさとやってしまったほうがいいのですね。期間を先にガッツ利とたとえば年4回発行するから3ヵ月後とかやってるとおそらく終わりません。ページ数はなんとなく増えていきますが・・・といった感じで分解するでしょう。創刊号はうまく出たとしても2号はないわけです。

そこがid:Florian氏の腕なのでしょうね。

ページ数が100を超えたら出してもいいくらいの勢いでかまわないと思います。


あと、Twitterですべてきまるのはまぁいいとしても、ユーザーからの問い合わせがメールのみなのがちと敷居が高い。メーリングリストとか普通だと思っている人も多いですが、やはり厳しいものがあります。掲示板などで「ここのソースコードの意味がわからないんだけど」といった事が気軽に聞けるようになるといいですね。

そういうのはmixiとかでコミュニティ作るのが一番あっているのかもしれませんね。低年齢層のmixi普及率はかなりのものですし、共通の話題を話すという場は雑誌とは離れた場所であってもかまわないと思うのです。

2010-12-24

[][]がまぐへのリンクがあったほうがいいかな

「ゲーム制作雑誌 執筆者+読者サイト」って、完成したがまぐへのリンクが見当たらない。完成しました!見たいな感じにしておいたほうがよいかな。一連のtwitterなどのながれだとこちらのサイトのほうしか見つからないので。


あとソースコードはやはり90度回転の2段表示がいいですね。A4は長いほうが短いほうの1.5倍ありますので多少の折り返し程度だとやっぱり大きな差が出ます。

ほかには記事と投稿プログラムとの間に1枚見出し用にはさんだほうがよいと思いました。いきなり投稿プログラムがきますのでわかりにくいです。ベーマガのように「えいっ」て髪の毛をひっこぬいている絵があるとよいですね。


2011年春号?ではこの辺も調整してほしいところです。