質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

4195閲覧

JavaのTimerTaskがうまく動作しない

dyarumokumu

総合スコア16

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2018/10/29 04:52

前提・実現したいこと

現在marioAIを使って勉強していて、その中で穴に落ちそうになったら壁キックをするようなエージェントをつくりたい。

発生している問題・エラーメッセージ

TimerTask内の1つめの処理しか実行されず、次の処理にうまく移ってくれない

該当のソースコード

Java

1if(action[Mario.KEY_RIGHT] && isOnTheRightWall(r, c)) { 2 Timer timer1 = new Timer(), 3 timer2 = new Timer(), 4 timer3 = new Timer(), 5 timer4 = new Timer(); 6 action[Mario.KEY_JUMP] = false; 7 timer1.schedule(new TimerTask() { 8 public void run() { 9 action[Mario.KEY_JUMP] = isMarioAbleToJump; 10 } 11 }, 50); 12 timer1.cancel(); 13 timer1 = null; 14 timer2.schedule(new TimerTask() { 15 public void run() { 16 action[Mario.KEY_RIGHT] = !action[Mario.KEY_RIGHT]; 17 } 18 }, 51); 19 timer2.cancel(); 20 timer2 = null; 21 timer3.schedule(new TimerTask() { 22 public void run() { 23 action[Mario.KEY_LEFT] = !action[Mario.KEY_LEFT]; 24 } 25 }, 52); 26 timer3.cancel(); 27 timer3 = null; 28 timer4.schedule(new TimerTask() { 29 public void run() { 30 action[Mario.KEY_JUMP] = isMarioAbleToJump || !isMarioOnGround; 31 } 32 }, 53); 33 timer4.cancel(); 34 timer4 = null; 35 }

試したこと

上に示したコードではtask1つ1つにtimerを用意していますが、もともとは4つのtaskを1つにまとめて、timerも1つにして実装していましたが、挙動は現在のコードと変わりませんでした。taskやtimerについては宣言する場所を変えてみたり、cancel()の位置を変えてみたりもしました。また、Thread.sleep()も使ってみましたが、marioAIの実行自体が止まってしまいました。

補足情報(FW/ツールのバージョンなど)

上のコードを実際に試してみたところ、壁にぶつかりそうになるとジャンプキーが無効になった後、ちょっとしてから有効になって、壁をけった後は1度無効になって再度有効になります。ほかのキーに関しては、右・左キーともに変化しませんでした。
そもそもなぜこのように遅延を設けているのかということですが、地形情報の取得が画面内の規定のグリッド単位でしか行えないため、(今回であれば)右側の壁にマリオが接しているという状態は、実際に壁に衝突するより少し前にしか判断できないので、壁にちゃんと接してからジャンプキーを有効にしたいことが理由です。
また、壁キックですが、接している壁の側の方向キー及びダッシュ(のための)キーを有効にすることで可能となり、壁キックが可能であることはisMarioAbleToJumpを使うことで検出できます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

java

1timer1.schedule(new TimerTask() { 2 public void run() { 3 action[Mario.KEY_JUMP] = isMarioAbleToJump; 4 } 5 }, 50); 6// timer1.cancel(); この箇所がいりません 7 timer1 = null;

Timer.cancel() は、

現在スケジュールされているタスクを破棄して、このタイマーを終了します。現在実行中のタスク(ある場合)には干渉しません。タイマーが終了すると、実行スレッドも同時に終了し、タスクはスケジュールされなくなります。 java8-api java.util.Timer#cancel()

ということで、実行するとスレッドは実行されません。

なぜあなたが言っていた動作になるかわかりませんが、Java8では少なくともこうなります。

あと、できたらコードはクラスごと貼り付けてほしいです。変数等がわかりにくいです。長文失礼いたしました。

投稿2018/10/29 10:18

yukkuri

総合スコア624

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dyarumokumu

2018/10/29 11:00

回答有り難うございます 変数等に関しては自分で作ったものではなく、元から用意されているものですが、説明不足でした、すいません 奇妙な挙動の原因としてtimerに関する処理がすべて終わる前に再び同じ条件分岐の中に入ってしまっているのではないかと考えたのですが、if文の中にtimerによる処理が含まれる場合、その処理が終わるまでif文の外には抜けないのでしょうか?
yukkuri

2018/10/29 11:11

実際に説明すると長く難しくなりますのでまとめると、Timer は スレッドです。(マルチスレッドのインターフェースを実装しているため(正確には少し違うかも)) なので、並行して処理が行われているように見えます。これを防ぐためには、synchronized というキーワードを使います。詳しくはネットに良い情報があるので調べてみてください。
dyarumokumu

2018/10/29 12:25

ありがとうございます!調べてみます また分からなかったら質問すると思うので、よかったら回答してください
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問