IntelliJ IDEAでScala on Android using sbt Part.1[じゃんけんアプリ]
こちらの記事を参考に、ScalaでAndroidのじゃんけんアプリを書きました。
IDEはIntelliJ IDEA CE 2016.2で、ビルドツールはsbt 0.13.12を使っています。
動作確認は、API level 23のAndroidエミュレータで実施しました。
目次
Scala on Androidでじゃんけんアプリ
手の画像を配置したImageButton
を押すと、相手*1とじゃんけんができるだけのアプリです。
参考元の記事で言及されている通り、リソース画像やOnClickListenerの扱いの勉強になりました。
ソースコードをGitHubに置いてますので、動かしてみる場合はこちらの記事を参考にして下さい。
プロジェクトディレクトリの構成
~/RockPaperScissors
|- build.sbt // sbtのビルド定義ファイル
|- /project // sbt関連の設定ファイルを配置するディレクトリ
|- /src // アプリのモジュールを構成するディレクトリ
| |- /main // アプリのメインソースセットを配置するディレクトリ
| | |- AndroidManifest.xml // アプリに関する情報を記述するマニフェストファイル
| | |- /libs // 外部ライブラリを配置するディレクトリ
| | |- /res // リソースファイルを配置するディレクトリ
| | | |- /drawable-mdpi // 中解像度の画像を配置するディレクトリ
| | | |- /drawable-hdpi // 高解像度の画像を配置するディレクトリ
| | | |- /drawable-xhdpi // 超高解像度の画像を配置するディレクトリ
| | | | |- ic_launcher.png // アプリのアイコン画像
| | | | |- rock.png // じゃんけんのぐーの画像
| | | | |- scissor.png // じゃんけんのちょきの画像
| | | | |- paper.png // じゃんけんのぱーの画像
| | | |- /drawable-xxhdpi // 超超高解像度の画像を配置するディレクトリ
| | | |- /drawable-xxxhdpi // 超超超高解像度の画像を配置するディレクトリ
| | | |- /layout // レイアウトの定義ファイルを配置するディレクトリ
| | | | |- activity_main.xml // 画面レイアウトの定義ファイル
| | | |- /values // 配色や文字の定義ファイルを配置するディレクトリ
| | |
| | |- /scala // Scalaのコードを配置するディレクトリ
| | |- /com.b0npu.rpsgame // アプリのパッケージディレクトリ
| | |- MainActivity.scala // アプリのメインファイル
| |
| |- /test // テストコードを配置するディレクトリ
|
|- /target // ビルドで生成された成果物の出力先ディレクトリ
主なソースコード
Empty Activityテンプレートのactivity_main.xml
にWidgetを配置し、MainActivity.scala
でWidgetのリソースID
を取得して操作しています。
アプリ名は、res/values/strings.xmls
のapp_name
で定義しています。
また、APKファイルの名前は、build.sbt
のname :=
で定義しています。
activity_main.xml
- Text
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context="com.b0npu.rpsgame.MainActivity"> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/rockButton" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="60dp" android:src="@drawable/rock" android:minHeight="96dp" android:minWidth="96dp" android:scaleType="fitXY"/> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/scissorButton" android:src="@drawable/scissor" android:layout_alignBottom="@+id/rockButton" android:layout_centerHorizontal="true" android:minHeight="96dp" android:minWidth="96dp" android:scaleType="fitXY"/> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/paperButton" android:src="@drawable/paper" android:layout_alignTop="@+id/scissorButton" android:layout_alignParentRight="true" android:scaleType="fitXY" android:minHeight="96dp" android:minWidth="96dp"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/playerMove" android:src="@drawable/rock" android:layout_below="@+id/resultText" android:layout_centerHorizontal="true" android:layout_marginTop="40dp" android:minHeight="96dp" android:minWidth="96dp"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/enemyMove" android:src="@drawable/rock" android:layout_marginTop="40dp" android:layout_alignParentTop="true" android:layout_alignLeft="@+id/playerMove" android:minHeight="96dp" android:minWidth="96dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/resultText" android:text="Rock Paper Scissors 1 2 3..." android:textSize="24dp" android:gravity="center" android:layout_below="@+id/enemyMove" android:layout_centerHorizontal="true" android:layout_marginTop="40dp"/> </RelativeLayout>
- Design
MainActivity.scala
package com.b0npu.rpsgame import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.View import android.view.View.OnClickListener import android.widget.{ImageButton, ImageView, TextView} class MainActivity extends AppCompatActivity with TypedFindView { /** * フィールドの定義 * * widgetのidを格納する変数とじゃんけんで使う変数を定義する * じゃんけんで使う変数は変更しないのでvalで定義 */ var rockButton: ImageButton = _ var scissorButton: ImageButton = _ var paperButton: ImageButton = _ var playerMove: ImageView = _ var enemyMove: ImageView = _ var resultText: TextView = _ val handSigns = Map[String, Int]( "Rock" → R.drawable.rock, "Scissor" → R.drawable.scissor, "Paper" → R.drawable.paper ) val handsArray = handSigns.keys.toArray /** * アプリの画面を生成 * * アプリを起動するとonCreateが呼ばれてActivityが初期化され * setContentViewでレイアウトがビューに表示される */ override def onCreate(savedInstanceState: Bundle): Unit = { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) /** * widgetのidを取得 * * sbt-androidプラグインのTyped Resources(TR)を使って * レイアウトに設置したwidgetのidを変数に格納する */ rockButton = findView(TR.rockButton) scissorButton = findView(TR.scissorButton) paperButton = findView(TR.paperButton) playerMove = findView(TR.playerMove) enemyMove = findView(TR.enemyMove) resultText = findView(TR.resultText) /** * ButtonをClickしてじゃんけん * * ClickしたButtonのImageをRPSGameメソッドに渡してじゃんけんする */ rockButton.setOnClickListener(new OnClickListener() { override def onClick(v: View): Unit = { RPSGame(handsArray.indexOf("Rock")) } }) scissorButton.setOnClickListener(new OnClickListener() { override def onClick(v: View): Unit = { RPSGame(handsArray.indexOf("Scissor")) } }) paperButton.setOnClickListener(new OnClickListener() { override def onClick(v: View): Unit = { RPSGame(handsArray.indexOf("Paper")) } }) } /** * じゃんけんのメソッド * * 引数でplayerのhandSignを受け取ってRandomでenemyのhandSignを決める * handSignはRock: 0, Scissor: 1, Paper: 2の数字を割り当てているので * ((playerSign - enemySign) + 3 ) % 3の結果で勝敗が決まる * 0: Draw, 1: Lose, 2: Win */ private def RPSGame(playerSign: Int): Unit = { val gameResult = Map[Int, String]( 0 → "Draw", 1 → "Oh You Lose...", 2 → "You Win!!" ) val enemySign = scala.util.Random.nextInt(3) val result = (playerSign - enemySign + 3) % 3 playerMove.setImageResource(handSigns(handsArray(playerSign))) enemyMove.setImageResource(handSigns(handsArray(enemySign))) resultText.setText(gameResult(result)) } }
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">じゃんけん</string> </resources>
build.sbt
・
・
・
name := "RPSGame"
・
・
・
Run/Debugの実行結果
うまくいけば、じゃんけんで暇が潰せます。
参考記事
ScalaやAndroidに関しては、こちらの記事を参考にさせていただきました。
じゃんけんアプリの作成に関しては、こちらの記事を参考にさせていただきました。
開発環境
- OSX 10.11.6 El Capitan
- IDE: InteiijJ IDEA Community Edition 2016.2
- Java Development Kit: Java SE Development Kit 8u101
- Android SDK Tools: android-sdk_r24.4.1-macosx
- Android Virtual Device: Android 6.0(Google APIs) API level 23 - Scala 2.11.8
- ビルドツール: sbt 0.13.12
関連記事
*1:相手はランダムに手を選びます