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

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

ただいまの
回答率

87.49%

Java Turtleアプレット「一匹の亀をドラッグすると、三匹の他の亀がそれぞれ1/2,1/3,2倍の距離を同時に動くようにしたい。」 

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 4,169

score 95

こんにちは、Java初心者です。
Turtleアプレットの作成を通じて、イベント処理とオブジェクト指向の学習をしています。
現在、亀に足跡を描かせるクラス。Turtleクラスをを用いて、4匹の亀を生成します。うち1匹をドラッグすると、それに伴って他の亀が同じ向きで距離だけ異なって移動し、図形を描画させたいです。
頑張って考えたのですが、実際に動かしてみると、全く描画されません。
急ぎなので、わかる方お願いします!

Turtle.java
import java.applet.Applet;
import java.awt.*;
import java.util.*;

public class Turtle{

    //インスタンス変数の宣言

    int x, y;
    double angle = 0;
    int pensize = 1;
    Color pencolor = Color.black;

    ArrayList<Point> points = new ArrayList<Point>();


    //コンストラクタの定義

    Turtle(int i, int j){
    x = i;
    y = j;
    //亀さんの座標を決定

    points.add(new Point(x, y));
 
    }



    //各種メソッドの定義
    
    //現在位置から進行方向に向かって距離lengthだけ移動する。
  
    public void move(double length){
    int i = points.size()-1;
    Point pt = points.get(i);
    int x_l = (int)Math.round(length * Math.cos(angle)) + pt.x;
    int y_l = (int)Math.round(length * Math.sin(angle)) + pt.y;

    points.add(new Point(x_l, y_l));
    }
    
    //進行方向をdegだけ左回転する。
    public void turn(double deg){
    angle -= deg;           
    } 

    //ペンの太さを設定する。

    public void PenSize(int size){
    pensize = size;
    }

    //ペンの色を設定する

    public void penColor(Color c){
    pencolor = c;
    }

    //亀の軌跡の描画

    public void paint(Graphics g){
    g.setColor(pencolor);

    int i;
    int px[] = new int[points.size()];
    int py[] = new int[points.size()];
    for( i = 0; i < points.size(); i++){
        Point p_i = points.get(i);
        px[i] = p_i.x;
        py[i] = p_i.y;
    }
    g.drawPolyline(px, py, points.size());    
    }
}
Turtle2.java
import java.applet.Applet;
import java.awt.*;
import java.util.*;

public class Turtle2{

    Turtle kame[] = new Turtle[4];

    Turtle2(Turtle k[]){
    kame = k;
    }

    void move(double length){
    kame[0].move(length);
    kame[1].move(length/2);
    kame[2].move(length/3);
    kame[3].move(length*2);
    }

    void turn(double deg){
    for(int i = 0; i < 4; i++){
        kame[i].turn(deg);
    }
    }

    void paint(Graphics g){
    for(int i = 0; i < 4; i++){
        kame[i].paint(g);
    }
    }
    
}

Rabbit.java
import java.applet.Applet;
import java.awt.*;
import java.util.*;
import java.awt.event.*;


public class Rabbit extends Applet implements MouseMotionListener{
    int current_x;     //マウスの現在のx座標
    int current_y;     //マウスの現在のy座標
    Turtle kame[] = new Turtle[4];
    Turtle2 Usagi = new Turtle2(kame);
    double deg = 0;
    double length = 0;
    double pi = Math.PI;
    Image  imgs;
 

    public void init(){
    setBackground(Color.white);
          imgs= getImage(getDocumentBase(), "kame2.gif");

    kame[0] = new Turtle(100, 100);
    kame[1] = new Turtle(300, 100);
    kame[2] = new Turtle(100, 300);
    kame[3] = new Turtle(300, 300);

    //addMouseListener(this);

    addMouseMotionListener(this);

    }
    
    public void mouseDragged(MouseEvent e){
    
           int size = kame[0].points.size() - 1;
    Point p_0 = kame[0].points.get(size);
    if(current_x >= p_0.x && current_x <= p_0.x+68 && current_y >= p_0.y && current_y <= p_0.y + 48){
        current_x = e.getX();
        current_y = e.getY();
        kame[0].points.add(new Point(current_x, current_y));
    }
    repaint();
    }

    public void mouseMoved(MouseEvent e){

    }
    
    

    public void paint(Graphics g){
    int size = kame[0].points.size() - 1;
    for(int i = 0; i < 4; i++){
        g.drawImage(imgs, kame[i].points.get(size).x, kame[i].points.get(size).y, this);
    }
    g.setColor(Color.black);
    Point p_0 = kame[0].points.get(size - 1);
    double dx = current_x - p_0.x;
    double dy = current_y - p_0.y;
    deg = Math.atan2(dy, dx);
    if( deg != 0   || deg != pi || deg != -pi){
        length = dx;
    }
    else{
        length = dy/Math.sin(deg);
    }
        Usagi.turn(deg);
    Usagi.move(length);
    Usagi.paint(g);
    }
}
解決「現在は実行時エラーです。
また、実行時エラーにならずとも、足跡が描画されなかったり、右下にしか亀が動かなかったりします。」

現在、実行した段階でなぜか毎回決まった線が描画されてしまっています。

修正後
Turtle.java
public class Turtle{

    //インスタンス変数の宣言

    int x, y;
    double angle = 0;

    ArrayList<Point> points = new ArrayList<Point>();


    //コンストラクタの定義

    Turtle(int i, int j){
    x = i;
    y = j;
    points.add(new Point(x, y));
 
    }
    //各種メソッドの定義
    public void move(double x, double y){
    int i = points.size() - 1;
    Point pt = points.get(i);

    points.add(new Point( (int)x+pt.x, (int)y+pt.y));
    }

    //亀の軌跡の描画

    public void paint(Graphics g){
    
    g.setColor(pencolor);

    int i;
        int px[] = new int[points.size()];
    int py[] = new int[points.size()];
    for( i = 0; i < points.size(); i++){
        Point p_i = points.get(i);
        px[i] = p_i.x;
        py[i] = p_i.y;
    }
    g.drawPolyline(px, py, points.size());    
    
    }
}
Turtle2.java
public class Turtle2{

    Turtle kame[] = new Turtle[4];

    Turtle2(Turtle k[]){
    kame = k;
    }

    void move(double x, double y){
    kame[1].move(x/2, y/2);
    kame[2].move(x/3, y/3);
    kame[3].move(x*2, y*2);
    

    void paint(Graphics g){
    for(int i = 0; i < 4; i++){
        kame[i].paint(g);
    }
    }
    
}
Rabbit.java
public class Rabbit extends Applet implements MouseListener, MouseMotionListener{
    int current_x;     //マウスの現在のx座標
    int current_y;     //マウスの現在のy座標
    Turtle kame[] = new Turtle[4];
    Turtle2 Usagi = new Turtle2(kame);
    Image  imgs;
 

    public void init(){
    setBackground(Color.white);
          imgs= getImage(getDocumentBase(), "kame2.gif");

    kame[0] = new Turtle(100, 100);
    kame[1] = new Turtle(300, 100);
    kame[2] = new Turtle(100, 300);
    kame[3] = new Turtle(300, 300);

    addMouseListener(this);

    addMouseMotionListener(this);

    }
    
    public void mouseDragged(MouseEvent e){
    
           int size = kame[0].points.size() - 1;
    Point p_0 = kame[0].points.get(size);
    if(current_x >= p_0.x && current_x <= p_0.x+68 && current_y >= p_0.y && current_y <= p_0.y + 48){
        current_x = e.getX();
        current_y = e.getY();
        kame[0].points.add(new Point(current_x, current_y));
        repaint();
    }
    }

    public void mouseMoved(MouseEvent e){

    }

    public void mouseClicked(MouseEvent e){

    }
    public void mouseEntered(MouseEvent e){

    }
    public void mouseExited(MouseEvent e){
    
    }

    public void mousePressed(MouseEvent e){
    
    }

    public void mouseReleased(MouseEvent e){
    
    }   

    public void paint(Graphics g){
    for(int i = 0; i < 4; i++){
        
        int size = kame[i].points.size() - 1;
        
        Point p_cur = kame[i].points.get(size - 1);
        Point p_prev = kame[i].points.get(size - 1);
        double dx = p_cur.x - p_prev.x;
        double dy = p_cur.y - p_prev.y;
        Usagi.move(dx, dy);
        g.drawImage(imgs, kame[i].points.get(size).x, kame[i].points.get(size).y,this);
    }
    g.setColor(Color.black);
    Usagi.paint(g);
    }
}
こんなかんじになりました。現在実行時エラーです(´;ω;`)
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

変更点は2つです。
描画と亀の動きを弄るところを分けました。

mouseDraggedで亀を移動させる時、他の亀の移動も処理しています。
paintメソッドでは描画のみを実行しています。

public class Rabbit extends Applet implements MouseListener, MouseMotionListener{
    public void mouseDragged(MouseEvent e){
        int size = kame[0].points.size() - 1;
        Point p_0 = kame[0].points.get(size);
        if(current_x >= p_0.x && current_x <= p_0.x+68 && current_y >= p_0.y && current_y <= p_0.y + 48){
            current_x = e.getX();
            current_y = e.getY();

            kame[0].points.add(new Point(current_x, current_y));
            // 他の亀はドラッグにあわせて動くので、ここで座標も弄りましょう
            Point p_cur = kame[0].points.get(kame[0].points.size() - 1);
            Point p_prev = kame[0].points.get(kame[0].points.size() - 2);
            double dx = p_cur.x - p_prev.x;
            double dy = p_cur.y - p_prev.y;
            Usagi.move(dx, dy); // 他の亀の移動

            repaint();
        }
    }

    public void paint(Graphics g){
    // 描画に関することだけやります
    for(int i = 0; i < 4; i++){
        int size = kame[i].points.size() - 1;
        g.drawImage(imgs, kame[i].points.get(size).x, kame[i].points.get(size).y,this);
    }
    g.setColor(Color.black);
    Usagi.paint(g);
    }
}

先ほど見せていただいた修正後のコードを見たのですが、どこで実行時エラーがでているかまではちょっとわかりませんでした。
動きも予想で書いているのでチグハグなところがあるかもしれません。



旧回答
これは…まとめて質問に答えるのはたぶん難しいので気づいたところだけ。

右下にしか亀が動かなかったりします。
public void move(double length){
    int i = points.size()-1;
    Point pt = points.get(i);
    int x_l = (int)Math.round(length * Math.cos(angle)) + pt.x;
    int y_l = (int)Math.round(length * Math.sin(angle)) + pt.y;

    points.add(new Point(x_l, y_l));
}
これではMath.roundの結果分常に他の亀は右下に進み続けてしまいます。
移動距離だけ渡すなら、xとyを別々に計算してそれぞれの亀の現在位置に加算するようにしましょう。
(上に100移動していたらy=-100, 他の亀は-50, -33,-200 する、下に100移動なら+50,+30,+200)

実行時エラーについては…
ぱっと見ですがpublic void paint(Graphics g)の以下の部分は初期状態で長さ2以上あるのでしょうか?(points.size() - 2 の位置を参照しても大丈夫ですか?)
Point p_0 = kame[0].points.get(size - 1);

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/06/02 19:55

    ありがとうございます!

    キャンセル

  • 2015/06/02 20:05

    もう一つ気になったことが・・・

    mouseDraggedで座標を処理していますが、これだと移動範囲がかなり狭められてしまいます。
    下記はドラッグの開始位置を調整したいコードだと思いますが、ドラッグ中の座標移動でよばれるコードなのでこれでは右下にしか移動できません。
    if(current_x >= p_i.x && current_x <= p_i.x+68 && current_y >= p_i.y && current_y <= p_i.y + 48){
    }

    このソースコードを消してみてください。左上に移動できるようになりますが、一方でどこをクリックしても亀が移動できるようになると思います。

    そこまで書いたら、mousePressed と mouseReleased の二つのイベントを使って
    亀をドラッグ中か判定するフラグ処理を作ってみてください

    }

    キャンセル

  • 2015/06/02 20:39

    できました!
    長い時間私に付き合っていただき本当にありがとうございました!!

    キャンセル

+1

ドラッグするということは、マウスボタンを離した所まで移動するということになりますね。
ドラッグを始めた位置→ドラッグを終えた位置という2点の情報が得られるはずです。
この2点のx差分とy差分を調べます。左上の亀を左下へ50ずつ動かしたとしましょう。
右下座標系、右へ行けばxがプラス、下へ行けばyがプラスという前提で。
100,100から50,150へ移動したと思います。
ということはx差分は50-100で-50、y差分は150-100で+50ですね。
この差分値を他の亀の座標に加算してあげれば良いのです。
右上の亀は300,100なので250,150。左下の亀は100,300なので50,350。右下はの亀は250,350になります。

ドラッグ中もマウスの動きを監視して描画させたい場合も同じで、前回の位置と今回の位置の差分をとって、他の亀の位置へ加算すれば良いです。

あ、掲題に書いてある「二分の一、三分の一、二倍」については、その差分値を1/2, 1/3, 2倍してから加算すれば良いです。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

同じタグがついた質問を見る

  • トップ
  • Javaに関する質問
  • Java Turtleアプレット「一匹の亀をドラッグすると、三匹の他の亀がそれぞれ1/2,1/3,2倍の距離を同時に動くようにしたい。」