Kotlinのサンプルを紹介します ①
Kotlinでのプログラミングを学習するためテトリスのようなものを作っていきます。
Kotlin習得のためなるべくプログラムだけで実装したいと思います。
一から冷静に始めていきたいと思います。
プロジェクト作成
プロジェクトを作成します。
LanguageにKotlinを選択します。

図形表示させる
テトリスで使う図形は四角形と線ですかね。
この二つで何とか表現できるかと思います。
これらを表示するための処理はひとまずMainActivity.ktに記述していきます。
四角形を表示させます。
図形を表示させる場合、PaintクラスとCanvasクラスを使用するようです。
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 |
package euniclus.tetris import android.content.Context import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Rect import android.view.View class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(Graphic(this)) } inner class Graphic(context: Context): View(context) { private var paint: Paint = Paint() override fun onDraw(canvas: Canvas) { // 四角形を表示 paint.style=Paint.Style.FILL paint.color=Color.argb(255,255,0,255) canvas.drawRect(Rect(110,210,190,290),paint) } } } |

次は線を表示します。
線でフィールド(フィールドという言い方が正しいかはわかりませんが)を表現します。
表示する場所は真ん中周辺にしておきます。
onDrawメソッドに以下の記述を追加します。
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 |
// ラインを表示 val wm: WindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager val disp = wm.getDefaultDisplay() val size = Point() disp.getSize(size) val startX = 200f val startY = 300f val height = 1000 val width = 700 val sqSize = 100 for (i in 0..height/sqSize ) { paint.style = Paint.Style.STROKE paint.color = Color.argb(255, 190,200,255) paint.strokeWidth = 10f canvas.drawLine(startX, startY+i*sqSize ,startX+width,startY+i*sqSize , paint) } for (i in 0..width/sqSize ) { paint.style = Paint.Style.STROKE paint.color = Color.argb(255, 190,200,255) paint.strokeWidth = 10f canvas.drawLine(startX+i*sqSize , startY,startX+i*sqSize ,startY+height, paint) } |

これでテトリス作成に当たり必要なものを表示することができました。
しかしこのまま進めていくとすべての処理をMainActivityに書くことになってしまうため、ソースコードの整備をしま
以下のファイルを追加します
- 図形を表示するクラス
- ブロックに関する処理を行うクラス
- フィールドに関する処理を行うクラス
- パラメーターを記述するファイル(Const.kt)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package euniclus.tetris import android.support.v7.app.AppCompatActivity import android.os.Bundle class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(Graphic(this)) } } |
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 |
package euniclus.tetris import android.content.Context import android.graphics.* import android.view.View // 図形を表示するクラス class Graphic(context: Context): View(context) { private var paint: Paint = Paint() override fun onDraw(canvas: Canvas) { // ブロックを表示 drawBlock(canvas) // フィールドを表示 drawField(canvas) } private fun drawBlock(canvas: Canvas) { val block = Block() block.draw(canvas) } private fun drawField(canvas: Canvas) { val field = Field() field.draw(canvas, context) } } |
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 |
package euniclus.tetris import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Rect import java.util.* // ブロックに関する処理を行うクラス class Block { private var paint: Paint = Paint() init { paint.style= Paint.Style.FILL paint.color= Color.argb( 255, Random().nextInt(200), Random().nextInt(200), Random().nextInt(200)) } fun draw(canvas: Canvas) { canvas.drawRect(Rect( BLOCKSTARTX, BLOCKSTARTY, BLOCKSTARTX+BLOCKSIZE, BLOCKSTARTY+BLOCKSIZE),paint) } } |
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 |
package euniclus.tetris import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Point import android.view.WindowManager // フィールドに関する処理を行うクラス class Field { private var paint: Paint = Paint() fun draw(canvas: Canvas, context: Context) { val wm: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager val disp = wm.defaultDisplay val size = Point() disp.getSize(size) val startX = FIELDSTARTX val startY = FIELDSTARTY val height = FIELDHEIGHT val width = FIELDWIDTH val sqSize = SQUARESIZE for (i in 0..height/sqSize) { paint.style = Paint.Style.STROKE paint.color = Color.argb(255, 190,200,255) paint.strokeWidth = 10f canvas.drawLine(startX, startY+i*sqSize,startX+width,startY+i*sqSize, paint) } for (i in 0..width/sqSize) { paint.style = Paint.Style.STROKE paint.color = Color.argb(255, 190,200,255) paint.strokeWidth = 10f canvas.drawLine(startX+i*sqSize, startY,startX+i*sqSize,startY+height, paint) } } } |
図形の位置や大きさを定義するファイルです。
ここにパラメーターを追加していきたいと思います。
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 |
package euniclus.tetris /** * Block */ // 四角形のサイズ val BLOCKSIZE = 80 // 間隔 val BLOCKSPACE = 20+BLOCKSIZE // ブロックの表示開始位置 x val BLOCKSTARTX = 210 // ブロックの表示開始位置 y val BLOCKSTARTY = 210 /** * Field */ // 表示開始位置 val FIELDSTARTX = 200f // 表示開始位置 val FIELDSTARTY = 300f // フィールドの高さ val FIELDHEIGHT = 1000 // フィールドの幅 val FIELDWIDTH = 700 // フィールドのマスの大きさ val SQUARESIZE = 100 |
ブロックの体裁を整える
今は四角形一つだけが表示されている状態ですので、
テトリスらしく複数の四角形を組み合わせてブロックを数種類作成します。
Const.ktに以下の記述を追加します。
ひとつの四角形を中心にそこからオフセットを指定してブロックを作成します。
その値を配列で定義します。
今はとりあえず4種類ですね。
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 |
// 表示開始位置からのオフセットを配列で持つ val BlockTypeA = arrayOf( intArrayOf(0,0), intArrayOf(BLOCKSPACE,0), intArrayOf(BLOCKSPACE*2,0), intArrayOf(0,-BLOCKSPACE) ) val BlockTypeB = arrayOf( intArrayOf(0,0), intArrayOf(BLOCKSPACE,0), intArrayOf(BLOCKSPACE*2,0), intArrayOf(BLOCKSPACE*3,0) ) val BlockTypeC = arrayOf( intArrayOf(0,0), intArrayOf(BLOCKSPACE,0), intArrayOf(BLOCKSPACE*2,0), intArrayOf(BLOCKSPACE,-BLOCKSPACE) ) val BlockTypeD = arrayOf( intArrayOf(0,0), intArrayOf(BLOCKSPACE,0), intArrayOf(BLOCKSPACE,-BLOCKSPACE), intArrayOf(0,-BLOCKSPACE) ) |
上で定義した配列をブロッククラスが受け取るようにします。
そしてその配列をループで回しブロックを表示する処理を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Block(val blockInfo: Array<IntArray>) { private var paint: Paint = Paint() fun draw(canvas: Canvas) { paint.style= Paint.Style.FILL paint.color= Color.argb(255,255,0,255) for (i in 0..blockInfo.size-1) { canvas.drawRect(Rect( BLOCKSTARTX+blockInfo[i][0], BLOCKSTARTY+blockInfo[i][1], BLOCKSTARTX+BLOCKSIZE+blockInfo[i][0], BLOCKSTARTY+BLOCKSIZE+blockInfo[i][1]), paint) } } } |
そしてGraphicクラスから以下のようにして呼び出します。
1 2 |
val block = Block(BlockTypeC) block.draw(canvas) |
これを実行するとこのようになりました。

これで体裁は整ったかと思います。
あとはこれに機能を追加していくだけですね。
次回から機能の実装に入りたいと思います。