あかんわ

覚えたことをブログに書くようにすれば多少はやる気が出るかと思ったんです

IntelliJ IDEAでScala on Android using sbt Part.1[じゃんけんアプリ]

こちらの記事を参考に、ScalaAndroidのじゃんけんアプリを書きました。

IDEIntelliJ 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.xmlWidgetを配置し、MainActivity.scalaWidgetリソースIDを取得して操作しています。
アプリ名は、res/values/strings.xmlsapp_nameで定義しています。
また、APKファイルの名前は、build.sbtname :=で定義しています。

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
    f:id:b0npu:20160813141058p:plain
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の実行結果

うまくいけば、じゃんけんで暇が潰せます。
f:id:b0npu:20160813140139g:plain

参考記事

ScalaAndroidに関しては、こちらの記事を参考にさせていただきました。

じゃんけんアプリの作成に関しては、こちらの記事を参考にさせていただきました。

開発環境

関連記事

*1:相手はランダムに手を選びます