カテゴリ: IchigoJam

  • タイトル
    MatchBit

  • 開発環境
    IchigoJamBASIC1.2.1
    IchigoLatte1.0.1

  • 内容
    マイコンが決めた1と0の並びを30秒の制限時間以内に当てるゲームです。
    クリアすると1桁ずつ増えていきます。

  • MatchBit
  • 遊び方
    「START!」の表示の後、キーを入力していきます。
    入力された数字(0または1)は回答欄の右端に入り、それまであった並びは1桁ずつ左にずれます。一番左にあった数字は削除されます。(これを左シフトと言います)
    マイコンが決めた数字と一致すればレベルクリアで、かかったタイムと積算時間が表示されます。

  • 操作方法
    RUNすると「Ready?」と表示され、カウントダウンが始まります。
    「START!」の表示で入力開始。
    どのキーを押してもOKです。("Esc"を除く)
    入力されたキーのアスキーコードが奇数なら1、偶数なら0が入力されます。

  • プログラムの具体的な入力方法
    左にJavaScript、右にBASICのプログラムが書かれています。
    IchigoLatteの場合は左のプログラムを、IchigoJamの場合は右のプログラムを入力してください。

  • プログラムについて
    プログラムは、IchigoJamのBASICから、IchigoLatteのJavaScriptへステップアップするための参考プログラムとして、あえて各命令が対になるように書いてあります。
    また、IchigoLatteに無い「BIN$」命令は新たに作成しています。

    各処理の内容は下記の通りです。

  • 各行の処理
    JavaScriptBASIC処理内容
    init()30 @I:'init変数設定
    readyGo()90 @R:'ready_goカウントダウン
    bin() BIN$()
    key() 260 @K:'key キー入力、一致確認、タイムアウト
    disp()400 @D:'disp結果表示
    match()460 @O:'match 一致した場合の表示
    gameOvr()540 @E:'game overゲームオーバー表示
    main()620 @M:'mainメイン処理


  • BASICからJavaScriptへステップアップのコツ
    BASICからJavaScriptへステップアップする際、最初に戸惑うのは「GOTO」命令が無いことと思います。
    「GOTO」を使わないプログラムを書くためには、プログラムの設計段階から考えなくてはなりません。

    まずBASICのプログラムリストを見てください。
    全ての処理が小さなサブルーチンになっていて、それらはほとんどがメイン処理(main以後)から呼び出されています。
    BASICではこの様な書き方はあまり見られないと思いますが(構造化BASICを除く)、これような書き方をすると「GOTO」をできるだけ使わない書き方ができます。

    今回作ったJavaScriptのプログラムでは「GOTO」を使う代わりに、「while」で行を戻る、「if」や「break」で行を飛ばす、「return()」で処理を飛ばす、といった手法を使っています。

    今日広く使われているプログラミング言語の多くは「GOTO」命令の使用を推奨していません。(これについては色々な意見はあります)
    「GOTO」を使わない処理の流れを考えるクセをつけておくと、JavaScript以外の言語を習得する際にも役に立ちます。

    なお、今回はBASICとJavaScriptの比較をテーマにしましたので、全ての変数がグローバル変数になっています。
    実際にJavaScriptでプログラムする場合は、関数の返り値やローカル変数を多用します。
    JavaScriptでのプログラムに慣れてきたら、変数のスコープも考えてプログラムを設計するようにしましょう。

    以上、簡単ではありますが上記プログラムがJavaScript学習の一助になれば幸いです。


  • MachBit
    JavaScriptBASIC
    //MachBit
    
    var l=0, n, t, u=0, r, s=0, x, y;
    
    function init(){
     l=l+1;
     x=0;
     n=1<<(l+1);
     y=rnd(n);
    }
    
    function readyGo(){
     var i=0;
     cls();
     log("LEVEL = ",l);
     lc(0,5);
     i=0;
     while(i<=l){
      log("?");
      i=i+1;
     }
     lc(0,2);
     log("Ready?");
     i=0;
     while(i<=4){
      lc(0,3);
      log(5-i);
      sleep(1000);
      i=i+1;
     }
     lc(0,3);
     log("START!\n\n");
    }
    
    function bin(b,d){
     while(d>0){
      log(((1<<(d-1))&b)!=0);
      d=d-1;
     }
    }
    
    function key(){
     var k;
     while(x!=y){
      k=0;
      while(!k){
       k=inkey();
       lc(20,6);
       log((30000-tick()+t)/1000," ");
       if(tick()-t>30000){
        return(0);
       }
      }
      k=k%2;
      x=(x<<1)+k;
      x=x&(n-1);
      lc(0,6);
      bin(x,l+1);
     }
     return(1);
    }
    
    function disp(){
     lc(0,5);
     bin(y,l+1);
     lc(0,11);
     log("Your Level = ",l,"\n");
     log("Your time  = ",u/1000,"sec\n");
     log("Total time = ",s/1000,"sec\n");
    }
    
    function match(){
     u=tick()-t;
     s=s+u;
     log("\n\nMATCH BIT!");
     disp();
     log("\nHIT [enter] key then next level");
     while(inkey()!=10){}
    }
    
    function gameOvr(){
     log("\ntime out");
     disp();
     lc(13,11);
     log(l-1);
     lc(0,15);
     log("GAME OVER\n");
    }
    
    function main(){
    
     while(1){
      init();
      readyGo();
      t=tick();
      if(!key()){
       break;
      }
      match();
     }
     gameOvr();
    }
    
    main();
    
    10 'MachBit
    20 GOTO@M
    
    
    30 @I:'init
    40 L=L+1
    50 X=0
    60 N=1<<(L+1)
    70 Y=RND(N)
    80 RTN
    
    90 @R:'ready_go
    
    100 CLS
    110 ?"LEVEL = ";L
    120 LC0,5
    
    130 FORI=0TOL
    140 ?"?";
    
    150 NEXT
    160 LC0,2
    170 ?"Ready?"
    
    180 FORI=0TO4
    190 LC0,3
    200 ?5-I
    210 WAIT60
    
    220 NEXT
    230 LC0,3
    240 ?"START!"
    250 RTN
    
    'BIN$(b,d)
    
    
    
    
    
    
    260 @K:'key
    
    
    
    
    270 K=INKEY()
    280 LC20,6
    290 ?(1800-TICK())/60;" "
    
    
    300 IFTICK()>1800R=0:RTN
    310 IF!KGOTO@K
    320 K=K%2
    330 X=(X<<1)+K
    340 X=X&(N-1)
    350 LC0,6
    360 ?BIN$(X,L+1)
    370 IFX!=YGOTO@K
    380 R=1
    390 RTN
    
    400 @D:'disp
    
    410 LC0,5:?BIN$(Y,L+1)
    
    420 LC0,11:?"Your Level = ";L
    430 ?"Your time  = ";U/60;"sec"
    440 ?"Total time = ";S/60;"sec"
    450 RTN
    
    460 @O:'match
    470 U=TICK()-T
    480 S=S+U
    490 ?:?:?"MATCH BIT!"
    500 GSB@D:'disp
    510 ?:?"HIT [enter] key then next level"
    520 @W:IFINKEY()!=10GOTO@W
    530 RTN
    
    540 @E:'game over
    550 ?:?"time out"
    560 GSB@D:'disp
    570 LC13,11
    580 ?L-1
    590 LC0,15
    600 ?"GAME OVER"
    610 RTN
    
    620 @M:'main
    630 CLV
    640 @L:'loop
    650 GSB@I:'init
    660 GSB@R:'ready_go
    670 CLT:T=TICK()
    680 GSB@K:'key
    
    
    
    690 IFRGSB@O:GOTO@L:'match:'loop
    700 GSB@E:'end
    710 END
    
    
    

    ダウンロードURLは下記になります。
    MachBit(JavaScript)  http://tagiyasoft.blog.jp/machbit_J.bin
    MachBit(BASIC)  http://tagiyasoft.blog.jp/machbit_B.bin


    ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
    (例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)


  • タイトル
    MissileDefense (電子工作マガジン2017年SUMMER号掲載)

  • 開発環境
    IchigoJamBASIC1.2.1

  • 内容
    敵国によるICBM発射の兆候をつかんだ我が軍は、ミサイル防衛システムを配備した。
    ICBMが本土上に着弾する前にそれらを撃墜し、我が国を守らなければならない。

  • MissileDefense
  • 遊び方
    RUNすると少し時間を置いて、上空からミサイルが軌跡を描きながら落下してきます。
    画面上の照準「+」を操作し、照準の位置に迎撃弾を発射することができます。
    迎撃弾を発射すると爆炎が発生し、爆炎にミサイルを突入させることでミサイルを撃破できます。
    迎撃弾は一度に3個までしか発射することができません。
    1発でもミサイルが地表に着弾してしまったらゲームオーバーです。

    迎撃した時の画面上の爆炎の数が1つの場合は15点、2つは10点、3つは5点です。
    2つのミサイルを同時に破壊した時は、さらに10点追加です。

  • 操作方法
    [↑]キー 上移動
     [↓]キー 下移動
    [←]キー 左移動
    [→]キー 右移動
    [スペース]キー 迎撃弾発射

    2つのキーを同時に押して斜めに移動することもできます。

  • プログラムのしくみ

    変数表(プログラム2)
    [0]~[3]ミサイル1の構造体:[0]発生フラグ,[1]長さ,[2]始点のX座標,[3]終点のX座標
    [4]~[15]ミサイル2~3の構造体:内容はミサイル1と同じ
    [30]~[32]爆炎1~3の位置
    [33]~[35]爆炎1~3の大きさ
    Sスコア
    Rスコアの加算値
    I,Jループ用
    N,M爆炎用一時変数
    Kキー入力値
    V照準移動方向
    T照準の位置
    U自機のX座標
    Lミサイル用インデックス
    Cミサイルのキャラクタ
    Yミサイル描画Y座標

    各行の処理(プログラム2)
    1行コメント(ファイル名)
    2行初期化
    3行タイマ
    4~9行爆炎処理
    10~14行ミサイル処理
    15~22行キー入力処理
    23~24行ミサイルの軌跡描画

  • プログラムの具体的な入力方法
    プログラム1は機械語サブルーチンになっていますので、間違えないように入力してください。 入力間違いがあるとエラーメッセージが出ずに、IchigoJamが操作不能になってしまう可能性があります。 ですので、プログラムを入力したら、まずSAVEしてからRUNするようにしてください。 もしIchigoJamが操作不能になってしまった場合は電源を入れ直してください。 (保存していないプログラムは消えてしまいます)

  • プログラムの改造
    プログラム2の、3行めの「tick()<50-s /10」は敵ミサイルの速度を設定するタイマーになっており、現在はスコア連動で徐々に早くなるようになっています。
    「s/10」の分母を大きくするとゆっくりになり、逆に小さくすると早くなります。

    敵ミサイルの発生率は10行の「RND(10)」により決まります。
    数値を大きくすると発生率が下がり、数値を小さくすると発生率が上がります。

    このプログラムはIchigoJam-ap(PCアプリケーション版)やIchigoJam-PC(PC_OS版)でも実行することができます。
    ただし、IchigoJam-apやIchigoJam-PCでは機械語を実行することができないのでプログラム1は入力せず、その代わりプログラム2の23~24行をプログラム3のように変更してください。
    全く同じ処理を、プログラム3はBASICで記述、プログラム1は機械語で記述したものです。
    PCのスペックにもよりますが、IchigoJam-apやIchigoJam-PCはBASICの処理でも十分な速度が出ます。
    動作環境によっては照準の移動が速すぎるので、21行の「'」を消してWAIT文が実行されるようにしてください。 WAIT文の数値を変更することで照準の速度を遅くすることができます。

MissileDefense(プログラム1)
10 'MissileCommand1
20 POKE #700,254,180,140,38,54,1,14,68,144,39,63,1,15,68,0,37
30 POKE #710,44,34,18,1,243,120,210,24,179,120,210,26,106,67,22,35
40 POKE #720,91,2,1,36,100,2,0,32,154,66,1,212,210,26,0,25
50 POKE #730,91,8,100,8,248,209,115,120,180,120,2,25,184,92,3,40
60 POKE #740,2,209,1,32,157,66,5,208,48,121,184,84,1,53,171,66
70 POKE #750,222,218,0,32,254,188,112,71
80 LRUN(プログラム2の保存番号)

MissileDefense(プログラム2)
1 'MissileCommand2
2 CLV:CLS:POKE4098,0:U=#50:T=#A10:POKET,43
3 IFTICK()<50-S/10GOTO15
4 R=4:FORJ=33TO35:IF![J]GOTO9
5 [J]=([J]+1)%7:N=ABS([J]*2-7):M=J-3:R=R-1:IFN=7POKE[M]-32,0:POKE[M]-1,0,0,0:POKE[M]+32,0:[M]=0
6 IFN=5POKE[M]-32,0:POKE[M]-1,0,3,0:POKE[M]+32,0
7 IFN=3POKE[M]-33,0,3,0:POKE[M]-2,0,3,3,3,0:POKE[M]+31,0,3,0
8 IFN=1POKE[M]-33,3,3,3:POKE[M]-2,3,3,3,3,3:POKE[M]+31,3,3,3
9 NEXT:CLT
10 FORI=0TO3:L=I*4:IF![L]IFRND(10)GOTO13ELSE[L+2]=RND(32):[L+3]=RND(32):[L]=1
11 C=219:GOSUB23:IF[L]=0C=0:GOSUB23:[L]=0:[L+1]=0:S=S+R:R=R+1
12 [L+1]=[L+1]+1
13 LC0,0:?"SCORE ";S*5:IF[L+1]=23LC0,5:?"GAME OVER":END
14 NEXT
15 K=PEEK(4098):V=0:IF!KGOTO3
16 IFK&16FORI=30TO32:IF[I]=TI=32:NEXTELSEIF[I]NEXTELSE[I]=T:[I+3]=1:POKET,3:I=33:NEXT:GOTO3
17 IFK&1V=V-1
18 IFK&2V=V+1
19 IFK&4V=V-32
20 IFK&8V=V+32
21 K=T+V:IFK>#91F&&K<#BC0IFVPOKET,0:POKEU,0:T=T+V:U=#BE0+T%32:POKET,43:POKEU,240:'WAIT10
22 GOTO3
23 POKE#8C0,[L],[L+1],[L+2],[L+3],C:IFUSR(#700,C)[L]=0
24 RETURN

MissileDefense(プログラム3)
23 FORY=0TO[L+1]:P=#900+Y*(704+[L+3]-[L+2])/22+[L+2]:IFPEEK(P)=3&&Y=[L+1][L]=0:Y=22
24 POKEP,C:NEXT:RETURN

MissileDefense(プログラム1のアセンブラリスト)
push	{r1-r7}
mov	r6,#8c
lsl	r6,r6,4	'r6=#8c0=[l]
add	r6,r1	'#8c0 実アドレス
mov	r7,#90
lsl	r7,r7,4	'r7=#900=VRAM
add	r7,r1	'VRAM 実アドレス
mov	r5,0	'y=counter
@loop1
mov	r2,#2C
lsl	r2,r2,4	'r2=#2c0=704=32*22
ldrb	r3,[r6,3]	'R3=[L+3]
add	r2,r2,r3
ldrb	r3,[r6,2]	'R3=[L+2]
sub	r2,r2,r3
mul	r2,r5	'R2=y*(704+[L+3]-[L+2])
'--DIV st--
mov	r3,#16	'割算	r2/22
lsl	r3,r3,9	'r3=22*2^4=#160
mov	r4,#1	'r4=シフト_カウンタ
lsl	r4,r4,9
mov	r0,0	'r0=商
@div_loop
cmp	r2,r3
bmi	@div_shift	'jmp r2<r3
sub	r2,r2,r3
add	r0,r0,r4
@div_shift
lsr	r3,r3,1
lsr	r4,r4,1
bne	@div_loop
'--DIV ed--
ldrb	r3,[r6,1]	'R3=[L+1]
ldrb	r4,[r6,2]	'R4=[L+2]
add	r2,r0,r4	'商+[L+2]
ldrb	r0,[r7,r2]	'R3=peek(R2)
cmp	r0,3
bne	@nohit	'ifpeek(p)=3
mov	r0,1
cmp	r5,r3
beq	@hit	'ify=[L+1]
@nohit
ldrb	r0,[r6,4]	'R0=c
strb	r0,[r7,r2]	'pokeR2,R0
add	r5,1	'counter ++
cmp	r3,r5	'R3-R5=[L+1]-counter
bge	@loop1
mov	r0,0
@hit
pop	{r1-r7}
ret

MixJuiceでのダウンロードURLは下記になります。
MissileDefense(Program1)  http://tagiyasoft.blog.jp/missiledefense1.bin
MissileDefense(Program2)  http://tagiyasoft.blog.jp/missiledefense2.bin
MissileDefense(Program3)  http://tagiyasoft.blog.jp/missiledefense3.bin

以下のように入力してD/Lしてください。
NEW
? MJ GET tagiyasoft.blog.jp/missiledefense1.bin
? MJ GET tagiyasoft.blog.jp/missiledefense2.bin

ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
(例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

  • 題名
    テンケス+4x4文字 (電子工作マガジン2017年SPRING号掲載)

  • 開発環境
    IchigoJamBASIC1.2.0

  • 内容
    プログラムは2つのプログラムから成っています。
    プログラム1:4x4文字を表示します。
    プログラム2:数字をスライドさせ、同じ数字を重ねて消していくパズルゲームです。
  • テンケス
  • 使い方(4x4文字)
    プログラム1は、4バイト×4バイトの文字を表示するプログラムです。
    配列[101]に表示したい文字のアスキーコード、USR関数の第2引数に表示したいVRAMアドレスを入れてコールします。

    *注意:プログラムサイズを小さくするため表示アドレスのチェックは行っていません。
    ですので、VRAM以外および#B9C以後のアドレスを表示位置に指定するとプログラムやデータが破壊されます。

    ・使用例
    10 [101]=65:X=USR(#700,#900):'画面左上に「A」が表示されます
    20 [101]=97:X=USR(#700,#900+10+32*6):'横10,縦6の位置に「a」が表示されます
    30 [101]=255:X=3:Y=8:Z=USR(#700,#900+X+32*Y):'横3,縦8の位置に「イチゴ」が表示されます

  • 遊び方(テンケス)
    4x4マスの中に数字が表示されます。
    矢印キーを押すと数字がその方向に滑っていきます。
    同じ数同士がぶつかると重なって次の数に変わります。
    数字が「10」まで進むとマスから消えます。
    数字が移動するごとに新たに2つの数字が表示されます。
    空きマスが1マス以下になるとゲームオーバーです。
    空きマスの探索中は左下に数字が表示されますので、数字が消えるまでキーは押さないでください。

  • プログラムのしくみ
  • 変数表(プログラム2)
    I,J,Wループ用
    Vキー入力
    Sスコア
    R乱数用
    X,YマスのXY座標
    K,Zマスの座標を一列に変換した値
    AUSR関数用ダミー変数
    Zマスの移動元の配列添字
    Uマスの移動先の配列添字
    [0]~[15]マスの中の数字(画面表示は、左上[0]~右下[15])
    [21]~[24]矢印キーが押された時のジャンプ先行番号
    [101]4x4文字用

    各行の処理
    1行コメント
    2行初期画面表示・分岐先行の設定
    3行数字を表示×2
    4行キー入力・スコア表示
    5行空きマス探索・ゲームオーバー判断
    6行マス内の数字をアスキーコードに変換
    7行4x4文字を表示
    8,9行左キーが押された場合の処理
    10,11行右キーが押された場合の処理
    12,13行上キーが押された場合の処理
    14行下キーが押された場合の処理
    15行数字を表示してサブルーチン終了

  • プログラムの具体的な入力方法
    プログラムリスト中の「□」はスペース1個です。
    カードの枠線は「左ALT+SHIFT+キー」で入力します。
    ━ 左ALT+SHIFT+H
    ┃ 左ALT+SHIFT+I
    ┏ 左ALT+SHIFT+O(オー)
    ┓ 左ALT+SHIFT+P
    ┗ 左ALT+SHIFT+Q
    ┛ 左ALT+SHIFT+R
    プログラム1の50行のLRUN文にプログラム2の保存番号を記入すると、プログラム1を実行後、自動的にプログラム2を読み込んで実行できます。


  • プログラムの改造
    プログラム1は、このゲーム以外でも使用することができます。
    上記の使い方を参考に自作プログラム等に組み込んで使用してください。
    なおプログラム1の2行目は機械語ルーチンを書き込むアドレスです。
    現在はキャラクタ定義用のアドレスに書き込まれていますが、該当キャラクタを使用したい場合はアドレスを適宜変更してください。
    (その場合はUSR関数の呼び出しアドレスも変えてください)
    プログラム2の"if[k]=10"がマスから消える数字ですので、10以下にすると難易度が下がります。
    (11以上にすると数字以外の文字になってしまいます)

  • テンケス(プログラム1)
    10'4x4
    20 Z=#700
    30 pokeZ,224,180,64,24,8,35,27,2,202,51,91,92,219,0,155,24,4,38,64,180,4,33,28,120,93,120,1,180,8,32,0,34,0,38,0,39,100,8,86,65,118,0,109,8,87,65,127,0,1,56
    40 pokeZ+#32,247,209,116,8,125,8,1,188,3,34,47,70,23,64,191,0,38,70,22,64,62,68,128,54,6,112,164,8,173,8,1,48,1,57,242,209,28,48,2,51,64,188,1,62,216,209,224,188,112,71
    50 LRUN(プログラム2の保存番号)
    

    テンケス(プログラム2)
    1 'イッチ
    2 clv:let[21],4,5,6,7:cls:?"┏━━━━┳━━━━┳━━━━┳━━━━┓ SCORE:0":FORI=1TO4:forj=1to4:?"┃□□□□┃□□□□┃□□□□┃□□□□┃":next:?"┣□□□□╋□□□□╋□□□□╋□□□□┫":next:lc0,20:?
    "┗━━━━┻━━━━┻━━━━┻━━━━┛"
    2 clv:let[21],4,5,6,7:cls:?"「----v----v----v----フ SCORE:0":FORI=1TO4:forj=1to4:?"|    |    |    |    |":next:?">----+----+----+----<":next:lc0,20:?"L----^----^----^----ノ"
    3 gsb5:gsb5
    4 v=inkey()-27:ifv<1orv>4goto4elsegsb[20+v]*2:lc28,0:?s:goto3
    5 j=1:fori=0to15:j=j*[i]:next:ifj?"GAME OVER":endelser=rnd(16):lc0,21:if[r]?r:goto5else[r]=1:gsb6:?"  ";:rtn
    6 fory=0to3:forx=0to3:k=y*4+x:[101]=[k]:if[k][101]=[k]+48:if[k]=10[k]=0:[101]=12:s=s+10
    7 a=usr(#700,#921+y*160+x*5):next:next:rtn
    8 forw=0to2:fory=0to3:forx=0to2:z=y*4+x:u=z+1:if[z]OR[u]if[z]=0[z]=[u]:[u]=0elseif[z]=[u]s=s+[z]:[z]=[z]+1:[u]=0
    9 goto15
    10 forw=0to2:fory=0to3:forx=1to3:z=y*4+4-x:u=z-1:if[z]or[u]if[z]=0[z]=[u]:[u]=0elseif[z]=[u]s=s+[z]:[z]=[z]+1:[u]=0
    11 goto15
    12 forw=0to2:forx=0to3:fory=0to2:z=y*4+x:u=z+4:if[z]OR[u]if[z]=0[z]=[u]:[u]=0elseif[z]=[u]s=s+[z]:[z]=[z]+1:[u]=0
    13 goto15
    14 forw=0to2:forx=0to3:fory=1to3:z=(4-y)*4+x:u=z-4:if[z]or[u]if[z]=0[z]=[u]:[u]=0elseif[z]=[u]s=s+[z]:[z]=[z]+1:[u]=0
    15 next:next:gsb6:next:rtn

    テンケス(プログラム1のアセンプラリスト)
    push	{r5,r6,r7}
    add	r0,r0,r1	'描画実VRAM
    mov	r3,#8
    lsl	r3,r3,8
    add	r3,#ca		'[101]の下位アドレス=#8CA
    ldrb	r3,[r3,r1]	'[101]の数
    lsl	r3,r3,3		'キャラジェネアドレス
    add	r3,r3,r2	'実キャラジェネアドレス
    mov	r2,#03		'0000 0011マスク
    mov	r6,#4		'大ループカウンタ
    @LOOP1
    push	{r6}		'大ループカウンタ保存
    mov	r1,#4		'小ループカウンタ
    ldrb	r4,[r3,0]	'1行目
    ldrb	r5,[r3,1]	'2行目
    @LOOP2
    cpy	r7,r5		'2行目
    and	r7,r2		'0000 0011マスク
    lsl	r7,r7,2
    cpy	r6,r4		'1行目
    and	r6,r2		'0000 0011マスク
    add	r6,r7
    add	r6,#80		'疑似グラフィックキャラ
    strb	r6,[r0,0]	'描画
    lsr	r4,r4,2
    lsr	r5,r5,2
    add	r0,1		'描画位置右移動
    sub	r1,#1		'小ループカウンタ減算
    bne	@LOOP2
    add	r0,#1C
    add	r3,2
    pop	{r6}		'大ループカウンタ取り出し
    sub	r6,1		'大ループカウンタ減算
    bne	@LOOP1
    pop	{r5,r6,r7}
    ret
    


MixJuiceでのダウンロードURLは下記になります。
テンケス(Prpgram1) http://tagiyasoft.blog.jp/tenkes1.bin
テンケス(Prpgram2) http://tagiyasoft.blog.jp/tenkes2.bin

以下のように入力してD/Lしてください。
NEW
? MJ GET tagiyasoft.blog.jp/tenkes1.bin
? MJ GET tagiyasoft.blog.jp/tenkes2.bin

ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
(例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

  • 題名
    おにごっこゲーム (電子工作マガジン2017年SPRING号掲載)

  • 開発環境
    IchigoJamBASIC1.2.0

  • 内容
    あなたは猫です。
    天敵の蛸(?)に捕まらないように部屋にあるキャットフードを全て食べつくしてください。 nekotako

  • 遊び方
    テンキーの[2][4][6][8]のキーで上下左右に移動します。
    敵は最短距離で近づいてきますので、捕まらないように逃げながらドットを消してください。
    全てのドットを消すと面クリアです。
    面をクリアするごとに移動速度が少しずつ速くなり、ランダムに配置される壁が少なくなります。

  • プログラムのしくみ
  • 変数表
    A残りのドットの数
    C残りの猫の数
    D自分の移動先のキャラクタ
    I,Jループ用
    K入力されたキー
    O敵の位置
    P自分の位置
    Sスコア
    T敵が移動した後に表示するキャラクタ
    V自分の移動方向
    W移動速度
    X,Y乱数用一時変数

    各行の処理
    1行コメント行
    2行初期設定
    3~4行画面描画
    5行敵を右下に描画
    6行自分を左上に描画
    7行キー入力と移動方向の計算
    8行自分移動先のキャラクタによって移動方向決定
    9行自分の移動とスコア加点
    10行敵と自分の最短移動方向を計算
    11行敵移動先のキャラクタによって移動方向決定
    12行面クリア判定
    13行捕まったか判定
    14行ゲームオーバー処理
    15行TRY AGAIN?
    16行画面中央の3行をクリア


  • プログラムの改造
    2行のW=21の数値を小さくすると全体の速度が早くなります。
    2行のC=2の数値を大きくすると自分の残数が増えます。


  • おにごっこゲーム
    1'ネコタコ
    2 CLS:CLV:W=21:C=2:LC25,0:?"SCORE":LC25,15:?CHR$(236);"= 2"
    3 FORJ=0TO22:FORI=0TO22:LCI,J:IF(I%22<>0ANDJ%4=1)OR(J%22<>0ANDI%4=1)?CHR$(144)ELSE?CHR$(4)
    4 NEXT:NEXT:FORI=0TOW/10:X=RND(12)+5:Y=RND(12)+5:IFVPEEK(X,Y)=144LCX,Y:?CHR$(4)ELSEI=I-1
    5 NEXT:O=#BB5:V=1:T=144:POKEO,237:A=214-W/10
    6 P=#921:POKEP,236:WAIT90
    7 K=INKEY():POKE#1003,0:IFK=0K=VELSEK=K-53:IFABS(K)<>1ANDABS(K)<>3K=VELSEK=(1/K)-(K/3)*32
    8 D=PEEK(P+K):IFD<>4V=KELSEIFV=KK=RND(4)*2-3:K=(1/K)-(K/3)*32:GOTO8ELSEK=V:GOTO8
    9 POKEP,0:P=P+V:IFPEEK(P)=144THENS=S+1:LC25,1:?S:A=A-1
    10 POKEP,236:Y=(P-O)/32:X=P%32-O%32:POKEO,T:IFABS(Y)< ABS(X)Z=(ABS(X)/X)ELSEZ=(ABS(Y)/Y)*32
    11 T=PEEK(O+Z):IFT<>4O=O+Z:POKEO,237:ELSEZ=RND(4)*2-3:Z=(1/Z)-(Z/3)*32:GOTO11
    12 IFA=0GOSUB16:LC6,11:?"SATGE CLEAR":WAIT90:W=W-2:GOTO3
    13 WAITW:IFP<>OGOTO7ELSEIFC>0C=C-1:LC28,15:?C:T=0:GOTO6
    14 GOSUB16:LC7,11:?"GAME OVER":LC4,13:?"TRY AGAIN?(Y/N)"
    15 K=INKEY():IFK=89ORK=121RUNELSEIFK=78ORK=110ENDELSEGOTO15
    16 FORI=3TO19:FORJ=10TO12:LCI,J:?" ":NEXT:NEXT:RETURN
    


MixJuiceでのダウンロードURLは下記になります。
ネコタコ http://tagiyasoft.blog.jp/nekotako.bin

以下のように入力してD/Lしてください。
NEW
? MJ GET tagiyasoft.blog.jp/nekotako.bin

ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
(例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

  • タイトル
    インベーダー

  • 開発環境
    IchigojamBASIC1.2.1

  • 内容
    宇宙からインベーダーが大挙して攻めてきます。
    あなたは地球を守るためインベーダーを迎撃しなくてはなりません。
    invader
  • 遊び方
    画面上方から徐々に侵略してくるインベーダーを、画面下部の砲台よりミサイルを打って撃墜してください。
    インベーダーの攻撃に当たる、もしくはインベーダーが地上に着いて地球侵略された時点でゲームオーバーです。

  • 操作方法
    [1]キー 左移動
    [2]キー 右移動
    [スペース]キー ミサイル発射

  • プログラムのしくみ
    機械語部分(プログラム1)とBASIC部分(プログラム2)に分かれています。

    プログラム1の2行目はキャラクタ設定を行っています。

    機械語部分はBASE16というエンコード方法で変換されています。
    (8bitのうち上位4bitと下位4bitをそれぞれ@~Oの文字に変換)

    インベーダーの動き、インベーダーのミサイル、自機のミサイルなど、処理速度が必要な部分を機械語で処理しています。
    画面描画、自機の動き、UFOの発生、得点、サウンドなど比較的処理速度の必要でない部分をBASICで処理しています。

    変数については、変数領域の半分くらいまで機械語プログラムが書き込まれているため、変数の後半(Z~W)のみを使用しています。


  • 機械語プログラム(プログラム1)
    機械語ルーチンへの渡し値
    #770-#771自機ミサイル位置
    #77E面クリアフラグ
    #77Fインベーダー移動方向
    機械語ルーチンから戻り値(USR関数)
    1Invader撃墜
    2UFO撃墜
    #FF自機被弾

    キャラクタ表
    #E0上段インベーダー
    #E1中段インベーダー
    #E2下段インベーダー
    #E3敵ミサイル
    #E4自ミサイル
    #E5砲台
    #E6UFO
    #E7爆発

    画面構成
    #900-#91FSCORE
    #920-#93FUFO
    #920-BE0Invaders
    #BE0-BFFSHIP

    BASICプログラム(プログラム2)
    変数一覧表
    Z点数
    Y得点(1or2)またはゲームオーバーフラグ(=#FF)
    X自機の位置
    Wループ用


    各行の処理
    10行コメント行
    20行キャラクタ定義
    30行点数クリア
    40行初期設定()
    50行初期画面描画
    60行インベーダー移動
    70行面クリア判定
    80行インベーダーのミサイル移動
    90行自機のミサイル移動
    100行キー入力:ミサイル発射
    110行自機左右移動
    120行自機描画
    130行インベーダーのミサイル発生
    140行UFO出現
    150行繰り返し
    160行ゲームオーバー判定:加点処理

    機械語処理については、機械語プログラムのコメントを参照してください。

  • (5)プログラムの具体的な入力方法
    機械語部分は入力を間違えると操作不能になってしまうので、間違えないようにしてください。
    もしプログラムを実行して操作不能になってしまった場合は、一度IchigoJamの電源を切ってから再度電源を入れ直してください。

    まずプログラム1を入力して保存、次にプログラム2を入力してしてください。
    遊ぶ時は、まずプログラム1をロードして実行します。するとメモリ内に機械語プログラムが書き込まれます。
    次にプログラム2をロードして実行しするとゲームが始まります。
    プログラム1の8行目のendを「LRUN(プログラム2の保存番号)」に変更すると、プログラム1を実行後に自動でプログラム2を読み込み実行させることができます。

  • プログラムの改造
    プログラム2(BASICプログラム)の数値の変更による難易度変更は下記の通りです。

    80行のFOR文のループ数を大きくすると、自機ミサイルの速度が上がります。
    同じく80行のWAIT文の式を変更するとインベーダーの移動速度が変わります。(現在は点数に連動)
    120行のWの値を変えるとインベーダーのミサイルの発生率が変わります。
    130行のWの値を変えるとUFOの発生率が変わります。

    他の改造については、BASIC部分にメモリの余裕があるので改造しやすいと思います。
    (例:自機数を増やす、面ごとにインベーダーの初期描画位置を下げるなど)

    変数領域まで機械語プログラムが書き込まれているため、改造の際は使用する変数をK以後にしてください。
インベーダー(プログラム1)
1'invader1
2CLS:CLP:CLV:W=#50:LET[0],#0B,#EC,#ED,#F2,#1E,#F0,#F1,#F4:FORZ=0TO7:COPY(#E0+Z)*8,[Z]*8,8:NEXT
3Z="G@KD@@BFIABDBD@A@OCDFCAHAJGHN@BJ@AMKNBBJA@MMEJGHN@BJ@AMKNBBJ@KMMB@CDBE@IKOBMO@MKGGBDBD@A@OCDFBEL@@BJBAM@@ABJCFM@KOBDBD@AFEAHBJGHN@BJ@KMKNBBJ@IMLBC@IKLBKABMJ@@BC":Y=#780:GSB9
4Z="BKG@B@CEBKGHNEBK@LM@BJG@@ACLBE@II@BMNKMAGGBDBD@A@OCDFBEL@ABCEJD@FBEDMINGOOB@BLN@KOBDBD@AFDAHBBGHN@BJ@JMKNBBJ@HMLAFALFCGHNDBK@AMA@AB@@@BBFBG@@@BBBBG@@ACLFCAJAK@J":Y=#7D0:GSB9
5Z="@HBKNLMAAEN@IBBDBD@AFDAHFBGHN@BJ@JMKNBBJ@HMLAFALBCGHNDBK@AMA@AB@@@BBBBG@@@BBFBG@@ACDFCAJAK@IKOBKNLMAGGBBAB@A@NCBEFEDG@KLG@DG@@@@C@KDB@BEKOBDBD@A@OCDFDAHBBGHNCBJ":Y=#820:GSB9
6Z="@LMA@@BCBCG@FCAJAK@IKNBK@FMJFCEM@@BK@BM@NEBK@AMAOOB@FBEE@ACLFCAJAK@IIABKNJMAC@KLG@DG@@@@@@@@@@@@G@KDGGBEBM@AFLEJ@@BLAEM@@@BFFFEDB@CLBBDFBC@IIBBK@NMKNDBCFBEL@BB@":Y=#870:GSB9
7Z="NFBJ@FM@@@B@BFDFN@BJ@DMKNCBJ@BML@AB@@@BC@@BFFCEDFNEBG@KLG@DG":Y=#8C0:W=#1E:GSB9
8END
9FORX=YTOY+W-1:POKEX,PEEK(Z)&15<<4+PEEK(Z+1)&15:Z=Z+2:?"#";HEX$(X),HEX$(PEEK(X)):NEXT:RTN

インベーダー(プログラム2)
10 'invader2
20 POKE#E0*8,#42,#24,#7E,#DB,#FF,#BD,#24,#42,#3C,#7E,#FF,#99,#FF,#FF,#66,#DB,#18,#3C,#7E,#DB,#FF,#5A,#81,#42
30 Z=0
40 CLS:?"SCORE:":LC8,0:?Z:POKE#770,0,0:POKE#77E,0,0:X=#BF0:POKEX,#E5
50 FORW=0TO4:FORY=0TO7:LCY*3+1,8-W*2+1:?CHR$(#E0+W/2):NEXT:POKE#B40+3+W*6,1,1,1:NEXT
60 Y=USR(#780,0):GSB160:BEEP255,1:IFYPOKE#770,0,0
70 IFPEEK(#77E)=0LC10,10:?"CLEAR":PLAY"O4BO5GB":WAIT60:GOTO40
80 Y=USR(#860,0):GSB160
90 FORW=0TO4:Y=USR(#8A0,0):GSB160:WAIT(100-Z)/10
100 Y=INKEY()-50:POKE#1003,0:IFY=-18ANDPEEK(#771)=0THENPOKE#770,#C0+(X-#BE0),#0B:GOTO120
110 IFABS(Y)=1POKEX,0:X=X+Y:IFX<#BE0ORX>#BFFX=X-Y
120 POKEX,#E5:NEXT
130 W=3:Y=RND(#60*W):IFY%WIFPEEK(#A40+Y/W)=0POKE#A40+Y/W,#E3
140 W=#10:Y=RND(#20*W):IFPEEK(#920+Y/W)=#E6POKE#920+Y/W,0ELSEIFNOT(Y%W)IFPEEK(#920+Y/W)=0POKE#920+Y/W,#E6
150 GOTO60
160 IFYIFY=#FFPOKEX,#E7:LC10,10:?"GAME OVER":PLAY"C02EDC":ENDELSEZ=Z+Y:LC8,0:?Z
170 RTN

プログラム1のアセンブラリスト
'インベーダー移動	usr(#780,0)
'左端、右端チェック処理
push	{r4,r5,r6}
mov	r6,0		'敵存在フラグクリア
mov	r4,#91
lsl	r4,r4,4
add	r4,#f		'探索VRAM=#91F:右端
@lr_loop_down
add	r3,r4,r1	'R3=実VRAM
ldrb	r2,[r3,0]	'右端キャラ
cmp	r2,#e0
blt	@l_chk_down	'R2<#E0なら左端をチェック
cmp	r2,#e2
ble	@vector_down	'R2<=#E2なら1段下げ処理へ
@l_chk_down
ldrb	r2,[r3,1]	'左端キャラ
cmp	r2,#e0
blt	@chk_add_down	'R2<#E0なら1行下チェックへ
cmp	r2,#e2
ble	@vector_down	'R2<=#E2なら1段下げ処理へ
@chk_add_down
add	r4,#20		'1行下
lsr	r5,r4,4
cmp	r5,#bf
blt	@lr_loop_down	'R4<#BF*ならループ

'左右移動に分岐処理
@lr_move
mov	r4,#77
lsl	r4,r4,4
add	r4,#f
ldrb	r2,[r4,r1]	'#7FF=インベーダー移動方向
cmp	r2,0		'0=右/1=左
beq	@inv_r_move	'右移動処理へ
cmp	r2,1
beq	@inv_l_move	'左移動処理へ

'1段下げる処理
@vector_down
mov	r4,#bf		'開始VRAM=#BF0
lsl	r4,r4,4
@loop_down		'1段下げループ
add	r5,r4,r1	'R5=実VRAM
ldrb	r2,[r5,0]
cmp	r2,#e0
blt	@add_down	'R2<#E0なら左隣チェックへ
cmp	r2,#e2
bgt	@add_down	'R2>#E2なら左隣アドレスへ
lsr	r3,r4,4	
cmp	r3,#bc		'#BC*=最下行
bge	@game_over	'R3>=#BC*ならゲームオーバー処理
mov	r3,0
strb	r3,[r5,0]	'元位置クリア
add	r5,#20
ldrb	r3,[r5,0]	'1段下のキャラ
cmp	r3,#e5
beq	@game_over	'1段下が砲台ならゲームオーバー処理
strb	r2,[r5,0]	'1段下にインベーダー描画
@add_down
sub	r4,1		'左隣のアドレス
lsr	r5,r4,4		'アドレス#90*
cmp	r5,#90
bne	@loop_down	'R5!=#90なら1段下げループへ

'進行方向逆転
mov	r4,#77
lsl	r4,r4,4
add	r4,#f
ldrb	r2,[r4,r1]	'#7FF=インベーダー移動方向
mov	r3,1		'0=右/1=左
eor	r2,r3		'0,1を反転
strb	r2,[r4,r1]
bla	@lr_move	'左右移動に分岐処理

'ゲームオーバー処理
@game_over
mov	r0,#FF		'ゲームオーバーフラグ
bla	@end

'右移動
@inv_r_move
mov	r4,#bf		'開始VRAM=#BF0
lsl	r4,r4,4
add	r4,r4,r1	'R4=実VRAM
@loop_rmov		'ループ開始
ldrb	r2,[r4,0]	'移動元のキャラクタ
cmp	r2,#e0
blt	@add_rmov	'R2<#E0なら左隣アドレスへ
cmp	r2,#e2
bgt	@add_rmov	'R2>#E2なら左隣アドレスへ
mov	r6,r2		'敵存在フラグ
ldrb	r3,[r4,1]	'移動先のキャラクタ
cmp	r3,#e4		'自弾
bne	@hit_rmov	'R3!=#E4ならキャラクタ移動へ
mov	r0,1		'撃墜フラグセット
mov	r2,0		'インベーダー消去
@hit_rmov
strb	r2,[r4,1]	'キャラクタを移動先に
mov	r2,0
strb	r2,[r4,0]	'元位置をクリア
@add_rmov
sub	r4,1		'左隣のアドレス
sub	r3,r4,r1
lsr	r3,r3,8
cmp	r3,8
bne	@loop_rmov	'R3!=#8**ならループへ
bla	@end

@inv_l_move
mov	r4,#92		'開始VRAM=#920
lsl	r4,r4,4
add	r4,r4,r1	'R4=実VRAM
@loop_lmov		'ループ開始
ldrb	r2,[r4,1]	'移動元のキャラクタ
cmp	r2,#e0
blt	@add_lmov	'R2<#E0なら右隣アドレスへ
cmp	r2,#e2
bgt	@add_lmov	'R2>#E2なら右隣アドレスへ
mov	r6,r2		'敵存在フラグ
ldrb	r3,[r4,0]	'移動先のキャラクタ
cmp	r3,#e4		'自弾
bne	@hit_lmov	'R3!=#E4ならキャラクタ移動へ
mov	r0,1		'撃墜フラグセット
mov	r2,0		'インベーダー消去
@hit_lmov
strb	r2,[r4,0]	'キャラクタを移動先に
mov	r2,0
strb	r2,[r4,1]	'元位置をクリア
@add_lmov
add	r4,1		'右隣のアドレス
sub	r3,r4,r1
lsr	r3,r3,4
cmp	r3,#bf
bne	@loop_lmov	'R3!=#BF*ならループへ

@end			'インベーダー移動終了処
mov	r2,#77
lsl	r2,r2,4
add	r2,#e		
strb	r6,[r2,r1]	'敵存在フラグ=#77E
pop	{r4,r5,r6}
ret

nop

'敵弾(全走査)		usr(#860,0)
push	{r4,r5}
mov	r5,#20		'1行のアドレス増分
mov	r4,#bf
lsl	r4,r4,4
add	r4,#f		'開始VRAM=#BFF
add	r4,r4,r1	'R4=実VRAM
@loop_bomb
ldrb	r2,[r4,0]	'移動元のキャラクタ
cmp	r2,#e3		'敵弾
bne	@no_bomb	'R2!=#E3なら左隣のアドレスへ
mov	r3,0
strb	r3,[r4,0]	'元位置クリア
sub	r3,r4,r1
lsr	r3,r3,4
cmp	r3,#be
bge	@no_bomb	'R3>=#BE*なら左隣のアドレスへ
ldrb	r3,[r4,r5]	'移動先のキャラ
cmp	r3,0
beq	@mov_bomb	'空白なら敵弾移動
cmp	r3,#e5		'砲台
bne	@no_bomb	'R3!=#E5なら左隣のアドレスへ
mov	r0,#FF		'ゲームオーバーフラグ
@mov_bomb
strb	r2,[r4,r5]	'敵弾移動
@no_bomb
sub	r4,1		'左隣のアドレス
sub	r3,r4,r1
lsr	r3,r3,4
cmp	r3,#91		'アドレス#91*
bne	@loop_bomb	'R3!=#91ならループへ
pop	{r4,r5}
ret

nop
nop
nop

'自弾(自位置=#770)	usr(#8A0,0)
push	{r4,r5,r6}
mov	r5,#77		'自弾位置ポインタ=#770
lsl	r5,r5,4
ldrh	r4,[r5,r1]	'自弾位置
cmp	r4,0		'自弾無し
beq	@exit_msl	'r4==0処理終了
mov	r6,0
strb	r6,[r4,r1]	'元位置クリア
sub	r4,#20		'1行上
cpy	r2,r4		'自弾1行上位置コピー
lsr	r3,r4,4
cmp	r3,#92		'VRAM=#920
blt	@exit_msl	'R3<=#920なら処理終了
mov	r3,#e4		'自弾キャラクタ
ldrb	r2,[r4,r1]	'1行上キャラクタ
mov	r0,2		'UFO=2pts
cmp	r2,#e6		'UFO=#E6
beq	@clr_msl	'R2==#E6なら自弾クリアへ
mov	r0,0		'notUFO=0pts
cpy	r6,r4
cmp	r2,#e0
blt	@mov_msl	'R2<#E0なら自弾移動へ
cmp	r2,#e3
bgt	@mov_msl	'R2>#E3なら自弾移動へ
mov	r0,1		'Invader=1pts
@clr_msl
mov	r3,0		'自弾クリア
mov	r6,0		'自弾位置クリア
@mov_msl
strb	r3,[r4,r1]	'1行上に自弾orクリア
@exit_msl		'処理終了
strh	r6,[r5,r1]	'自弾位置保存
pop	{r4,r5,r6}
ret
MixJuiceでのダウンロードURLは下記になります。
インベーダー1 http://tagiyasoft.blog.jp/invader1.bin
インベーダー2 http://tagiyasoft.blog.jp/invader2.bin

以下のように入力してD/Lしてください。
NEW
? MJ GET tagiyasoft.blog.jp/invader1.bin
? MJ GET tagiyasoft.blog.jp/invader2.bin

ブラウザでD/LしてIchigoJamに転送する場合は、通信ソフトでバイナリ送信をしてください。
(例:TeraTermの場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

↑このページのトップヘ