Javaでブロック崩しゲームを作る

# ブロック崩し
最近、Javaを勉強しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/4f5a9081-7f23-8872-b3a7-8eddf866f2a4.png)

こんな感じのブロック崩しを作りました。
想像以上に難しかったです。
オブジェクト指向って修正がしやすく、わかりやすく書ける気がします。


## オブジェクト

1. ボール
1. 反射板（操作可能）
1. 障害物
1. 壁

このうち**ボール以外は線分の組み合わせ**だと考えられます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/92c347e3-86d9-a3de-ca97-79649e5ba1ec.png)
障害物がこのように長方形の場合、4つの線分で障害物を構成できます。

そこで、**”線分クラス”**　を作り、障害物や壁・反射板は　**”線分インスタンス”の集まり**としました。
こう考えることで、**線分とボールの反射だけ**を考えるのみで、全ての  "オブジェクト-ボールの反射"  を考えられます。
どういうことかというと
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/d5d4607a-d806-736b-b04b-aea2ad260c72.png)
このようにボールが障害物に向かって進んでいる状況の場合、**反射後の位置の計算**が必要になります。
これを、**”線分インスタンス”とボールの反射**が起きているのみだと考えることで

1. 記述量が少なくなる（障害物・壁・反射板全て同じ計算になる）
1. ボールの軌道も"線分"と考えることで、線分同士の計算となる。よって**反射先計算が線分クラス内でまとまる**

非常に有益であるといえます。

# 反射計算

1. 衝突するか判定
1. 反射後の地点計算

この二つになります。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/b6569593-d07e-f1ea-caf6-204ee772b6f3.png)

この状況の場合、

1. ボールの線分（軌道）と障害物の線分**全てとの交点を計算**
1. 交点が線分内か検証（**線分が交わっているか調べる**）
1. ボールの線分の支点から、交点への**距離を計算**
1. **一番近い交点で反射が起こる**
1. 反射先を計算
1. 1に戻る

という計算の流れになります。
一番近いというのは、次のような状況への対処が必要なためです。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/633cd3c6-5685-7f8a-d68f-74bdf220dfd1.png)
この場合、交点は4つありますが、反射するのは一番近い交点となります。
よって線分クラスに必要な機能が二つあります。

1. 線分同士の交点計算
1. 交点が線分内に存在するか（線分が交わっているか） 
1. 交点から線分の始点（ボールの軌道線分はベクトルとして考える）への距離の計算

## 交点計算
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/8c469040-ef4e-6d87-fb33-8d8a7934bd6e.png)
このように、二つの線分があるとき、交点を計算すると

```math
p_x = -\frac{(x_1'-x_2')(x_1 y_2-x_2 y_1)  -  (x_1-x_2)(x_1' y_2'-x_2' y_1') }
{(x_1'-x_2')(y_1 - y_2) - (x_1-x_2)(y_1' - y_2')}\\

p_y = \frac{  (y_1-y_2)(x_1' y_2'-x_2' y_1') - (y_1'-y_2')(x_1 y_2-x_2 y_1)  }
{(x_1'-x_2')(y_1 - y_2) - (x_1-x_2)(y_1' - y_2')}\\

```
となります。
ここで、分母が0となるのは、二つの線分が平行であるときです（外積と同じ計算してるので０＝平行）。

## 反射先計算
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/b795c576-f67e-9e73-d142-d46dd7e616d2.png)
このように、線分とベクトルがぶつかった状況を考えます。
ぶつかった場合、反射します。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/0edb8d01-ef6e-490f-a907-812cb69af846.png)

こんな感じです。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/b8774f22-efaf-6757-80d1-40145e7a6366.png)

次のように名前を付けます。$\vec{e},\vec{e}_v$は線分の単位ベクトルと単位法線ベクトルです。
**$\vec{v_2}$を求めることが目標**となります。
交点が計算できているため$\vec{v_0},\vec{v_1}$は自明です。$\vec{e},\vec{e}_v$も正規化＋90度回転で計算できます。

```math
\vec{d} = - \vec{e}_v (\vec{v_1}*\vec{e}_v)\\
\vec{f} =\vec{e} (\vec{v_1}*\vec{e})\\
```

```math
\begin{eqnarray}
\therefore \vec{v_2} &=&  \vec{f}  +\vec{d} \\
&=&\vec{e} (\vec{v_1}*\vec{e})  - \vec{e}_v (\vec{v_1}*\vec{e}_v)
\end{eqnarray}
```
で計算できます。$*$は内積計算

これで軌道計算が完了です。

# プログラミング
Swingを使います。

https://qiita.com/GANTZ/items/147e7576c4a15f84785c

以前に書いた記事です。ご参考までに

### フレームの作成
JFrameを継承したクラスのインスタンスを生成した段階でフレームが生まれます。

```Java
BlockBreak frame = new BlockBreak();
```

### タイマー処理
動的に動かすには、**一定時間ごとにボールオブジェクトを動かし**、**反射を調べて**、**描画を更新していく**、必要があります。


初期設定として、

1. まずタイマーオブジェクトを生成します。
1. タイマーの時間を設定します。

```Java
Timer time = new Timer();
time.scheduleAtFixedRate(new SampleTask(), delay, period);
```
実行内容

```Java
public class Timer_task extends TimerTask {
    public void run() {
       
    }
}
```
run()内の処理が一定時間ごとに実行されます。
swingではrepaint()を実行することで描画を更新できます。
repaint()の処理内にはpaint()処理が入っています。
一般にpaint()処理をorverrideして好きな内容に書き換えるみたいです。

以上で説明が必要な部分は終わりです。
後はコードを乗せます。
ほんとはGitとか使った方がいいかもですが、それはまた今度勉強しようと思います。


# コード

### オブジェクト
BlockBreak extend JFrame

* mainを持つ
* フレーム本体

Ball

* ボール

Manipulate_obj

* 操作板

Obstacle_polygon

* 障害物

Line

* 線分

以上の構成になっています。


### 本体

#### BlockBreakクラス

```java:BlockBreak.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Timer;

public class BlockBreak extends JFrame implements KeyListener {

    private final int height = 600;
    private final int width = 600;
    private long startTime;

    Wall_Line wall;
    Ball ball;
    Obstacle_polygon obstacle1;
    Manipulate_obj board;

    ArrayList<Obstacle_polygon> obstacle_list = new ArrayList<>();


    public static void main(String[] args){
        System.out.println("Start");
        BlockBreak frame = new BlockBreak();
        java.util.Timer timer = new Timer();
        Timer_task timer_task = new Timer_task();
        timer_task.setFlame(frame);
        timer_task.setTimer(timer);
        timer_task.clearEndTimer();
        timer.scheduleAtFixedRate(timer_task, 0,30);
    }


    public BlockBreak() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(this.width, this.height);
        setVisible(true);
        this.startTime = System.currentTimeMillis();
        this.ball = new Ball(200,200,0.5,0.4,Color.red);
        ball.set_radius(4);
        ball.set_radius_Afterimage(2);
        this.wall = new Wall_Line(this.height,this.width,Color.blue);
        this.wall.set_wallSize(new int[]{10, 500}, new int[]{10, 500});
        this.obstacle1 = new Obstacle_polygon(
                new int[]{25, 145, 25, 145},new int[]{25, 25, 145, 145},Color.green);

        this.board = new Manipulate_obj(new int[]{200, 350, 350, 200},
                                        new int[]{400, 400, 420, 420},
                                        Color.green);
        this.board.set_speed(1.0);

        for(int i=0;i<10;i++){
            for(int j=0;j<4;j++){
                //i 横、j 縦
                int x1 = 70+i*40;
                int x2 = 70+i*40 + 20;
                int y1 = 50 + j*40;
                int y2 = 50 + j*40 + 20;
                this.obstacle_list.add(new Obstacle_polygon(
                        new int[]{x1, x2, x2, x1},
                        new int[]{y1, y1, y2, y2},
                        Color.green));

            }
        }
        addKeyListener(this);
    }

    @Override
    public void paint(Graphics g){
        Image imgBuf = createImage(this.width,this.height);
        Graphics gBuf = imgBuf.getGraphics();               //gBufがバッファの画像
        gBuf.setColor(Color.white);
        gBuf.fillRect(0,0,this.width,this.height);
        long now_time = System.currentTimeMillis();

        //ボールを動かす
        this.ball.move(this.width,this.height);

        //Keyboardでの入力でボードを移動する。
        //移動距離は時間を測る。
        this.board.move_speed(now_time,this.width);

        //反射処理
        this.reflection();

        if(this.wall.ball_outside_judge(this.ball)){
            System.out.println("ball outside");
            System.out.println(ball.ball_position_toString());
            while(true){
                continue;
            }
        }

        //位置を更新する
        this.ball.update();

        //描画処理開始
        this.ball.draw(gBuf);
        this.wall.draw(gBuf);
        //this.obstacle1.draw(gBuf);
        this.board.draw(gBuf);
        for(Obstacle_polygon poly:this.obstacle_list){
            poly.draw(gBuf);
        }
        //this.ball.draw_velocity(gBuf,height,width);

        //バッファを画面に表示
        Graphics graphics = getContentPane().getGraphics();
        graphics.drawImage(imgBuf,0,0,this);
    }

    public boolean ball_outside_judge(Ball ball){
        //ball が領域外にあるか判定する true->外
        double[] position = ball.get_position();
        double x = position[0];
        double y = position[1];
        if(x<0 || width < x ||
            y<0 || height < y){
            return true;
        }else{
            return false;
        }

    }
    public void reflection(){
        //反射処理：
        boolean flag = true;
        Line before_reflect_line = null;
        Obstacle_polygon min_obj = null;
        do {
            double min_distance = 1000;
            Line min_line = null;
            for (Line line : this.wall.line) {
                double distance = line.inter_section_distance(ball.ball_line);
                if (distance < min_distance && distance != 0
                        &&!line.same_line(before_reflect_line)) {
                    min_line = line;
                    min_distance = distance;
                    min_obj = null;
                }
            }
            /*
            for (Line line : this.obstacle1.line) {
                double distance = line.inter_section_distance(ball.ball_line);
                if (distance < min_distance && distance != 0
                        &&!line.same_line(before_reflect_line)) {
                    min_line = line;
                    min_distance = distance;
                }
            }
             */
            for (Line line : this.board.line) {
                double distance = line.inter_section_distance(ball.ball_line);
                if (distance < min_distance && distance != 0
                        &&!line.same_line(before_reflect_line)) {
                    min_line = line;
                    min_distance = distance;
                }
            }
            for(int i=0;i<this.obstacle_list.size();i++){
                Obstacle_polygon poly = this.obstacle_list.get(i);
                for (Line line : poly.line) {
                    double distance = line.inter_section_distance(ball.ball_line);
                    if (distance < min_distance && distance != 0
                            &&!line.same_line(before_reflect_line)) {
                        min_line = line;
                        min_distance = distance;
                        min_obj = poly;
                    }
                }
            }



            //min_line と　反射させて　ballを更新する
            if (min_line != null) {
                min_line.reflect(ball);
                before_reflect_line = min_line;
                if(min_obj != null) {
                    this.obstacle_list.remove(this.obstacle_list.indexOf(min_obj));
                }
            }else{
                flag = false;
            }
            //System.out.println(ball.ball_velocity_toString());
            //flag = false;

        }while(flag);
    }
    @Override
    public void keyTyped(KeyEvent e) {
        //使用しないので空にしておきます。
    }
    @Override
    public void keyPressed(KeyEvent e) {
        switch ( e.getKeyCode() ) {
            case KeyEvent.VK_RIGHT:
                if(!this.board.get_state()){
                    this.board.set_start_time(System.currentTimeMillis());
                }
                this.board.set_right();
                this.board.set_move();
                System.out.println("right");
                break;
            case KeyEvent.VK_LEFT:
                if(!this.board.get_state()){
                    this.board.set_start_time(System.currentTimeMillis());
                }
                this.board.set_left();
                this.board.set_move();
                System.out.println("left");
                break;
        }
    }
    @Override
    public void keyReleased(KeyEvent e) {
        switch ( e.getKeyCode() ) {
            case KeyEvent.VK_RIGHT:
            case KeyEvent.VK_LEFT:
                this.board.clear_move();
                System.out.println("stop");
                break;
        }

    }
}

```
#### TimerTaskクラス


```java:Timer_task.java
import java.util.Timer;
import java.util.TimerTask;

public class Timer_task extends TimerTask {
    BlockBreak frame_timer;
    private int num = 0;
    private boolean endFlag = true;
    Timer timer;

    public void run() {
        frame_timer.repaint();
        num++;

        if(num>1000 && endFlag == true){
            System.out.println("End");
            cancel();
            frame_timer.dispose();
            timer.cancel();
        }
    }
    public void setFlame(BlockBreak frame){
        frame_timer = frame;
    }
    public void setTimer(Timer time3){
        this.timer = time3;
    }
    public void setEndTimer(){
        this.endFlag = true;
    }
    public void clearEndTimer(){
        this.endFlag = false;
    }
}
```

```java:Ball.java
import java.awt.*;
import java.util.ArrayDeque;
import java.util.Queue;

public class Ball {
    private double x = 0;
    private double y = 0;
    private double next_x;
    private double next_y;
    private double velocity_x = 0;
    private double velocity_y = 0;
    private Color color;
    private Color color_Afterimage;
    private long before_time;
    private long now_time;
    private double radius = 10;
    private double radius_Afterimage = 3;
    Queue<Double> que_pos_x;
    Queue<Double> que_pos_y;
    public Line ball_line;
    public Ball(int x,int y,double velocity_x,double velocity_y,Color color){
        before_time =  System.currentTimeMillis();
        now_time =  System.currentTimeMillis();
        this.color = color;
        this.color_Afterimage = Color.CYAN;
        this.x = x;
        this.y = y;
        this.velocity_x = velocity_x;
        this.velocity_y = velocity_y;
        que_pos_x = new ArrayDeque<Double>();
        que_pos_y = new ArrayDeque<Double>();
        this.ball_line = new Line(x,y,x,y);
    }
    public void draw(Graphics g){
        if(que_pos_x.size()>= 1) {
            for (int i = 0; i < que_pos_x.size() ; i++) {
                double x = que_pos_x.remove();
                double y = que_pos_y.remove();

                g.setColor(color_Afterimage);
                g.fillOval((int)(x - radius_Afterimage), (int)(y - radius_Afterimage),
                        (int)(radius_Afterimage * 2), (int)(radius_Afterimage * 2));

                que_pos_x.add(x);
                que_pos_y.add(y);
            }
        }

        g.setColor(color);
        g.fillOval((int)(x - radius), (int)(y - radius), (int)(radius * 2), (int)(radius * 2));
        
    }
    public void draw_velocity(Graphics g,double height,double width){
        g.setColor(color);
        g.drawLine((int)width/2,(int)height/2,
                (int)(width/2+this.velocity_x*10),(int)(height/2+this.velocity_y*10));
        double x = width/2;
        double y = height/2;
        double radius = 3;
        g.fillOval((int)(x - radius), (int)(y - radius),
                (int)(radius * 2), (int)(radius * 2));

    }
    public void set_radius(int radius){
        this.radius = radius;
    }
    public void set_radius_Afterimage(int radius){
        this.radius_Afterimage = radius;
    }
    public void move(int width,int height){
        //次の場所を計算する
        this.now_time =  System.currentTimeMillis();
        long elapsed_time = this.now_time - this.before_time;
        this.next_x = this.x + this.velocity_x*elapsed_time;
        this.next_y = this.y + this.velocity_y*elapsed_time;
        if(this.next_x > width){
            this.next_x = width;
        }else if(this.next_x <0){
            this.next_x = 0;
        }
        if(this.next_y > height){
            this.next_y = height;
        }else if(this.next_y <0){
            this.next_y = 0;
        }
        this.before_time = this.now_time;
        this.ball_line.set(this.x,this.y,this.next_x,this.next_y);
    }
    public double[] get_position(){
        //x,y,next_x,next_yの順に返す
        return new double[]{x,y,next_x,next_y};
    }
    public double[] get_velocity(){
        return new double[]{this.velocity_x,this.velocity_y};
    }
    public String ball_position_toString(){
        String text;
        text = "(ball now "
                +String.valueOf(this.x)
                +" , "
                +String.valueOf(this.y)
                +")";
        return text;
    }
    public String ball_velocity_toString(){
        String text;
        text = "("
                +String.valueOf(this.velocity_x)
                +" , "
                +String.valueOf(this.velocity_y)
                +")";
        return text;
    }
    public String ball_nposition_toString(){
        String text;
        text = "(next ball "
                +String.valueOf(this.next_x)
                +" , "
                +String.valueOf(this.next_y)
                +")";
        return text;
    }
    public void reflect_UPDOWN(){
        this.velocity_y = -1 * this.velocity_y;
    }
    public void reflect_RIGHTLEFT(){
        this.velocity_x = -1 * this.velocity_x;
    }
    public void set_position(double next_x,double next_y){
        //nextの位置を変更する
        this.next_x = next_x;
        this.next_y = next_y;
    }
    public void set_velocity(double velocity_x,double velocity_y){
        this.velocity_x = velocity_x;
        this.velocity_y = velocity_y;
    }
    public void update(){
        que_pos_x.add(this.x);
        que_pos_y.add(this.y);
        //次の位置に更新する
        x = next_x;
        y = next_y;

        if(que_pos_x.size()>10){
            que_pos_x.remove();
            que_pos_y.remove();
        }
    }
}
```

#### Lineクラス


```java:Line.java
public class Line {
    private double[][] points = new double[2][2];
    public double x_inter;
    public double y_inter;
    public Line e_vec;
    public Line e_vertical_vec;
    public Line(double x1,double y1,double x2,double y2){
        this.points[0][0] = x1;
        this.points[1][0] = x2;
        this.points[0][1] = y1;
        this.points[1][1] = y2;
    }
    public void reflect(Ball ball){
        //事前に計算された交点ー＞反射先終点　にball_lineを更新
        //速度方向を変換
        this.e_vec();   //単位ベクトル計算
        Line v1;
        v1 = new Line(0,0,
                ball.ball_line.points[1][0] - x_inter,
                ball.ball_line.points[1][1] - y_inter);
        Line d;
        //d = -e2(e2'v1);
        this.e_vec();
        d = this.e_vertical_vec.product(-1*this.e_vertical_vec.dot(v1));
        Line v2;
        //v2 = d + e(e'v1)
        v2 = d.add_vec(this.e_vec.product(this.e_vec.dot(v1)));


        //ball オブジェクトの更新
        //ball_line,next,x,y,velocity を　変える
        ball.set_position(this.x_inter + v2.points[1][0]
                ,this.y_inter + v2.points[1][1]);
        ball.ball_line.set(this.x_inter,this.y_inter,
                this.x_inter + v2.points[1][0],this.y_inter + v2.points[1][1]);

        double[] velocity = ball.get_velocity();
        double norm_vel = Math.sqrt((velocity[0]*velocity[0] + velocity[1]*velocity[1]));
        v2.e_vec();
        ball.set_velocity(v2.e_vec.points[1][0]*norm_vel,
                v2.e_vec.points[1][1]*norm_vel);
        //System.out.println(norm_vel);
        //System.out.println("---");
        //System.out.println(ball.ball_velocity_toString());
        ///System.out.println(ball.ball_line.toString());

    }
    public void set(double x1,double y1,double x2,double y2){
        this.points[0][0] = x1;
        this.points[1][0] = x2;
        this.points[0][1] = y1;
        this.points[1][1] = y2;
    }
    public boolean exist_point(double x1,double y1){
        /*
        System.out.print("exist point ");
        System.out.print(this.points[0][0]);
        System.out.print(" ");
        System.out.print(this.points[1][0]);
        System.out.print(" ");
        System.out.println(x1);
        */
        //計算誤差で含まれない結果になることを防止するため
        //範囲を少し広げるための変数
        double error = 1e-10;

        if(this.points[0][0] < this.points[1][0] ){
            if(this.points[0][0]-error <= x1 &&
                    x1 <= this.points[1][0] +error){
                if(this.points[0][1] < this.points[1][1] ){
                    if(this.points[0][1] -error <= y1 &&
                            y1 <= this.points[1][1] +error){
                        return true;
                    }
                }else{
                    if(this.points[1][1]-error <= y1 &&
                            y1 <= this.points[0][1] +error ){
                        return true;
                    }
                }
            }
        }else{
            if(this.points[1][0]-error <= x1 &&
                    x1 <= this.points[0][0] +error){
                if(this.points[0][1] < this.points[1][1] ){
                    if(this.points[0][1] -error <= y1 &&
                            y1 <= this.points[1][1] +error){
                        return true;
                    }
                }else{
                    if(this.points[1][1] -error <= y1 &&
                            y1 <= this.points[0][1] +error){
                        return true;
                    }
                }
            }
        }
        return false;
    }
    public void e_vec(){
        double x1 = this.points[0][0];
        double y1 = this.points[0][1];
        double x2 = this.points[1][0];
        double y2 = this.points[1][1];
        double norm = Math.sqrt((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2));
        this.e_vec = new Line(0,0,(x2-x1)/norm, (y2-y1)/norm);
        this.e_vertical_vec = new Line(0,0,-1*(y2-y1)/norm,(x2-x1)/norm);
    }
    public Line add_vec(Line line){
        Line line2;
        line2 = new Line(this.points[0][0],this.points[0][1],
                this.points[1][0] + line.points[1][0],
                this.points[1][1] + line.points[1][1]);
        return line2;
    }
    public Line product(double norm){
        Line line2;
        line2 = new Line(this.points[0][0]*norm,
                this.points[0][1]*norm,
                this.points[1][0]*norm,
                this.points[1][1]*norm);
        return line2;
    }
    public double dot(Line line){
        double x1 = this.points[1][0] - this.points[0][0];
        double y1 = this.points[1][1] - this.points[0][1];
        double x2 = line.points[1][0] - line.points[0][0];
        double y2 = line.points[1][1] - line.points[0][1];
        double dot;
        dot = (x1*x2 + y1*y2);
        return dot;
    }
    public double inter_section_distance(Line ball_line){
        //交点を計算ー＞交点が両方のラインに含まれるか確認ー＞ボールの始点からの距離を返す
        double x1 = this.points[0][0];
        double y1 = this.points[0][1];
        double x2 = this.points[1][0];
        double y2 = this.points[1][1];
        double x1q = ball_line.points[0][0];
        double y1q = ball_line.points[0][1];
        double x2q = ball_line.points[1][0];
        double y2q = ball_line.points[1][1];

        double deno;
        deno = (x1q - x2q)*(y1-y2) - (y1q - y2q)*(x1-x2);
        //System.out.println(deno);

        if(deno < 0.0000001 && deno > -0.0000001){  //平行
            return 10000;
        }else{
            this.x_inter = -1 * ((x1q - x2q) * (x1 * y2 - x2 * y1) - (x1 - x2) * (x1q * y2q - x2q * y1q));
            this.x_inter = this.x_inter / deno;
            this.y_inter = (y1 - y2) * (x1q * y2q - x2q * y1q) - (y1q - y2q) * (x1 * y2 - x2 * y1);
            this.y_inter = this.y_inter / deno;
        }
        /*
        System.out.print("inter point ");
        System.out.print(this.x_inter);
        System.out.print(" ");
        System.out.println(this.y_inter);
         */

        boolean cross_flag = (this.exist_point(this.x_inter,this.y_inter)) &&
                (ball_line.exist_point(this.x_inter,this.y_inter));

        if(cross_flag){
            double distance;
            distance = Math.sqrt((x1q-this.x_inter)*(x1q-this.x_inter)
                    + (y1q-this.y_inter)*(y1q-this.y_inter) );
            return distance;
        }else{
            return 10001;
        }
    }
    public boolean same_line(Line line){
        if(line == null){
            return false;
        }else {
            if (this.points[0][0] == line.points[0][0]) {
                if (this.points[1][0] == line.points[1][0]) {
                    if (this.points[0][1] == line.points[0][1]) {
                        if (this.points[1][1] == line.points[1][1]) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    public String toString(){
        String text;
        text =  "("
                +String.valueOf(this.points[0][0])
                +" , "
                +String.valueOf(this.points[0][1])
                +") ( "
                +String.valueOf(this.points[1][0])
                +" , "
                +String.valueOf(this.points[1][1])
                +")";
        return text;
    }
}

```

#### Obstacle_polygonクラス

```java:Obstacle_polygon.java
import java.awt.*;

public class Obstacle_polygon {
    protected Line[] line;
    private Color color;
    protected int[] x_pos;  //多角形点座標 x
    protected int[] y_pos;  //多角形点座標 y

    public Obstacle_polygon(int[] x_pos, int[] y_pos, Color color){
        this.line = new Line[x_pos.length];
        this.x_pos = x_pos;
        this.y_pos = y_pos;
        for(int i=0;i<this.x_pos.length-1;i++){
            this.line[i] = new Line(x_pos[i],y_pos[i],x_pos[i+1],y_pos[i+1]);
        }
        this.line[x_pos.length-1] = new Line(x_pos[x_pos.length-1],y_pos[x_pos.length-1],
                                                    x_pos[0],y_pos[0]);
        this.color = color;
    }
    public void draw(Graphics g){
        g.setColor(color);
        Polygon polygon = new Polygon(this.x_pos,this.y_pos,this.x_pos.length);
        g.fillPolygon(this.x_pos,this.y_pos,this.x_pos.length);

    }
    public String ToString(){
        String text;
        text =  "("
                +String.valueOf(this.x_pos[0])
                +" , "
                +String.valueOf(this.y_pos[0])
                +") ( "
                +String.valueOf(this.x_pos[1])
                +" , "
                +String.valueOf(this.y_pos[1])
                +") ( "
                +String.valueOf(this.x_pos[2])
                +" , "
                +String.valueOf(this.y_pos[2])
                +") ( "
                +String.valueOf(this.x_pos[3])
                +" , "
                +String.valueOf(this.y_pos[3])
                +")";
        return text;
    }

}

```

#### Manipulate_objクラス

```java:Manipulate_obj.java
import java.awt.*;

public class Manipulate_obj extends  Obstacle_polygon{
    private double speed = 0.1;
    public boolean move_enable = false;
    private long start_time = 0;
    public Manipulate_obj(int[] x_pos, int[] y_pos, Color color){
        super(x_pos,y_pos,color);
        this.start_time = System.currentTimeMillis();
    }
    public void move(int x,int width){
        for(int i=0;i<this.x_pos.length;i++){
            if(this.x_pos[i]+x < 0){
                x = this.x_pos[i]*-1;
            } else if (this.x_pos[i] + x > width) {
                x = width - this.x_pos[i];
            }
        }
        for(int i=0;i<this.x_pos.length;i++){
            this.x_pos[i] = this.x_pos[i] + x;
        }
        for(int i=0;i<this.x_pos.length-1;i++){
            this.line[i] = new Line(x_pos[i],y_pos[i],x_pos[i+1],y_pos[i+1]);
        }
        this.line[x_pos.length-1] = new Line(x_pos[x_pos.length-1],y_pos[x_pos.length-1],
                x_pos[0],y_pos[0]);
    }
    public void set_speed(double speed){
        this.speed = speed;
    }
    public void set_start_time(long time){
        this.start_time = time;
    }
    public void set_move(){
        this.move_enable = true;
    }
    public void clear_move(){
        this.move_enable = false;
    }
    public boolean get_state(){
        if(this.move_enable == true){
            return true;
        }else{
            return false;
        }
    }
    public void set_right(){
        this.speed = Math.abs(this.speed);
    }
    public void set_left(){
        this.speed = Math.abs(this.speed)*-1;
    }
    public void move_speed(long now_time,int width){
        if(this.move_enable == true){
            double x = speed * (now_time - this.start_time);
            this.move((int)x,width);
            set_start_time(now_time);
        }
    }
}

```