2016年12月

  • タイトル
    インベーダー

  • 開発環境
    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の場合は、メニューの[ファイル]-[ファイル送信]で当該ファイルを送信します)

  • 題名
    JOLTSZX (電子工作マガジン2016年WINTER号掲載)

  • 開発環境
    IchigoJamBASIC1.1.1

  • 内容
    テトリスもどきゲームです。TETRIS

  • 遊び方
    キー操作で落ちてくるピースを操作して底から積み上げていきます。
    1列全て揃うとその段が消えて、段が詰まります。
    最上段まで積み上がってしまうとゲームオーバーです。

  • 操作方法
    テンキーでピースを操作します。

    [1]:左移動
    [2]:回転
    [3]:右移動

    回転方向は時計回りのみで、落下はありません。

  • プログラムのしくみ


  • 変数表
    A現位置のピース形状(復帰用に保存)
    B現位置のピース形状
    C移動後のピース形状
    D回転後のピース形状
    Kピースの高さ
    Pピース種類
    Qピースの向き
    R回転後のピースの向き
    U移動後のピースの位置
    V現在のピースの位置
    L入力キー
    Sスコア
    I,Jループ用
    W頻出数=32
    [0]~[27]ピース形状
    <br/>
    各行の処理
    10行コメント行
    20行機械語サブルーチン、初期画面作成
    30行ピース形状
    40行ピースの出現、キー入力
    50行ピースが移動できるか?
    60行回転前のピースを消去
    70行移動前のピースを消去
    80行移動後のピースを描画
    90行積み上がったらピースのキャラクタを変更
    100行1段揃ったか?
    110行1段落とす
    120行ピース出現に戻る


    1段落ちの処理はBASICだと処理が遅いので機械語にしました。

    各ピースは下記の形状をしており、1バイトで表され、配列変数に納められます。
    画面表示の時に、左下から右上にかけて、1bit~8bitの順に展開されます。
    ○は常に空マスで、ピースの描画基点となります。
    3x3マスで表示するため、オリジナルのテトリスにある「I」形状は無く、代わりに「+」形状が使われています。

    各ビットを展開した時の並び方
     123
    1■■○
    2■■
    3
     #D8
    
     123 123
    1  ○ ■ ○
    2 ■■ ■■
    3■■   ■ 
     #33	 #5A
    
     123 123
    1  ○  ■○ 
    2■■  ■■ 
    3 ■■ ■  
     #1E	 #99
    
     123 123 123 123
    1■■○   ○  ■○   ○
    2■   ■■■  ■  ■
    3■     ■ ■■  ■■■
     #C9	 #3C	 #93	 #0F
    
     123 123 123 123
    1  ○  ■○   ○ ■■○
    2■■■  ■    ■  ■
    3■    ■■ ■■■  ■
     #39	 #96	 #27	 #D2
    
     123 123 123 123
    1  ○  ■○  ■○  ■○ 
    2■■■ ■■  ■■■  ■■ 
    3 ■   ■       ■  
     #3A	 #9A	 #B8	 #B2
    
     123 123 123
    1 ■○
    2■ ■
    3 ■
     #AA
    
    

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

  • プログラムの改造
    40行の「P=RND(7)」を「P=RND(6)」にすると「+」のピースが出現しなくなるので少しだけ簡単になります。


  • JOLTSZX
    10 'テトリス
    20 CLS:CLV:W=32:poke#8A0,3,70,202,92,32,51,202,84,64,59,26,10,8,42,248,209,1,48,2,70,15,35,26,64,11,42,240,209,112,71:LC15,0:?"SCORE:":FORI=0TO19:POKE#900+I*W,2:POKE#90B+I*W,2:IFI<12POKE#B80+I,2
    30 NEXT:LET[0],216,216,216,216,51,90,51,90,30,153,30,153,201,60,147,15,57,150,39,210,58,154,184,178,170,170,170,170
    40 V=#925:P=RND(7):Q=RND(4):R=Q:FORK=0TO18:U=V+W:L=INKEY():IFLL=(L-1)%3-1:IFL=0R=(Q+1)%4ELSEU=V+W+L
    50 A=[P*4+R]:B=A:FORI=0TO2:FORJ=0TO2:IFB&1ANDPEEK(U-I*W+J)=2IFK=0LC15,5:?"GAME OVER":ENDELSEI=3:J=3:IFQ<>RR=Q:NEXT:NEXT:GOTO50ELSEIFLU=U-L:L=0:NEXT:NEXT:GOTO50ELSEU=U-W:K=18
    60 B=B>>1:NEXT:NEXT:B=A:C=B:D=[P*4+Q]:FORI=0TO2:FORJ=0TO2:IFD&1POKEV-I*W+J,0
    70 IFB&1POKEV-I*W+J,0
    80 IFC&1POKEU-I*W+J,1
    90 B=B>>1:C=C>>1:D=D>>1:NEXT:NEXT:V=U:Q=R:NEXT:B=A:FORI=0TO2:FORJ=0TO2:IFB&1POKEV-I*W+J,2
    100 B=B>>1:NEXT:NEXT:FORI=0TO19:FORJ=0TO9:IFPEEK(#B61-I*W+J)=0J=20
    110 NEXT:IFJ=9S=S+1:LC23,0:?S:FORJ=0TO9:POKE(#B61-I*W+J),0:NEXT:J=USR(#8A0,#B40-I*W):I=-1
    120 NEXT:GOTO40
    


    機械語サブルーチン(一段落ち)
    USR(#8A0,*)
    引数:消えた行の1行上のアドレス/戻値:無し(不定)
    @LBL1
    cpy	R3,R0		'R3=R0		'R3=転送元アドレス(USR引数)
    @LBL2
    ldrb	R2,[R1,R3]	'R2=[R1+R3]	'キャラクタ=[実アドレス+転送元アドレス]
    add	r3,#20		'R3+=#20	'R3=転送先アドレス
    strb	r2,[r1,r3]	'[R1+R3]=R2	'[実アドレス+転送元アドレス]=キャラクタ
    sub	r3,#40		'R3-=#40	'R3=転送元アドレスを1行上
    lsr	r2,r3,8		'R2=R3>>8	'R2=転送元アドレスの上位バイト
    cmp	r2,#8		'R2-8		'R2が8か?(転送元アドレスが#8**か?)
    bne	@LBL2		'IF!0GOTO @LBL2	'偽なら@LBL2へ
    add	r0,#1		'R0+=1		'転送元アドレスを隣の列へ
    cpy	r2,r0		'R2=R0		'R2=転送元アドレス
    mov	r3,#f		'R3=#0F		'マスク
    and	r2,r3		'R2&=R3		'R2の下8bit
    cmp	r2,#b		'R2-#0B		'11列めか?
    bne	@LBL1		'IF!0GOTO @LBL1	'偽なら@LBL1へ
    ret			'RET
    
MixJuiceでのダウンロードURLは下記になります。
TETRIS http://tagiyasoft.blog.jp/tetris.bin

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

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

↑このページのトップヘ