Home English

Kuina-chan

くいなちゃんOct 17, 2017


プログラミング言語Kuin」を初めて触る人に向けたチュートリアルです。

プログラム作成の流れ

kuin.exe

Kuinを手に入れたら、まずは「kuin.exe」を実行してみましょう(Kuinのファイル群)。
Kuinのファイル群
Kuinのファイル群
Kuinでの開発には、主に(1)の「kuin.exe」だけを使います。 (2)の「kuincl.exe」は、コマンドプロンプト上からコンパイルするためのツールです。
「kuin.exe」を起動するとkuin.exeの画面が現れます。
kuin.exe
kuin.exe
この「kuin.exe」は、プログラムエディタとコンパイル機能とデバッグ機能がセットになったものです。 (1)にプログラムを書き、(2)を押すとコンパイル・実行されます。
(3)では生成するプログラムの種類が選べます。 ウインドウアプリなら「ウインドウ」を、コマンドプロンプト上で実行させるアプリなら「CUI」を選びます。
コンパイル結果のログは(4)に出力され、エラー内容もここや(5)で確認できます。

Hello, world!

まずは1文字もプログラムを書いていない状態で「コンパイル&実行」、もしくはキーボードの「F5」キーを押してみてください。 画面に「Hello, world!」と表示されればコンパイル&実行は成功です(ウインドウで「Hello, world!」)。
ウインドウで「Hello, world!」
ウインドウで「Hello, world!」
まれに、ウイルス対策ソフトで警告が出るそう(exeを生成する行為が該当しているらしい?)ですが、問題なさそうであれば解除してください。
Kuinでは、何もプログラムを書かないと「Hello, world!」を画面に表示するプログラムになります。
ちなみに「CUI」を選択してコンパイル&実行するとCUIで「Hello, world!」のようになります。
CUIで「Hello, world!」
CUIで「Hello, world!」
あとは、あなたが自由にプログラムを書いてコンパイル&実行するだけです。

リリースビルド

最後に、プログラムが完成して配布したいときには「リリースビルド」を行います(リリースビルド)。
リリースビルド
リリースビルド
(1)の「リリースビルド」をクリックし、適当な名前(.zip)でアーカイブファイルを保存します。 すると、高速に動作する実行ファイルが各種ファイルと共に、必要最小限の形にまとまって生成されますので、そのままzipファイルごと配布できます。
普段の開発時には「コンパイル&実行」を押すことで、コンパイルが高速でエラーも細かく検知できる「デバッグビルド」で生成され、完成して配布するときには動作が高速で配布に適した「リリースビルド」を行う流れです。

resフォルダ

ちなみに、コンパイルするソースファイル(.kn)と同じ位置に「res」という名前のフォルダを作成しておくと、コンパイル時に中身のファイルごと実行ファイルの位置にコピーされますので、プログラム内で使うリソースファイルはresフォルダに入れると便利です(resフォルダ)。
resフォルダ
resフォルダ

アクションゲームの作成

それでは簡単なプログラムを書いてみましょう。 迫りくる敵をジャンプでかわす、アクションゲームです。
かなりざっくりと解説しますので、各関数や構文の詳しい情報は「Kuinドキュメント」を参照してください。

ウインドウの表示

まずはウインドウを表示するプログラムを書きます。 kui_jump1.knの通りです。
var wndMain: wnd@Wnd
  
func main()
  do @wndMain :: wnd@makeWnd(null, %aspect, 1600, 900, "くいじゃん")
  while(wnd@act())
  end while
end func
kui_jump1.kn
4行目の「wnd@makeWnd」関数でウインドウを作成し、1行目で宣言したグローバル変数「@wndMain」に保持させています。
5行目の「wnd@act」関数は、ウインドウメッセージを処理する関数で、これを定期的に呼ばないとウインドウはフリーズしてしまいます。 ウインドウが閉じられると「wnd@act」関数はfalseを返すため、「while」ブロックでウインドウが閉じられるまで待機しておきます。
「ウインドウモード」で実行するとくいじゃん1のようになります。
くいじゃん1
くいじゃん1

ドローコントロールと背景色

次に、グラフィックスを描画するための「ドローコントロール」を作成します。 5、6、8行目に処理を追加してください(kui_jump2.kn)。
var wndMain: wnd@Wnd
  
func main()
  do @wndMain :: wnd@makeWnd(null, %aspect, 1600, 900, "くいじゃん")
  do wnd@makeDraw(@wndMain, 0, 0, 1600, 900, %scale, %scale, false)
  do draw@clearColor(16#FF333366)
  while(wnd@act())
    do draw@render(60)
  end while
end func
kui_jump2.kn
5行目の「wnd@makeDraw」関数でドローコントロールを、「@wndMain」ウインドウの子として作成しています。
6行目の「draw@clearColor」関数は、背景色を設定する関数です。 「16#FF333366」とは16進数で、アルファ(不透明度)が「FF」、赤が「33」、緑が「33」、青が「66」という色を表します。
8行目の「draw@render」関数は、描画結果を画面に転送する関数です。 「60」という値を渡すと、60FPS(1秒間に60回描画)になるように自動でウエイトします。
drawライブラリで描画したものはバックバッファという目に見えない領域に描画されます。 このため、それを目に見える画面に転送するには「draw@render」関数を呼ぶ必要があります。 いったんバックバッファに描画することで、描画途中の状態が画面に現れず、画面のちらつきを防ぐことができます。
実行するとくいじゃん2のようになります。
くいじゃん2
くいじゃん2

プレイヤーと敵の表示

それではプレイヤーと敵を表示します。 プレイヤーと敵の変数を作成し、その座標情報に基づいて描画する流れです(kui_jump3.kn)。
class Pos()
  +var x: float
  +var y: float
  +var veloX: float
  +var veloY: float
end class
  
var player: @Pos
var enemy: @Pos
var wndMain: wnd@Wnd
  
func main()
  do @wndMain :: wnd@makeWnd(null, %aspect, 1600, 900, "くいじゃん")
  do wnd@makeDraw(@wndMain, 0, 0, 1600, 900, %scale, %scale, false)
  do draw@clearColor(16#FF333366)
  do @player :: #@Pos
  do @player.x :: 400.0
  do @player.y :: 800.0
  do @enemy :: #@Pos
  do @enemy.x :: 1500.0
  do @enemy.y :: 800.0
  do @enemy.veloX :: -10.0
  while(wnd@act())
    do draw@circle(@player.x, @player.y, 50.0, 50.0, 16#FFFFFF00)
    do draw@circle(@enemy.x, @enemy.y, 40.0, 40.0, 16#FFFF0000)
    do draw@render(60)
  end while
end func
kui_jump3.kn
1~6行目で位置と速度を表すクラス「@Pos」を定義し、8、9行目でその「@Pos」型の変数「@player」「@enemy」を作成しています。
「@player」はプレイヤーの情報、「@enemy」は敵の情報を表し、16~22行目でそれらの値を設定しています。
24、25行目では、それらの位置情報に基づき、プレイヤーと敵を円で描画しています。
実行するとくいじゃん3のようになります。
くいじゃん3
くいじゃん3

敵とプレイヤーの移動

ここから先は、「while(wnd@act())」から「end while」の間だけを書き換えるため、その部分のプログラムだけを抜粋して掲載します。 敵の移動処理を加えます(kui_jump4.kn)。
  while(wnd@act())
    do @enemy.x :+ @enemy.veloX
    if(@enemy.x < -40.0)
      do @enemy.x :: 1640.0
      do @enemy.veloX :: -lib@rndFloat(6.0, 50.0)
    end if
    do draw@circle(@player.x, @player.y, 50.0, 50.0, 16#FFFFFF00)
    do draw@circle(@enemy.x, @enemy.y, 40.0, 40.0, 16#FFFF0000)
    do draw@render(60)
  end while
kui_jump4.kn
2行目では位置X「@enemy.x」に速度X「@enemy.veloX」を加えています。 これを繰り返すことで、敵は徐々に横に移動します。
3~6行目は、敵が画面の左端まで行ってしまったときに、右端に戻す処理です。 そのとき速度「@enemy.veloX」を「-6.0~-50.0」の範囲の乱数で変更しておきます。
実行すると、敵が速度を変えながら何度も迫り来ることがわかります。
さて次は、プレイヤー側も敵をよけられるように、ジャンプできるようにします(kui_jump5.kn)。
  while(wnd@act())
    do @enemy.x :+ @enemy.veloX
    if(@enemy.x < -40.0)
      do @enemy.x :: 1640.0
      do @enemy.veloX :: -lib@rndFloat(6.0, 50.0)
    end if
    do @player.veloY :+ 1.0
    do @player.y :+ @player.veloY
    if(@player.y > 800.0)
      do @player.y :: 800.0
      do @player.veloY :: 0.0
    end if
    if(input@pad(0, %a) = 1 & @player.y = 800.0)
      do @player.veloY :: -20.0
    end if
    do draw@circle(@player.x, @player.y, 50.0, 50.0, 16#FFFFFF00)
    do draw@circle(@enemy.x, @enemy.y, 40.0, 40.0, 16#FFFF0000)
    do draw@render(60)
  end while
kui_jump5.kn
7行目では速度Y「@player.veloY」に下向きの加速度「1.0」を加えています。 これは重力に相当します。
8行目では位置Y「@player.y」に速度Y「@player.veloY」を加えています。 この段階でプレイヤーには重力が加わり、下向きにどんどん落下していきます。
9~12行目は、プレイヤーが地面より下まで落下しないように接地させる処理です。 地面よりも下にいた場合、位置Yを地面の位置「800.0」に補正し、速度Yも「0.0」にリセットしています。
13~15目は、ジャンプの処理です。 「%a」つまりゲームパッドの「Aボタン」が押されて、かつプレイヤーが接地していたら、速度Y「@player.veloY」を「-20.0」に設定することで、上向きに投げ上げるようなジャンプ運動をします。
ゲームパッドの「Aボタン」はキーボードの「Zキー」や「スペースキー」などに割り当てられているため、キーボードでも操作できます。
実行するとくいじゃん4のようになります。
くいじゃん4
くいじゃん4

衝突

最後に衝突判定をします(kui_jump6.kn)。
  while(wnd@act())
    if(lib@dist(@enemy.x, @enemy.y, @player.x, @player.y) < 50.0 + 40.0)
      do draw@rect(0.0, 0.0, 1600.0, 900.0, 16#FFCC3333)
      do draw@circle(@player.x, @player.y, 50.0, 50.0, 16#FFFFFF00)
      do draw@circle(@enemy.x, @enemy.y, 40.0, 40.0, 16#FFFF0000)
      do draw@render(0)
      do lib@sleep(800)
      do @wndMain.close()
    end if
    do @enemy.x :+ @enemy.veloX
    if(@enemy.x < -40.0)
      do @enemy.x :: 1640.0
      do @enemy.veloX :: -lib@rndFloat(6.0, 50.0)
    end if
    do @player.veloY :+ 1.0
    do @player.y :+ @player.veloY
    if(@player.y > 800.0)
      do @player.y :: 800.0
      do @player.veloY :: 0.0
    end if
    if(input@pad(0, %a) = 1 & @player.y = 800.0)
      do @player.veloY :: -20.0
    end if
    do draw@circle(@player.x, @player.y, 50.0, 50.0, 16#FFFFFF00)
    do draw@circle(@enemy.x, @enemy.y, 40.0, 40.0, 16#FFFF0000)
    do draw@render(60)
  end while
kui_jump6.kn
2行目の「lib@dist」関数は、2点間の距離を求める関数です。 敵とプレイヤーの距離を求め、敵とプレイヤーの半径の和よりも小さくなれば、両者は近づきすぎて衝突していることになります。
3~8行目は衝突したときの処理です。 3行目の「draw@rect」関数で背景を赤く塗りつぶし、4~6行目でプレイヤーと敵を描画し、7行目の「lib@sleep」関数で800ミリ秒(0.8秒)待ったのち、8行目の「@wndMain.close」メソッドによってウインドウを閉じて終了しています。
本来なら、ゲームオーバー画面を出してタイトル画面に戻すとより親切です。
実行するとくいじゃん5のようになります。
くいじゃん5
くいじゃん5
以上で、アクションゲームの完成です。
今回作ったゲームは単純な見栄えになりましたが、円の代わりに画像を使ってキャラクターを描画するだけで本格的な見た目になりますし、市販の素晴らしいゲームも単純なプログラムの組み合わせで作られています。 少しずつ高みを目指すと良いでしょう!

サンプルプログラムの実行

さて、「samples」フォルダには、いくつかのサンプルを収録しています。 これらのサンプルには様々な技法が駆使されて作られていますので、参考にしてみてください。
サンプルを開くには、ファイルを開くの(1)をクリックします。
ファイルを開く
ファイルを開く
ちなみに(2)では作成したプログラムが保存できます。
試しに「samples/0000_kuinvaders/main.kn」を開いてみましょう。 ウインドウモードでコンパイル&実行すると、「Kuinvaders(くいんべーだー)」が実行されます(Kuinvaders)。
Kuinvaders
Kuinvaders
付属のサンプルはいずれもウインドウモード向けプログラムです。
収録されているサンプルはKuinのサンプル一覧の通りです。
Kuinのサンプル一覧
フォルダ名 概要
0000_kuinvaders インベーダーゲーム「Kuinvaders(くいんべーだー)」
0001_kuinote 単純なテキストエディタ「Kuinote(くいのーと)」
0002_draw_2d 2Dの描画方法をまとめたサンプル
0003_draw_3d 3Dの描画方法をまとめたサンプル
0004_sound 音の再生方法をまとめたサンプル
0005_input 入力デバイスからの取得方法をまとめたサンプル
0007_random 乱数の生成方法をまとめたサンプル
0008_time 時間の扱い方をまとめたサンプル
0009_file ファイルの読み書きの方法をまとめたサンプル
Kuinドキュメント」にある各機能の説明と照らし合わせることで、機能の使い方が把握できると思います。
以上、チュートリアル「はじめてのKuin」でした。 ここから先のチュートリアルでは、プログラムでよく使う手法を具体的に説明しますので、必要になったときに好きな順序で読み進めてください!
1508205700ja