.NETでXMLを活用していきます。

ファミコン風ドット絵にグッときてしまった

»

ファミコン

 ファミコン……ああ懐かしい響きですね。そうです。任天堂のファミリーコンピュータです。実は先日、こんなブログ記事を発見してしまいました。

 「ドット絵マリオクッキー - メロウマイマインド

 う何かピコーンと閃いて、以下のような「実行プラン」が、天から降ってきました。

 「ドット絵マリオクッキー - メロウマイマインド」 + 「ファミコンカラーパレット」 + 「XML」 + 「XSLT」 = (^^)

 れでは、実際にやってみます。

データの持ち方

 ット絵のデータの持ち方ですが、とりあえずパレット4色を「0~3」に割り当てて、属性として持たせました。

■Mario.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8" ?>
<
root>
    <
row value="00000000000000"></row>
    <
row value="00001111100000"></row>
    <
row value="00011111111100"></row>
    <
row value="00022233230000"></row>
    <
row value="00232333233300"></row>
    <
row value="00232233323330"></row>
    <
row value="00223333222200"></row>
    <
row value="00003333333000"></row>
    <
row value="00022122200000"></row>
    <
row value="00222122122200"></row>
    <
row value="02222122122220"></row>
    <
row value="03321311312330"></row>
    <
row value="03331111113330"></row>
    <
row value="03311111111330"></row>
    <
row value="00011100111000"></row>
    <
row value="00011100111000"></row>
    <
row value="00222000022200"></row>
    <
row value="02222000022220"></row>
    <
row value="00000000000000"></row>
</
root>

 んだかうっすらとですが、ドット絵の内容が確認できますね。

 XSLTファイルはこんな感じです

■Mario.xslt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version="1.0" encoding="utf-8"?>
<
xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <
xsl:output method="html" indent="yes"/>

   
    <
xsl:attribute-set name="cellsize">
        <
xsl:attribute name="width">20</xsl:attribute>
        <
xsl:attribute name="height">20</xsl:attribute>
    </
xsl:attribute-set>
    <
xsl:attribute-set name="cell0" use-attribute-sets="cellsize">
        <
xsl:attribute name="style">background-color:#000000;</xsl:attribute>
    </
xsl:attribute-set>
    <
xsl:attribute-set name="cell1" use-attribute-sets="cellsize">
        <
xsl:attribute name="style">background-color:#DB2B00;</xsl:attribute>
    </
xsl:attribute-set>
    <
xsl:attribute-set name="cell2" use-attribute-sets="cellsize">
        <
xsl:attribute name="style">background-color:#8B7300;</xsl:attribute>
    </
xsl:attribute-set>
    <
xsl:attribute-set name="cell3" use-attribute-sets="cellsize">
        <
xsl:attribute name="style">background-color:#FF9B3B;</xsl:attribute>
    </
xsl:attribute-set>


    <
xsl:template match="/root">
        <
table border="0" cellpadding="0" cellspacing="1">
            <
xsl:apply-templates select="row">
            </
xsl:apply-templates>
        </
table>
    </
xsl:template>


    <
xsl:template match="row">
        <
tr>
            <
xsl:call-template name="countup">
                <
xsl:with-param name="prmcount" select="1" />
                <
xsl:with-param name="len" select="string-length(@value)" />
            </
xsl:call-template>
        </
tr>
    </
xsl:template>


    <
xsl:template name="countup">
        <
xsl:param name="prmcount"/>
        <
xsl:param name="len"/>
        <
xsl:choose>
            <
xsl:when test="substring(@value,$prmcount,1) = '0'">
                <
td xsl:use-attribute-sets="cell0"></td>
            </
xsl:when>
            <
xsl:when test="substring(@value,$prmcount,1) = '1'">
                <
td xsl:use-attribute-sets="cell1"></td>
            </
xsl:when>
            <
xsl:when test="substring(@value,$prmcount,1) = '2'">
                <
td xsl:use-attribute-sets="cell2"></td>
            </
xsl:when>
            <
xsl:when test="substring(@value,$prmcount,1) = '3'">
                <
td xsl:use-attribute-sets="cell3"></td>
            </
xsl:when>
        </
xsl:choose>
        <
xsl:if test="$prmcount != $len">
            <
xsl:call-template name="countup">
                <
xsl:with-param name="prmcount" select="$prmcount + 1" />
                <
xsl:with-param name="len" select="$len" />
            </
xsl:call-template>
        </
xsl:if>
    </
xsl:template>
   

</
xsl:stylesheet>

いです。68行あります。長くなった理由は、「XSLTの限界」を突破するために必要だったからです。ではこれから、「XSLTの限界」の説明と、その「解決法」を順番に見てきます。

XSLTの変数は上書きできない

 つ目の限界は「XSLTの変数は上書きできない」ということです。つまり、定数(constの変数)として存在するので、変数の内容を後から上書きできません。この動かせない事実が、様々なところで問題になります。

 えば今回の例でいうと、ループ処理で問題になりました。ドット絵のデータは1行14ドットで、全部で19行あります。単純に考えると、19回のループ中に14回ループを入れて処理する必要があります。19×14=266回の変換です。C#やJavaScriptで処理を書くならば、ループ変数「i」と「j」などを定義して、現在処理している位置をループによってずらしていくのがパターンでしょうか。しかし、XSLTでは変数の上書きができないのです。

for-eachは属性値のループに使用できない

 つ目の限界は「for-eachは属性値のループに使用できない」ということです。もっと詳しく言うと、「for-each」はノードの集合に対して使用するものであるため、「00001111100000」という属性値を1文字ずつ処理することができません。

 性値のループができないなら、属性値のデータを1ドットずつばらしておけばいいのでは? ……確かにそれで解決です。しかし、それでは全然面白くないので、少々「あがいてみる」ことにしました。「何とか抜け道はないものだろうか?」と。

再帰処理を使う

 えは、再帰処理でした。実行プランはこうです。

  • 「ループの回数」と「現在の値」を引数に持つテンプレートを用意する
  • テンプレート内で「現在の値」を1ずつ変化させて自分自身を呼ぶ
  • 「ループの回数」になるまで自分自身を呼び続ける

 XSLTのファイル上では、具体的には42~65行目の処理になります。

 帰処理は、「処理の終了条件」を特に注意しないと、無限ループになる可能性があります。今回は、それほど複雑な処理は行っていないので、まったく問題ありません。

トランスフォーム

 よいよ実行します。F5

 PlayStation3の豪華なグラフィックには到底及びませんが、カクカクのドット絵もまた、味があっていいですね。

Comment(0)

コメント

コメントを投稿する