なでしこを明後日の方向に

日本語プログラム言語なでしこを応援しています

なでしこでテトリスの回転やSRSのテーブルを生成する

前回の続きです

(前回) なでしこでテトリスブロックをスーパーローテーションさせる - なでしこを明後日の方向に

回転テーブルはプログラムで作る!

テトリスのブロック回転の実装方法を検索すると、回転結果をテーブルとしてソースに直打ちしているものをよく見かけます。

SRSのほうは条件分岐をひたすら打ち込んでいるものも多数あり、長くなっているものが多い気がします。

プログラムでテーブルを作成することによって、SRSを短いコードで実装する方法を考えます。

完成プログラムと図

投稿してきました。
とりあえず実行すると、ブロックが回ります。

n3s.nadesi.com

回転と左右反転

あとで使うので右回転左右反転の関数を置いておきます。 なでしこ3のインデント構文で書いています。

●右回転(ブロックを)
 ブロック[0,0]1ブロック回転
●左回転(ブロックを)
 ブロック[0,0]-1ブロック回転
●左右反転(vを)
 変数 結果 = []
 v反復
   x,y = 対象
   結果[-x,y]配列追加
 結果戻す

//回転方向:1=右 それ以外=左
//新しい配列を生成して返す
●ブロック回転(ブロックを,回転中心で,回転方向に)
 結果 = []
 変数 [中心X, 中心Y] = 回転中心
 もし回転方向=1でなければ、回転方向=-1
 
 ブロック反復
   x,y = 対象
   
   x,y = [x-中心X, y-中心Y] //中心を引く
   x,y = [-y*回転方向, x*回転方向]   //回転する(回転方向は+1が右、-1が左)
   x,y = [x+中心X, y+中心Y] //中心を足す
   
   結果[x,y]配列追加
 結果戻す

回転結果のテーブルを作成する

初期値だけ書いておき、 x,y = [-y,x] で右回転すればOKです 前回の記事を参照。

以下は初期の回転軸を[0,0]としたブロックの中心です。

//なでしこ3 ブロック7種初期値
ブロック初期値={}
ブロック初期値["T"]=[[0,0],[1,0],[-1,0],[ 0,-1]]
ブロック初期値["L"]=[[0,0],[1,0],[-1,0],[ 1,-1]]
ブロック初期値["J"]=[[0,0],[1,0],[-1,0],[-1,-1]]
ブロック初期値["S"]=[[0,0],[1,-1],[-1,0],[0,-1]]
ブロック初期値["Z"]=[[0,0],[1,0],[-1,-1],[0,-1]]
ブロック初期値["I"]=[[-1.5,-0.5],[-0.5,-0.5],[0.5,-0.5],[1.5,-0.5]]
ブロック初期値["O"]=[[0.5,0.5],[-0.5, 0.5],[-0.5,-0.5],[0.5,-0.5]]

これを右回転させた座標を使えばプログラム内でテーブルを生成できます。

SRSの回転中心テーブルを生成する1(棒以外)

完成形はこれです。(棒以外)
これを中心に回転するとSRSが実装できます。

この表の左上を初期値として、右回転と左右反転でテーブルを完成させることができます。

[棒以外・状態0・左回転] = [[[0,0],[0.5,-0.5],[0,-1],[1,1],[1.5,0.5]]
[棒以外・状態0・右回転]は上記を左右反転
[棒以外・状態1・左回転]は上記を右回転
[棒以外・状態1・右回転]は上記を右回転
[棒以外・状態2・左回転]は上記を右回転
[棒以外・状態2・右回転]は上記を左右反転
[棒以外・状態3・左回転]は上記を右回転
[棒以外・状態3・右回転]は上記を右回転

//なでしこ3
定数 SRSテーブル1 = SRSテーブル1作成
●SRSテーブル1作成 //棒以外
 変数 table = [] //戻り値 
 変数 a = 0  //回転状態 0~3
 変数 v = [[0,0],[0.5,-0.5],[0,-1],[1,1],[1.5,0.5]] //通常回転[0,0] とSRS1~4(状態0の左回転)
 
 a0から3まで繰り返す
   table[a]=[]
   table[a][0]=v //table[状態][左回転]
   もしa=0またはa=2ならば
     v=v左右反転
   違えば
     v=v右回転
   table[a][1]=v //table[状態][右回転]
   v=v右回転
  //↑ vを左右反転・右回転・右回転・右回転・左右反転・右回転・右回転・右回転 の8回
 
 table戻す

SRSの回転中心テーブルを生成する2(棒)

完成形はこれです。(棒)

まず棒の状態0を初期値として手入力します。

[棒・状態0・左回転] = [[0,0],[-0.5, 0.5],[ 1.0,-1.0],[-1.5,-0.5],[ 1.5,-0.5]]
[棒・状態0・右回転] = [[0,0],[-1.0,-1.0],[ 0.5, 0.5],[-1.5,-0.5],[ 1.5,-0.5]]

この2つを基準として、右回転+2つを入れ替えしていきます……これは画像かプログラムを見た方が早い

定数 SRSテーブル2 = SRSテーブル2作成
●SRSテーブル2作成 //棒
 変数 table =[] //戻り値
 変数 v0 = [[0,0],[-0.5, 0.5],[ 1.0,-1.0],[-1.5,-0.5],[ 1.5,-0.5]] //[状態0][左回転]
 変数 v1 = [[0,0],[-1.0,-1.0],[ 0.5, 0.5],[-1.5,-0.5],[ 1.5,-0.5]] //[状態0][右回転]
 変数 a = 0
 
 //a = [回転状態]
 a0から3まで繰り返す
   table[a]=[v0,v1] //[左回転時,右回転時]
   v0,v1 = [v1右回転,v0右回転] //右回転してv0とv1を入替
 
 table戻す

できあがり

以上を用いて出来上がったのが最初のプログラムです。 もう一回リンクを貼っておきます。

n3s.nadesi.com

あなたのテトリスにもSRSが実装されますように!

なでしこでテトリスブロックをスーパーローテーションさせる

プログラムの練習で作るゲームといえばテトリス
ネックとなる「ブロックを回転させる」プログラムを作ります。

知ってる? スーパーローテーションシステム(SRS)

テトリスブロックを回転させるためにはSRSの存在を知らなければなりません。

ブロックを回転させたとき、何かにぶつかったら回転軸をずらして再試行する機構です。
これを実装しないと「壁けり」や「Tスピントリプル」が発生せず、テトリスの練習に使うことができません。

wikipediaにあるT-Spin Tripleの概略図
(https://ja.wikipedia.org/wiki/%E3%83%86%E3%83%88%E3%83%AA%E3%82%B9)

実践例だとこちらが見やすいと思います https://www.mintscore333.com/2018-09-05-203200/

前提

右がXのプラス方向、下がYのプラス方向、回転は角度は右回転方向とします。
回転していない状態を「状態0」として、右回転ごとに状態1・状態2・状態3とします。

初期回転軸を[0,0]としたブロックを定義する!

ここでは初期回転軸を[0,0]としてブロックを定義します。

この座標[0,0]は回転する「点」であり、「ブロックの中心点」となります。

T字ブロックは [[0,0],[1,0],[-1,0],[ 0,-1]] です。(上の状態0の図を参照)
カドの部分は0.5ズレた座標になります。

……I字ブロックは [[-1.5,-0.5],[-0.5,-0.5],[0.5,-0.5],[1.5,-0.5]]です(小声)

通常時の座標の回転

座標を回転させましょう。
座標[x,y]を回転軸[0,0]で右に90度だけ回転するのだから、一般的に回転後の座標は

 x' = x * cos(90度) - y * sin(90度)
 y' = x * sin(90度) - y * cos(90度)

で求められます。

テトリスだと90度単位しか使わないので sin(90度) = 1、cos(90度)=0で計算すると

 x' = -y
 y' = x

となります。

逆回転の場合は sin(-90度) = -1、cos(-90度)=0なので

 x' = y
 y' = -x

となります。

なでしこ3では複数変数への代入文が使えるので このように書けます。

 x,y = [-y, x]      //回転する(右回転)

回転、かんたんですね!

複数変数への代入文について(v3.2.6以降) なでしこさん マニュアル - 文法/代入文

実例

T字ブロックの状態0は[[0,0],[1,0],[-1,0],[ 0,-1]]。
右回転すると状態1の座標[[0,0],[0,1],[0,-1],[1,0]になるはず。
なでしこ3で式を入れて確認してみましょう。

[[0,0],[1,0],[-1,0],[ 0,-1]]を反復
    x,y = 対象
    x,y= [-y,x]
    [x,y]を表示
ここまで

座標[[0,0],[0,1],[0,-1],[1,0]が表示されました!

SRSに対応する回転式

テトリス99やぷよぷよテトリスなどでは、床についたT字ブロックを右回転すると、壁際に立ちます。

このとき、「ブロックは[0,-1]を中心に回転した」はずです。

中心が[0,0]でない場合、「回転の中心」を引いて、回転して、「回転の中心」を足します。
これをプログラムしてみます。

中心X,中心Y=[0,-1]

[[0,0],[1,0],[-1,0],[ 0,-1]]を反復
 x,y = 対象
 x,y = [x-中心X,y-中心Y] //中心を引く
 x,y = [-y,x]     //回転する(右回転)
 x,y = [x+中心X,y+中心Y] //中心を足す
 [x,y]を表示
ここまで

実行結果は[[-1,-1],[-1,0],[-1,-2],[0,-1]]を示しています。 これで合ってます!

Tスピントリプルの回転

Tスピントリプルの場合も中心が違うだけです。
右回転によるTスピントリプルの回転中心は[-1.5,0.5]です。
(ブロックの中心が[0,0]なので、角は0.5ずれた座標になります)

回転の中心座標テーブルを用意する

ブロックを回転した時に衝突判定をして、なにかにぶつかったら別の回転中心を使います。
[0,0]で右回転してダメだったら[-0.5,-0.5]、そこもだめなら[0,-1]、[-1,1]、[-1.5,0.5]の順に回転の中心を変更して衝突判定します。

[0,0]、[-0.5,-0.5]、[0,-1]、[-1,1]、[-1.5,0.5]

上記の座標は「T字ブロックが、状態0から、右回転するとき」の座標です。
この座標は、ブロック種類と状態と回転方向で変わりますから、座標をテーブルでもつ必要があります。

棒以外のテーブル

棒のテーブル

※ 間違いがあればお気軽にコメント欄でおねがいします
テトリスちゃんねるさんの図には間違いがあります


これで美しい残像をもったTスピントリプルが描画できそうです。

なでしこ3の正規表現マッチがなでしこ1と変わっている件

※ これが書かれたのは なでしこなでしこv3.3.83~v3.4.1あたりの頃です


私は正規表現に詳しくないので、なでしこ1の時もなんとなくで使っていました。
なでしこ3でもなんとなくで使ってみたら……なにかが違う!

たとえば、なでしこ1のサンプルにあるこのコード

「02:50:30」「(\d+):(\d+):(\d+)」正規表現マッチ
抽出文字列表示

\dが数値、+が後ろにつくとその連続、で\d+が数値の連続した部分です。
( )の中身が変数 抽出文字列に配列形式で返ってきます。

このプログラム、なでしこ3で実行すると抽出文字列に入らないんです!

続いて、このプログラム

「02:50:30」「\d+」正規表現マッチ
それ表示

なでしこ1では"02"が表示されます。
なでしこ3で"02,50,30"が表示されます。
["20","50","30"]の配列が返ってきているようです。

正規表現マッチはなでしこ1となでしこ3で非互換と言えるでしょう。

というわけで、なでしこ3の正規表現マッチがどう変わったか調べてみました。

変わっていない点

命令の引数は変わっていません。

・なでしこ1
 正規表現マッチ(AをBで|AがBに)
・なでしこ3
 正規表現マッチ(AをBで|AがBに)

変数 抽出文字列もなでしこ1、なでしこ3どちらでも変数定義されていました。

変更点「正規表現修飾子の指定方法」

正規表現には修飾子というものがあって、挙動を変えるスイッチのようなものがあります。

iを指定すると大文字と小文字を同一視する
gを指定すると複数マッチングするかを調べる

…などがあるようです。

この正規表現修飾子を指定する方法がすこし変わりました。

・なでしこ1の正規表現修飾子の指定方法

マニュアルより

修飾子を使ったマッチを行いたい場合は、Perlの形式でパターンを『m/パターン/修飾子』のように指定します。日本語(S_JIS)の文字列をマッチする場合は、オプションに「k」を追加します。

サンプルはこうなっています。

「マーチ」を「m/ー/k」で正規表現マッチ

m/で始まって、後ろの/kの部分が修飾子です。
修飾子は /gmkなどの感じで指定するそうです。

・なでしこ3の正規表現修飾子の指定方法

マニュアルより

パターンBは「/pat/opt」の形式で指定。optにgの指定がなければ部分マッチが『抽出文字列』に入る

先頭のmがいらなくなって、後ろの/optの部分を /gm とかなんかにするみたいです。

「gの指定がなければ部分マッチが『抽出文字列』に入る」とあります。
裏を返すと
「gの指定があれば『抽出文字列』に入らない」……ということ、か?

だから最初のサンプルでは抽出文字列が空だったんですかね。
もう一度最初の画像を見てみましょう。

「g」の指定は……ないです。 ないけど抽出文字列は空です。はて?

変更点「正規表現修飾子を省略した場合の挙動」

自分が正規表現マッチの命令を使うとき、修飾子を指定する形式『m/パターン/修飾子』(なでしこ1)『/pat/opt』(なでしこ3)の形で使っていませんでした。

なでしこには正規表現修飾子を省略した場合の挙動が備わっているので、それに乗っかっていたということになります。

なでしこ1で正規表現修飾子を省略した場合

正規表現修飾子という変数があり、初期値は文字列gmkです。
"g"はグローバルマッチ
"m"は複数行マッチ
"k"はSJIS対応
SJISの文章を改行を含めてまるごと見るよ」って感じでしょうか(自信無し)。

なでしこ1で正規表現修飾子を省略した場合、この変数 正規表現修飾子 が使われるようです。

なでしこ3で正規表現修飾子を省略した場合

マニュアルには書いていないので、ソースを確認しました

異国の言語で書かれていますね…… 雰囲気的に、パターンがない場合'g'を指定するって書いてあるように感じます。

ということは……省略した場合、「g」を指定したのと同じ動作をする……そして「gの指定があれば『抽出文字列』に入らない」……となります。

修飾子を省略した形とそうでない形を覚える

/パターン/修飾子』のように『/』がある書き方が修飾子を省略しない形で
パターンの前後に『/』がなければ省略した形です。

具体的には

「02:50:30」「(\d+):(\d+):(\d+)」正規表現マッチ //←省略した形
「02:50:30」「m/(\d+):(\d+):(\d+)/gmk」正規表現マッチ //←なでしこ1の省略しない形
「02:50:30」「/(\d+):(\d+):(\d+)/g」正規表現マッチ //←なでしこ3の省略しない形

そして次の形

//なでしこ3の省略しない形
「02:50:30」「/(\d+):(\d+):(\d+)/」正規表現マッチ 

これは「修飾子を省略せずに空を指定した形」です。
なでしこ3のサンプルにあるのはこの形です。

挙動のまとめ


「02:50:30」を「(\d+):(\d+):(\d+)」で正規表現マッチ

バージョン 修飾子 それ 抽出文字列
なでしこ1 省略形 文字列"02:50:30" 配列["02","50","30"]
なでしこ3 省略形 配列["02:50:30"] 配列[ ]

「02:50:30」を「(\d+)」で正規表現マッチ

バージョン 修飾子 それ 抽出文字列
なでしこ1 省略形 文字列"02" 文字列"02"
なでしこ3 省略形 配列["02","50","30"] 配列[ ]

「02:50:30」を「/(\d+):(\d+):(\d+)/」で正規表現マッチ

バージョン 修飾子 それ 抽出文字列
なでしこ3 空を指定 文字列"02:50:30" 配列["02","50","30"]

なでしこ1で省略した形と、なでしこ3で省略しない形がそっくりなので、プログラムを移植する場合はそのように。

結論

・命令は正規表現マッチ(AをBで|AがBに)で、なでしこ1と3で引数は変わらないが挙動に差がある

・引数Bには、正規表現修飾子を省略した書き方と、指定した書き方がある
指定した書き方はパターンの前後に『/』がある
「02:50:30」を「(\d+):(\d+):(\d+)」で正規表現マッチ というプログラムは正規表現修飾子を省略した書き方である
「02:50:30」を「/(\d+):(\d+):(\d+)/」で正規表現マッチ というプログラムは正規表現修飾子を指定した書き方である

・修飾子を省略した書き方をすると、なでしこ1では修飾子「gmk」が使用される
・修飾子を省略した書き方をすると、なでしこ3では修飾子「g」が使用される
・なでしこ3で修飾子「g」を使うと、抽出文字列が空配列になる
 ・以上よりなでしこ3で省略した書き方をすると抽出文字列が空配列になる

・なでしこ1で正規表現修飾子を省略すると、それに文字列で値が入る
・なでしこ1で正規表現修飾子を省略すると、抽出文字列に値が入る
・なでしこ3で正規表現修飾子を空に指定すると、それに文字列で値が入る
・なでしこ3で正規表現修飾子を空に指定すると、抽出文字列に値に値が入る

(なでしこ3で正規表現修飾子を省略すると、それに配列で値が入る)
(なでしこ3で正規表現修飾子を省略すると、抽出文字列が空になる)


なでしこ1での

  「02:50:30」を「(\d+):(\d+):(\d+)」で正規表現マッチ

というプログラムは「それ」「抽出文字列」に値が入ることを期待している

なでしこ3で同等の結果を期待する場合は 引数Bの部分を/ /で囲む書き方にすると良い。

  「02:50:30」を「/(\d+):(\d+):(\d+)/」で正規表現マッチ

そうすれば「それ」「抽出文字列」に値が入る。

※ これが書かれたのは なでしこv3.3.83~v3.4.1あたりの頃です


記事を書いた人はワイルドカードマッチ命令(なでしこ1)を応援しています

なでしこ3のイベントの発生について調べてみた

やること

マウスを移動させまくった時のキャンバスのマウス移動した時のイベントが発生する回数と画面更新時実行の発生回数を調べてみます

くわしく

キャンバスのマウス移動した時を設定すると、マウスカーソルを動かした時にすごい回数のイベントが発生します。

画面更新時実行を毎フレーム実行すると、これまたすごい回数のイベントが発生します。

どちらの方が多いかな?ということを計測します。

予想される結果は3通り

・同じ数、交互に発生する(マウス移動した時→画面更新→マウス移動した時→画面更新→…)
・マウス移動した時が多い(マウス移動した時→マウス移動した時→画面更新→マウス移動した時→マウス移動した時→画面更新→…)
・画面更新の方が多い(マウス移動した時→画面更新→画面更新→マウス移動した時→画面更新→画面更新→…)

プログラム

インデント構文

マウス移動回数=0
画面更新回数=0

描画中キャンバスマウス移動した時
 マウス移動回数=マウス移動回数+1


「更新時」画面更新時実行
●更新時
 「更新時」画面更新時実行
 もしマウス移動回数0ならば戻る
 
 画面更新回数=画面更新回数+1
 
 全描画クリア
 [10,10]画面更新回数文字描画
 [10,30]マウス移動回数文字描画
 [10,50](画面更新回数-マウス移動回数)文字描画 //実行回数の差を表示

検証方法

上記のプログラムを実行して、キャンバスの上でマウスを移動させ続ける
実行回数の差を見るとどちらが発生回数多いかがわかる

実行環境

2022年11月ころ ブラウザ:edge

実行結果

実行回数の差は0。
マウスを移動し続けたとき、「描画中キャンバスのマウス移動した時」と「画面更新回数」は同じ回数発生しているようです。

ブラウザの種類やブラウザのアップデートによって変わるかもしれないので、参考程度におねがいします。

なでしこ3の回数とか対象がうつろいやすい件

なでしこ3は回数が変わりやすい?

なでしこ3では回数がグローバル変数になっているようです。(v3.3.76時点)
なでしこ1ではローカル変数のような動きでした。

例)関数Aを呼んだあと回数を表示させた結果が異なる

●関数A
 10回
   それ回数 //回数を変更

3回
  関数A
  回数表示 //なでしこ1→1,2,3 なでしこ3→10,10,10

なでしこ1では「1,2,3」が表示されるのに対し、
なでしこ3では「10,10,10」が表示されます。
このコードでは回数で試しましたが、対象も同じような感じです。

対象、対象キーも同様

なでしこ3では回数対象対象キー抽出文字列グローバル変数です。(v3.3.76時点)
なでしこ1でも抽出文字列グローバル変数ですが、回数対象は違うみたいです。

以下のコードもなでしこ1と3で対象が異なっています。

「あいう」文字列分解して反復
  「かきく」文字列分解して反復
    それ対象  //か,き,くに対象を変更
  対象表示 //なでしこ1→あ,い,う なでしこ3→く,く,く

なでしこ3では対象が変わりやすくなった

なでしこ3では対象が変わる機会が増えました。
切り取る命令では、切り取った前半と後半をそれ対象に分けて代入します。
DOM部品のクリック時などのイベントでは、対象に発生した部品が入ります。
AJAX送信時などでは、対象に受け取った情報が入ります。

なでしこ1では反復以外では勝手に変わらない屈強な変数だった対象が変化しやすくなりました。

秒待つの最中に対象が変わる!

x秒待つで待っているときにイベントが走るときがあります。
このとき対象が変わっていることがありえます

以下のプログラムでは「秒待つ」している間にボタンクリックのイベントが起きた場合、対象が変わります

//サンプル(なでしこ3)
「ぼたん」ボタン作成
それクリックした時:
  //特になし(イベントが走ると対象がボタンに変わる)

「あいうえお」文字列分解して反復:
  1秒待つ  //ここでボタンをクリックすると対象が変わる
  対象表示

特殊変数を破壊から守る方法は……

※(マニュアルには特殊変数「それ」特殊変数「対象」といった記述あり)

関数の開始時に特殊変数をスタックに積んで、関数から戻る前にスタックから降ろせばよさそうです。

特殊変数用 = []
●特殊変数セーブ:
 特殊変数用{"回数":回数,"対象":対象,"対象キー":対象キー,"抽出文字列":抽出文字列}配列追加
●特殊変数ロード:
 変数 sore=それ
 変数 obj=特殊変数用から配列ポップ
 回数=obj["回数"]。 対象=obj["対象"]。 対象キー=obj["対象キー"]。 抽出文字列=obj["抽出文字列"]。
 sore戻す

●ユーザー定義関数
 特殊変数セーブ //回数や対象を保存
 //ここで回数や対象が変わる処理
 特殊変数ロード //回数や対象を復元
 戻る

……関数はともかく、イベントによる対象変更には無力です。どうにもならないね!

そのうち慣れる

ユーザー定義の関数を呼んだ後や、待つのあとは回数や対象は不定なものとして扱うしかなさそうです。
なでしこ1の挙動がステキだっただけに残念です。

なでしこ3で画像を半透明にする

なでしこ1には画像半透明コピーという命令がありました。
なでしこ3には今のところ実装されていないようです。(なでしこ3.3.74)

じゃあ調べて作ってみましょう!

完成

使用前 使用後

//なでしこ3.3.74 
インデント構文

画像w200。画像h200[画像w,画像h]キャンバス作成 //てきとう

「https://n3s.nadesi.com/image.php?f=8.jpg」画像読んだ時
  対象[0,0,画像w,画像h][0,0,画像w,画像h]画像部分描画。
  128画像半透明 //透明度50%

//不透明度 0~255
●画像半透明(alpで|alpに)
 w = 描画中キャンバス「幅」DOM属性取得
 h = 描画中キャンバス「高」DOM属性取得
 
 imagedata=描画中コンテキスト「getImageData」[0,0,w,h]JSメソッド実行
 data=imagedata["data"]
 start = 0
 end = (data要素数)-1
 
 istartからendまで4ずつ増やし繰り返す
   data[i+3]=alp
   
 imagedata["data"] = data
 描画中コンテキスト「putImageData」[imagedata, 0, 0]JSメソッド実行

序盤の解説

画像を半透明にする前に画像のロードが終わっていないといけません(1敗)。

キャンバスの作成、画像のロード(待ち)、キャンバスに元絵を描画、半透明処理、と進めていきます。
今回は画像読んだ時にはで処理を開始しています。

「https://n3s.nadesi.com/image.php?f=8.jpg」画像読んだ時
  対象[0,0,画像w,画像h][0,0,画像w,画像h]画像部分描画。
  128画像半透明 //透明度50%

●画像半透明(alpで|alpに)の解説

getImageDataする

imagedata=描画中コンテキスト「getImageData」[0,0,w,h]JSメソッド実行
↑画像から範囲指定してimageDataとかいうものを取り出します。
この部分に関しては、なでしこ3貯蔵庫にいいのがあったのでコピーしてきました。

imagedataをコンソール表示してみたところ…

imagedata["data"]が160000個の要素を持つ配列
imagedata["colorSpace"]が"srgb"形式であるらしい
imagedata["height"]が200
imagedata["widht"]が200

この160000の要素をもつdataは色のRGBAが順番に入っているそうです。
[R,G,B,A,R,G,B,A,R,G,B,A,……]
今回の作ったキャンバスは縦200×横200×RGBAで
200×200×4=160000要素ということです。
これを書き換えると色や透明度を変えられるようです。

不透明度を書き換える

RGBAのRGBは赤、緑、青。
のこりのAにあたる部分が不透明度なので、引数alpに書き換えて行きます。

 data=imagedata["data"]
 start = 0
 end = (data要素数)-1
 
 istartからendまで4ずつ増やし繰り返す
   data[i+3]=alp

ループの書き方はいろいろあるかと思いますが、せっかくなので~ずつ増やし繰り返すを使ってみました。
data[i]data[0]からdata[159999]なので注意します(1敗)

putImageDataする
 imagedata["data"] = data
 描画中コンテキスト「putImageData」[imagedata, 0, 0]JSメソッド実行

dataを書き換えたらimagedataをキャンバスに戻します。
dataのほうを戻すとエラーとなります(1敗)

使用例

使用例

参考にしたもの

n3s.nadesi.com

なでしこ1のイメージ部品についていろいろ

なでしこ1のイメージ部品について知っていることをあれこれ書いてみます。

・サイズを変えたら画面クリアしよう

イメージの幅や高さを変えたら画面クリアをしておくべき。
画面クリアするまで内部の描画領域のサイズが変わらず、絵が欠けたりします。

・描画処理反映という命令がある

イメージ部品に何か描いたとき、画面に反映されないことがあります。
ロード待ちのループ中に画像部分コピーとかするときとかが多いかな?
描画処理反映を使うと描いたものが画面に反映されます。

・イメージ部品の画像=?

イメージ部品の画像にはファイル名を指定しますが他にも「クリップボード」や「{イメージ部品の名前}」を指定することもできます。
動的生成(~をイメージとして作成)した場合はイメージ部品名を指定するときはイメージ部品[0]→名前を使います

イメージ部品Aとはイメージ
イメージ部品Bとはイメージ
イメージ部品A画像「クリップボード」//クリップボードの画像を取得
イメージ部品B画像「イメージ部品A」//部品名を指定するとコピーになる
//動的生成
イメージ部品[0]イメージして作成
イメージ部品[1]イメージして作成
イメージ部品[1]画像イメージ部品[0]名前//部品名を指定

・文字描画はとても時間がかかる

文字描画アンチエイリアス有り。
文字表示アンチエイリアス無し。
文字描画は目に見えて処理に時間がかかるので、ゲームを作るときには文字表示を使おう。
もっさり動作が改善されるかもしれません。

・イメージ部品の移動も時間がかかる

X,Yを変更する処理は処理に時間がかかる。
スプライト画像としてイメージを使うと処理落ちが激しい。
ゲームキャラを表示するときには画像部分コピーなどを使おう。

・座標とピクセル

幅とか座標の数値は方眼紙でいう線(交点)のところ(囲碁で石を置く場所) 点描画などでは指定した交点の右下のマスとなります

幅5高さ5のイメージは5x5の25ピクセル
5x5のイメージは点描画・点取得は0,0から4,4まで
3,3へ点描画すると、左から4つめのドットに色を塗る
0,0から4,4へ四角を描くと、点描画でいう0,0~3,3に線を引く(なでしこ3では違う)

・色のANDとかOR

画像ANDコピーとか画像ORコピーの命令があります。
黒色は$000000
白色は$FFFFFF
黒色とANDすると黒色になる
白色とANDすると色はそのまま
黒色とORすると色はそのまま
白色とORすると白色になる

・画像合成で変な色になるときは?

説明では「OBJ1の左上の色を透過色として扱う」のですが、左上の点が黒色(=$000000)以外だと変な色になります。
マニュアル検索ででてくるサンプルでは背景が黒なので正常に動いているように見えます。

画像合成で変な色になったら、透過色にしたい部分を黒にした画像を使い、0,0に黒色を点描画しておけば画像合成はうまくいくでしょう。

・できないこと

クリップボードに画像を送る方法はないみたい
透過PNGを扱うことはできないみたい
画像と画像を比較して一致するか調べることはできないみたい