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

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

ただいまの
回答率

89.97%

円の当たり判定が上手くいかなく、また、当たり判定の座標がずれます

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,374

ko20vonobird

score 48

実現したいこと

onDrawで描いた図形に当たり判定を設けて連動させたいです。

困っていること

なぜか当たり判定が行われるところがずれているのと、円の当たり判定が全くなされないです。

該当のソースコード

全文です

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

import static java.lang.Math.pow;

public class Main extends Activity {
    Screen sc;
    private TextView textView;
    private int winW, winH;
    private int winW2,winH2;
    private int colchk = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        //setContentView(R.layout.activity_main);

        sc = new Screen(this);
        parts();
    }
    public void parts() {
        FrameLayout fl = new FrameLayout(this);
        this.setContentView(fl);
        fl.addView(sc);
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
        fl.addView(ll);
        String action = "Touch Event";
        textView = new TextView(this);
        textView.setText(action);
        textView.setTextSize(36.0f);
        ll.addView(textView);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float tx = event.getX();
        float ty = event.getY();
        WindowManager wm2 = (WindowManager)getSystemService(WINDOW_SERVICE);
        Display dp2 = wm2.getDefaultDisplay();
        Point po2 = new Point();
        dp2.getSize(po2);
        winW2 = po2.x;
        winH2 = po2.y;
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                if (pow(tx - (winW - 120),2) + pow(ty - (winH - 110),2) < 2500 || pow(tx - 120,2) + pow(ty - (winH - 110),2) < 2500 || (70 <= tx && tx <= 270) && (winH - 160 <= ty && ty <= winH - 60) || (winW - 270 <= tx && tx <= winW - 70) && (winH - 160 <= ty && ty <= winH - 60)){
                    sc.colchange();
                }else{
                    sc.colreturn();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (pow(tx - (winW - 120),2) + pow(ty - (winH - 110),2) < 2500 || pow(tx - 120,2) + pow(ty - (winH - 110),2) < 2500 || (70 <= tx && tx <= 270) && (winH - 160 <= ty && ty <= winH - 60) || (winW - 270 <= tx && tx <= winW - 70) && (winH - 160 <= ty && ty <= winH - 60)){
                    sc.colchange();
                }else{
                    sc.colreturn();
                }
                break;
            case MotionEvent.ACTION_UP:
                sc.colreturn();
                break;
        }
        textView.setText("x:" + tx + "y:" + ty);
        textView.setTextSize(14.0f);
        return super.onTouchEvent(event);
    }
    public class Screen extends View {
    public Screen(Context context) {
        super(context);
    }
    protected void onDraw(Canvas c) {
        super.onDraw(c);
        WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
        Display dp = wm.getDefaultDisplay();
        Point po = new Point();
        dp.getSize(po);
        winW = po.x;
        winH = po.y;
        int wxa = winW - 320;
        int wxb = winW - 20;
        int wya = winH - 160;
        int wyb = winH - 60;
        int r = 50;
        RectF arear = new RectF(wxa, wya, wxb, wyb);
        RectF areal = new RectF(20,wya,320,wyb);
        Paint p = new Paint();
        c.drawColor(Color.WHITE);
        p.setARGB(100,50,215,50);
        if (colchk == 1){
            p.setARGB(100,200,50,50);
            colchk = 0;
        }
        p.setStyle(Paint.Style.FILL);
        c.drawRoundRect(arear,r,r,p);
        c.drawRoundRect(areal,r,r,p);
    }
    public void colchange() {
        colchk = 1;
        invalidate();
    }
    public void colreturn() {
        colchk = 0;
        invalidate();
    }
    }
}


以下で描画しています

WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
        Display dp = wm.getDefaultDisplay();
        Point po = new Point();
        dp.getSize(po);
        winW = po.x;
        winH = po.y;
        int wxa = winW - 320;
        int wxb = winW - 20;
        int wya = winH - 160;
        int wyb = winH - 60;
        int r = 50;
        RectF arear = new RectF(wxa, wya, wxb, wyb);
        RectF areal = new RectF(20,wya,320,wyb);
        Paint p = new Paint();
        c.drawColor(Color.WHITE);
        p.setARGB(100,50,215,50);
        if (colchk == 1){
            p.setARGB(100,200,50,50);
            colchk = 0;
        }
        p.setStyle(Paint.Style.FILL);
        c.drawRoundRect(arear,r,r,p);
        c.drawRoundRect(areal,r,r,p);


以下が当たり判定の部分です

if (pow(tx - (winW2 - 120),2) + pow(ty - (winH2 - 110),2) < 2500 || pow(tx - 120,2) + pow(ty - (winH2 - 110),2) < 2500 || 70 <= tx && tx <= 270 && winH2 - 160 <= ty && ty <= winH2 - 60 || winW2 - 270 <= tx && tx <= winW2 - 70 && winH2 - 160 <= ty && ty <= winH2 - 60){
                    sc.colchange();
                }else{
                    sc.colreturn();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (pow(tx - (winW2 - 120),2) + pow(ty - (winH2 - 110),2) < 2500 || pow(tx - 120,2) + pow(ty - (winH2 - 110),2) < 2500 || 70 <= tx && tx <= 270 && winH2 - 160 <= ty && ty <= winH2 - 60 || winW2 - 270 <= tx && tx <= winW2 - 70 && winH2 - 160 <= ty && ty <= winH2 - 60){
                    sc.colchange();
                }else{
                    sc.colreturn();
                }

補足

感覚ですが、四角い当たり判定のゾーンが存在しているのですが、その位置が描かれるものと数十ずれていると思われます。半円の部分が当たり判定されていないので円が当たり判定されていないのかと思われます。

修正点

・クリック処理を無くしました
・ORとANDにおいて()でくくるべき箇所を()でくくりました。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yona

    2017/01/18 02:04

    判定処理はどのクラスのどのメソッドから呼ばれていますか?

    キャンセル

  • ko20vonobird

    2017/01/18 10:07

    判定処理は、MainクラスのonTouchEventメソッド?から呼ばれているはずです。また、全文を載せました。

    キャンセル

回答 3

checkベストアンサー

+1

問題点

  • Screen#onClick内でcolchkが1になっているので、どこでもいいのでクリックしただけで当たったことになっている

  • drawRoundRectということは角丸矩形ですよね?角丸矩形の当たり判定を取りたいならこの判定式は全然成り立っていません。やりかたは色々ありますが、私が思いつく方法としては「角丸部分を除いた四角形が十字型に2つあると過程して判定を取る&角丸部分を円の4分の1であると考えて4隅分4回判定する」となります。

  • 描画のときは画面右下端から320、160の位置から300、100の大きさで書いているのに、当たり判定で使っている数値は右下端から120、110の位置を中心に50の大きさの円、画面左下から70、160の位置から200、100の大きさの矩形、画面右下から270、160の位置から200、100の大きさの矩形のように見えます

  • 当たり判定も条件のORとANDの結合優先度がめちゃくちゃで、各条件がカッコで囲まれていないため全く思ったとおりの判定にはなっていないでしょう

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/18 11:52

    一項目目について、クリック処理に関しましては誤って残したままでしたので削除しました。
    二項目目について、確かに角丸ですが、四分の一の円がくっついて半円になるように描画をしているので、円が両脇にくっついている四角形を二個と捉えて判定処理を行わせております。
    三項目目について、調査中です。
    四項目目について、括弧で囲み修正しました。

    キャンセル

  • 2017/01/18 12:23

    円についても解決しました、ありがとうございました。

    キャンセル

+1

onTouchEventで取得できるタッチイベントは画面左上が原点の座標系です。
Canvasの描画系のメソッドで使われる座標はViewの左上を原点とした座標系です。
そのため、Viewの左上と画面の左上が一致しない限りタッチイベントと描画の位置は一致しないですよ。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/18 10:18

    そうなのですか、初めて知りました、ありがとうございます。
    Viewの左上が原点とありますが、Viewはスマホのどこを原点にしているのでしょうか?
    あと、どのみち円の判定がなされていないのですが、この原因は何なのでしょうか?

    キャンセル

  • 2017/01/18 10:49

    あなたが配置したViewの位置は私にはわかりません。

    円の判定については判定処理が誤っているんじゃないですか。各値をコンソールに出力し、想定とどう異なるかを確認してください。

    キャンセル

  • 2017/01/18 11:03

    了解しました。
    円について、二乗のところをpow(num,2)としているのですが、そもそもこれが合っているのか疑問です。一応AndroidStudioの指示の通りに書いたのですが。また、==とイコールは二個続けて書きますが不等式は二つ続けたりはしませんよね?

    キャンセル

  • 2017/01/18 12:23

    解決しました、ありがとうございました。

    キャンセル

0

四角い当たり判定のゾーンに色を付けて描画してみたら何か分かるんじゃないでしょうか

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/17 23:20

    後でやってみます。しかし、同じ値を設定しているはずなので文としては納得いきませんよね、、、

    キャンセル

  • 2017/01/18 12:24

    解決しました、ありがとうございました。

    キャンセル

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

  • ただいまの回答率 89.97%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる