Androidアプリ開発奮闘記 漢字ゲームを作る②
こんにちは、koheiです。
Androidアプリで漢字ゲームを作ろうということで、前回の記事では、文字入力まで作成しました。
Androidアプリ開発奮闘記 漢字ゲームを作る①
前回記事の続きで、今回はゲームの完成形まで作成していきたいと思います。
※前回の記事で作成したソースをベースに処理を追加していきます。
1. 仕様
前回の記事では、文字入力画面まで作成していました。今回の記事では、
・問題表示
・問題スキップボタン
・完了ボタンで文字判定
・正解で報酬機能
などを作っていきたいと思います。
2. レイアウトの対応
まずは、今回追加するボタン等を追加していきます。
activity_draw.xmlに以下のコードを追加します。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/draw_activity" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.inomacreate.mojigame1.DrawActivity"> <SurfaceView android:id="@+id/surfaceView" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginBottom="60dp" android:layout_marginEnd="32dp" android:layout_marginStart="32dp" android:layout_marginTop="100dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.611" /> <Button android:id="@+id/button_ansset" android:layout_width="0dp" android:layout_height="45dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="15dp" android:layout_marginTop="8dp" android:text="完了" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/button_clear" app:layout_constraintTop_toBottomOf="@+id/surfaceView" app:layout_constraintVertical_bias="1.0" /> <Button android:id="@+id/button_undo" android:layout_width="0dp" android:layout_height="45dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="戻る" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/button_redo" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/surfaceView" app:layout_constraintVertical_bias="1.0" /> <Button android:id="@+id/button_redo" android:layout_width="0dp" android:layout_height="45dp" android:layout_marginBottom="8dp" android:layout_marginEnd="2dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="進む" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/button_clear" app:layout_constraintStart_toEndOf="@+id/button_undo" app:layout_constraintTop_toBottomOf="@+id/surfaceView" app:layout_constraintVertical_bias="1.0" /> <Button android:id="@+id/button_clear" android:layout_width="0dp" android:layout_height="45dp" android:layout_marginBottom="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="クリア" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@+id/button_redo" app:layout_constraintTop_toBottomOf="@+id/surfaceView" app:layout_constraintVertical_bias="1.0" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="問題" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/problem_text" android:layout_width="135dp" android:layout_height="33dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="TextView" app:layout_constraintBottom_toTopOf="@+id/surfaceView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.072" app:layout_constraintStart_toEndOf="@+id/textView2" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0" /> <TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="認識文字" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/problem_text" /> <TextView android:id="@+id/ans_box" android:layout_width="110dp" android:layout_height="33dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" app:layout_constraintStart_toEndOf="@+id/textView4" app:layout_constraintTop_toBottomOf="@+id/problem_text" /> <Button android:id="@+id/button_skip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="スキップ" app:layout_constraintBottom_toTopOf="@+id/surfaceView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.755" app:layout_constraintStart_toEndOf="@+id/ans_box" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.916" /> <TextView android:id="@+id/textView6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="たまったお金" app:layout_constraintBottom_toTopOf="@+id/button_skip" app:layout_constraintEnd_toStartOf="@+id/text_money" app:layout_constraintStart_toEndOf="@+id/problem_text" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/text_money" android:layout_width="80dp" android:layout_height="20dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginTop="8dp" app:layout_constraintBottom_toTopOf="@+id/button_skip" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/textView6" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout> |
3. 問題表示、スキップの対応
次に、問題の表示、スキップ処理の対応を実装していきます。
まずは、問題用のテーブル、スキップボタン用の変数をDrawActivityクラス内に宣言します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class DrawActivity extends AppCompatActivity implements View.OnClickListener{ private SurfaceView mSurfaceView; private SurfaceHolder mHolder; private Paint mPaint; private Path mPath; private Bitmap mLastDrawBitmap; private Canvas mLastDrawCanvas; private int offset_x = 0; private int offset_y = 0; private Button undobt; private Button redobt; private Button clearbt; private Button skipbt; private Deque<Path> mUndoStack = new ArrayDeque<Path>(); private Deque<Path> mRedoStack = new ArrayDeque<Path>(); Map<Integer, String> problem_map; public int problem_cnt = 0; public TextView problem_txt; |
onCreateメソッド内に、問題の設定と表示処理を投入します。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_draw); // map登録 problem_map = new HashMap<Integer,String>() { { put(0,"音[どく]"); put(1,"花の[え]"); put(2,"字の[かたち]"); put(3,"文を[か]く"); put(4,"名を[し]る"); put(5,"きたと[みなみ]"); put(6,"手を[ちか]づける"); put(7,"[おな]じ色"); put(8,"せが[たか]い"); put(9,"[ほそ]い糸"); put(10,"[ちち]の日"); put(11,"[あに]"); put(12,"[おや]"); put(13,"[とも]だちとあそぶ"); put(14,"[からだ]"); put(15,"うんこは、[し]ぜんのまま"); put(16,"[け]いとでうんこ"); put(17,"きょうはにち[よう]日"); } }; // 問題表示 problem_txt = (TextView)findViewById(R.id.problem_text); problem_txt.setText(problem_map.get(problem_cnt)); // ボタンリスナ登録 undobt = (Button) findViewById(R.id.button_undo); undobt.setOnClickListener(this); redobt = (Button) findViewById(R.id.button_redo); redobt.setOnClickListener(this); clearbt = (Button) findViewById(R.id.button_clear); clearbt.setOnClickListener(this); skipbt = (Button) findViewById(R.id.button_skip); skipbt.setOnClickListener(this); // SurfaceView取得 mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView); // SurfaceHolder取得 mHolder = mSurfaceView.getHolder(); // コールバックを設定 mHolder.addCallback(mCallBack); // ペイントを設定 mPaint = new Paint(); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(30); } |
onClickメソッドにスキップボタンの処理を実装します。
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 |
@Override public void onClick(View view) { switch (view.getId()) { case R.id.button_undo: undo(); break; case R.id.button_redo: redo(); break; case R.id.button_clear: reset(); break; case R.id.button_skip: problem_cnt++; if(problem_cnt>problem_map.size()-1)problem_cnt=0; problem_txt.setText(problem_map.get(problem_cnt)); TextView output2 = (TextView) findViewById(R.id.ans_box); output2.setText(""); reset(); break; default: break; } } |
4.文字判定処理を組み込む
今回漢字ゲームで手書きで書いた漢字を判定するため、「tess-two」というライブラリを使うことにします。
4-1. ライブラリの設定
まずは、bulid.gradleに以下を追加します。
1 2 3 |
dependencies { implementation 'com.rmtheis:tess-two:9.0.0' } |
以下のサイトから文字を判定するための学習データ「jpn.traineddata」をダウンロードします。
tessdata
次に、プロジェクトのassetsフォルダーにtessdataというディレクトリを作り、その中にダウンロードした「jpn.traineddata」を格納します。(以下に手順記載します)
まずは、assetsフォルダーを作ります。appフォルダで右クリック→[New]→[Folder]→[Assets Folder]を選択し、assetsフォルダーを作ります。
assetsフォルダーで右クリック→[New]→[Directory]で、tessdataというディレクトリをつくります。
作成したtessdata内に、ダウンロードした「jpn.traineddata」をドラッグして格納します。以下のような構成にしましょう。
4-2. 文字判定処理実装
まずは、正解判定用のテーブル、完了ボタン、tess-two用の変数などをDrawActivityに追加します。
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 |
public class DrawActivity extends AppCompatActivity implements View.OnClickListener{ private SurfaceView mSurfaceView; private SurfaceHolder mHolder; private Paint mPaint; private Path mPath; private Bitmap mLastDrawBitmap; private Canvas mLastDrawCanvas; private int offset_x = 0; private int offset_y = 0; private Button undobt; private Button redobt; private Button clearbt; private Button skipbt; private Button anssetbt; private Deque<Path> mUndoStack = new ArrayDeque<Path>(); private Deque<Path> mRedoStack = new ArrayDeque<Path>(); Map<Integer, String> problem_map; Map<Integer, String> ans_map; public int problem_cnt = 0; public TextView problem_txt; TessBaseAPI tessBaseAPI; |
次に、onCreateメソッド内に、正解判定テーブル、完了ボタンのリスナー登録などを実装します。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_draw); // map登録 problem_map = new HashMap<Integer,String>() { { put(0,"音[どく]"); put(1,"花の[え]"); put(2,"字の[かたち]"); put(3,"文を[か]く"); put(4,"名を[し]る"); put(5,"きたと[みなみ]"); put(6,"手を[ちか]づける"); put(7,"[おな]じ色"); put(8,"せが[たか]い"); put(9,"[ほそ]い糸"); put(10,"[ちち]の日"); put(11,"[あに]"); put(12,"[おや]"); put(13,"[とも]だちとあそぶ"); put(14,"[からだ]"); put(15,"うんこは、[し]ぜんのまま"); put(16,"[け]いとでうんこ"); put(17,"きょうはにち[よう]日"); } }; ans_map = new HashMap<Integer, String>() { { put(0,"読"); put(1,"絵"); put(2,"形"); put(3,"書"); put(4,"知"); put(5,"南"); put(6,"近"); put(7,"同"); put(8,"高"); put(9,"細"); put(10,"父"); put(11,"兄"); put(12,"親"); put(13,"友"); put(14,"体"); put(15,"自"); put(16,"毛"); put(17,"曜"); } }; // 問題表示 problem_txt = (TextView)findViewById(R.id.problem_text); problem_txt.setText(problem_map.get(problem_cnt)); // ボタンリスナ登録 undobt = (Button) findViewById(R.id.button_undo); undobt.setOnClickListener(this); redobt = (Button) findViewById(R.id.button_redo); redobt.setOnClickListener(this); clearbt = (Button) findViewById(R.id.button_clear); clearbt.setOnClickListener(this); skipbt = (Button) findViewById(R.id.button_skip); skipbt.setOnClickListener(this); anssetbt = (Button) findViewById(R.id.button_ansset); anssetbt.setOnClickListener(this); // SurfaceView取得 mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView); // SurfaceHolder取得 mHolder = mSurfaceView.getHolder(); // コールバックを設定 mHolder.addCallback(mCallBack); // ペイントを設定 mPaint = new Paint(); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(30); } |
文字の判定処理はすごく時間がかかる処理なので、AsyncTaskという仕組みを使ってバックグラウンドで処理させたいと思います。
以下のように、DrawActivityクラス内にAsyncTaskを継承したOCRchecktaskを実装します。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
private class OCRchecktask extends AsyncTask<String, String, String> { String filepath = getFilesDir() + "/tesseract/"; @Override public String doInBackground(String... Params) { String result = ""; result = OCRcheck(); return result; } @Override public void onPostExecute(String result) { TextView output = findViewById(R.id.ans_box); output.setText(result); // 正解判定 if(result.equals(ans_map.get(problem_cnt))) { Toast.makeText(DrawActivity.this, "正解だよー!", Toast.LENGTH_LONG).show(); reset(); output.setText(""); } else { Toast.makeText(DrawActivity.this, "残念!もう一回チャレンジだ!", Toast.LENGTH_SHORT).show(); reset(); return; } problem_cnt++; if(problem_cnt>problem_map.size()-1) problem_cnt=0; problem_txt.setText(problem_map.get(problem_cnt)); } private String OCRcheck() { filepath = getFilesDir() + "/tesseract/"; Log.i("debug",filepath); tessBaseAPI = new TessBaseAPI(); checkFile(new File(filepath + "tessdata/")); tessBaseAPI.init(filepath,"jpn"); tessBaseAPI.setPageSegMode(TessBaseAPI.PageSegMode.PSM_SINGLE_CHAR); tessBaseAPI.setRectangle(0,0,mSurfaceView.getWidth(),mSurfaceView.getHeight()); tessBaseAPI.setImage(mLastDrawBitmap); String result = tessBaseAPI.getUTF8Text(); Log.i("debug","認識結果="+result); return result; } private void checkFile(File file) { if (!file.exists() && file.mkdirs()){ copyFiles(); } if(file.exists()) { String datafilepath = filepath+ "/tessdata/jpn.traineddata"; File datafile = new File(datafilepath); if (!datafile.exists()) { copyFiles(); } } } private void copyFiles() { try { String datapath = filepath + "/tessdata/jpn.traineddata"; InputStream instream = getAssets().open("tessdata/jpn.traineddata"); OutputStream outstream = new FileOutputStream(datapath); byte[] buffer = new byte[1024]; int read; while ((read = instream.read(buffer)) != -1) { outstream.write(buffer, 0, read); } outstream.flush(); outstream.close(); instream.close(); File file = new File(datapath); if (!file.exists()) { throw new FileNotFoundException(); } } catch (Exception ex) { ex.printStackTrace(); } } } |
最後に、完了ボタンを実装します。完了ボタンが押されたら、さっき作成した「OCRchecktask」を起動するようにします。
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 41 |
@Override public void onClick(View view) { switch (view.getId()) { case R.id.button_undo: undo(); break; case R.id.button_redo: redo(); break; case R.id.button_clear: reset(); break; case R.id.button_skip: problem_cnt++; if(problem_cnt>problem_map.size()-1)problem_cnt=0; problem_txt.setText(problem_map.get(problem_cnt)); TextView output2 = (TextView) findViewById(R.id.ans_box); output2.setText(""); reset(); break; case R.id.button_ansset: // 答え合わせ TextView output = (TextView) findViewById(R.id.ans_box); output.setText("判定中"); OCRchecktask ocRchecktask = new OCRchecktask(); ocRchecktask.execute(); break; default: break; } } |
5.報酬機能の追加
子どもたちのテンションを上げるため、正解したら、難易度に応じて報酬がもらえるようにしてみました。
まずは、もらえた報酬額を表示するテキストビューと報酬額用テーブルを宣言します。
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 |
public class DrawActivity extends AppCompatActivity implements View.OnClickListener{ private SurfaceView mSurfaceView; private SurfaceHolder mHolder; private Paint mPaint; private Path mPath; private Bitmap mLastDrawBitmap; private Canvas mLastDrawCanvas; private int offset_x = 0; private int offset_y = 0; private Button undobt; private Button redobt; private Button clearbt; private Button skipbt; private Button anssetbt; private Deque<Path> mUndoStack = new ArrayDeque<Path>(); private Deque<Path> mRedoStack = new ArrayDeque<Path>(); Map<Integer, String> problem_map; Map<Integer, String> ans_map; public int problem_cnt = 0; public TextView problem_txt; TessBaseAPI tessBaseAPI; public TextView money_txt; Map<Integer,Integer> money_map; |
獲得した報酬は、ゲームが終わってもAndroid上に保存しておくようにします。
SharedPreferencesという仕組みを使えば、データを保存することができます。
まずは、報酬額を保存する処理と取得する処理を作成します。DrawActivity内に以下の処理を実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 |
public void money_save(int money) { SharedPreferences data = getSharedPreferences("DataSave", Context.MODE_PRIVATE); SharedPreferences.Editor editor = data.edit(); editor.putInt("Money",money); editor.apply(); } public int money_get() { SharedPreferences data = getSharedPreferences("DataSave",Context.MODE_PRIVATE); int money = data.getInt("Money",0); return money; } |
onCreate処理に、報酬額のテーブルと、テキスト表示処理を実装します。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_draw); // map登録 problem_map = new HashMap<Integer,String>() { { put(0,"音[どく]"); put(1,"花の[え]"); put(2,"字の[かたち]"); put(3,"文を[か]く"); put(4,"名を[し]る"); put(5,"きたと[みなみ]"); put(6,"手を[ちか]づける"); put(7,"[おな]じ色"); put(8,"せが[たか]い"); put(9,"[ほそ]い糸"); put(10,"[ちち]の日"); put(11,"[あに]"); put(12,"[おや]"); put(13,"[とも]だちとあそぶ"); put(14,"[からだ]"); put(15,"うんこは、[し]ぜんのまま"); put(16,"[け]いとでうんこ"); put(17,"きょうはにち[よう]日"); } }; ans_map = new HashMap<Integer, String>() { { put(0,"読"); put(1,"絵"); put(2,"形"); put(3,"書"); put(4,"知"); put(5,"南"); put(6,"近"); put(7,"同"); put(8,"高"); put(9,"細"); put(10,"父"); put(11,"兄"); put(12,"親"); put(13,"友"); put(14,"体"); put(15,"自"); put(16,"毛"); put(17,"曜"); } }; money_map = new HashMap<Integer, Integer>() { { put(0,500); put(1,300); put(2,300); put(3,200); put(4,300); put(5,100); put(6,100); put(7,100); put(8,100); put(9,200); put(10,100); put(11,100); put(12,500); put(13,100); put(14,100); put(15,100); put(16,100); put(17,500); } }; // 問題表示 problem_txt = (TextView)findViewById(R.id.problem_text); problem_txt.setText(problem_map.get(problem_cnt)); // お金表示 money_txt = (TextView)findViewById(R.id.text_money); money_txt.setText(String.valueOf(money_get())); |
正解した時の処理(onPostExecute)に報酬額を取得する処理を実装します。
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 |
@Override public void onPostExecute(String result) { TextView output = findViewById(R.id.ans_box); output.setText(result); // 正解判定 if(result.equals(ans_map.get(problem_cnt))) { Toast.makeText(DrawActivity.this, "正解だよー!お金"+String.valueOf(money_map.get(problem_cnt))+"円ゲット!!", Toast.LENGTH_LONG).show(); reset(); output.setText(""); int money = money_get() + money_map.get(problem_cnt); money_save(money); money_txt.setText(String.valueOf(money_get())); } else { Toast.makeText(DrawActivity.this, "残念!もう一回チャレンジだ!", Toast.LENGTH_SHORT).show(); reset(); return; } problem_cnt++; if(problem_cnt>problem_map.size()-1) problem_cnt=0; problem_txt.setText(problem_map.get(problem_cnt)); } |
以上で実装が完了しました。
試しにシミュレータで動かしてみましょう!
ちゃんと動作しました!
最後に
以上、Androidアプリの漢字ゲームを作ってみました。
今回文字判定は、「tess-two」というライブラリを使いました。結構丁寧に文字を書かないとなかなか正解してくれなかったり、文字判定に時間かかったりとイマイチな部分もありますが、とりあえず完成したのでよかったです。
他にもいろんなAndroidアプリ制作に挑戦してみたいと思います!
それでは!!
スポンサーリンク