2016-04-09 11 views
1

私はJava Swingの方が新しく、私の大学コースのはしごや蛇のプロジェクトに取り組んでいます。インストラクターは、プレイヤーがゲームボード上のヘビの数と、ヘビの位置を正確に選択できるゲームを実装するように指示しました。それははしごのためです!だから私はゲーム内で1つまたは複数の固定画像を使うことができないので、プレイヤーはもうそれらを変更することはできません。スイングでヘビを描く方法は?

私のゲームでこのようなヘビやはしごを描く方法が必要です。問題は、Javaでこれを行うための最良のオプションは何ですか?つまり、ゲームボードにユーザーが望むヘビを描くことができますか?あなたができる

+0

'BufferedImage'を描画し、それを' JLabel'に描画します。 'ImageIcon'に変換するか、' paintComponet'をオーバーライドしてください。少なくともこれは私が通常やる方法です。 http://stackoverflow.com/a/2710035/4434762に例があります。 – Sarvadi

+0

親愛なるSarvadiを助けていただきありがとうございますが、ヘビの幾何学的形状を描く方法はわかりません。ヘビにはいくつかの円弧があり、どのように描画するのか分かりません。 – Narges

+0

シンプルな2Dゲームを作るための最良の選択肢は、JavaFXのCanvasをGraphicsContextと共に使用していると思います。 SwingのGraphics2Dよりも速くて完全です。 – Nasso

答えて

3

ことの一つは、与えられた角度によって、このように画像を回転させ、あなたは静止画を使用して

Rotate Image

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JSlider; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

public class Test { 

    public static void main(String[] args) { 
     new Test(); 
    } 

    public Test() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       try { 
        JFrame frame = new JFrame("Testing"); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        frame.add(new TestPane()); 
        frame.pack(); 
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true); 
       } catch (IOException exp) { 
        exp.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private BufferedImage ladder; 
     private double angle; 

     public TestPane() throws IOException { 
      ladder = ImageIO.read(getClass().getResource("Ladder.png")); 
      JSlider slider = new JSlider(0, 100, 0); 
      slider.addChangeListener(new ChangeListener() { 
       @Override 
       public void stateChanged(ChangeEvent e) { 
        angle = (360d * (slider.getValue()/100d)); 
        repaint(); 
       } 
      }); 
      setLayout(new BorderLayout()); 
      add(slider, BorderLayout.SOUTH); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(400, 400); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      applyQualityRenderingHints(g2d); 
      int x = getWidth()/2; 
      int y = getHeight()/2; 
      g2d.setColor(Color.RED); 
      g2d.rotate(Math.toRadians(angle), x, y); 
      g2d.drawImage(ladder, x - (ladder.getWidth()/2), y - ladder.getHeight(), this); 
      g2d.fillOval(x - 3, y - 3, 6, 6); 
      g2d.dispose(); 
     } 

     protected void applyQualityRenderingHints(Graphics2D g2d) { 
      g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
      g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
      g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 
     } 

    } 

} 

彼らの開始点と終了点を変更する機能を提供する可能性があります現在、実際のGraphicsのコンテキストを回転させているため、非常に複雑になることがあります。特に、場所を変更してオブジェクトの数を変更しようとすると、複雑になることがあります。

rいずれかの方法で

Rotated Image

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.geom.AffineTransform; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JSlider; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

public class Test { 

    public static void main(String[] args) { 
     new Test(); 
    } 

    public Test() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       try { 
        JFrame frame = new JFrame("Testing"); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        frame.add(new TestPane()); 
        frame.pack(); 
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true); 
       } catch (IOException exp) { 
        exp.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private BufferedImage ladder; 
     private double angle; 

     public TestPane() throws IOException { 
      ladder = ImageIO.read(getClass().getResource("Ladder.png")); 
      JSlider slider = new JSlider(0, 100, 0); 
      slider.addChangeListener(new ChangeListener() { 
       @Override 
       public void stateChanged(ChangeEvent e) { 
        angle = (360d * (slider.getValue()/100d)); 
        repaint(); 
       } 
      }); 
      setLayout(new BorderLayout()); 
      add(slider, BorderLayout.SOUTH); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(400, 400); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      applyQualityRenderingHints(g2d); 
      int x = getWidth()/2; 
      int y = getHeight()/2; 
      g2d.setColor(Color.RED); 
      BufferedImage rotated = rotate(ladder, angle); 
      g2d.drawImage(rotated, x - (rotated.getWidth()/2), y - (rotated.getHeight()/2), this); 
      g2d.dispose(); 
     } 

     public BufferedImage rotate(BufferedImage image, double byAngle) { 

      double rads = Math.toRadians(byAngle); 
      double sin = Math.abs(Math.sin(rads)), cos = Math.abs(Math.cos(rads)); 
      int w = image.getWidth(); 
      int h = image.getHeight(); 
      int newWidth = (int) Math.floor(w * cos + h * sin); 
      int newHeight = (int) Math.floor(h * cos + w * sin); 

      BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB); 
      Graphics2D g2d = rotated.createGraphics(); 
      applyQualityRenderingHints(g2d); 
      AffineTransform at = new AffineTransform(); 
      at.translate((newWidth - w)/2, (newHeight - h)/2); 

      int x = w/2; 
      int y = h/2; 

      at.rotate(Math.toRadians(byAngle), x, y); 
      g2d.setTransform(at); 
      g2d.drawImage(image, 0, 0, this); 
      g2d.dispose(); 

      return rotated; 
     } 

     protected void applyQualityRenderingHints(Graphics2D g2d) { 
      g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
      g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
      g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 
     } 

    } 

} 

...例えば、全体として画像をotate、あなたはあなたの前にいくつかの深刻な管理と数学を持っています。

あなたは詳細

ため Painting in AWT and SwingPerforming Custom Painting2D Graphicsで詳しく見ていくのが好きかもしれません

1

この質問に答えるための自由の多く(多くの、多くの)度があります。実際、「あまりにも広すぎる」と考えることができます。なぜなら、「スイングでは何かをどうやって塗りつぶすことができますか? (ここでは「何か」はヘビかラダーです)。なぜゲーム開発の重要な部分がプレーンなプログラミングだけでなく、グラフィックデザインなどである理由があります。

あなたのコースのタスクがこのポイントにどれくらい集中しているかははっきりしません。一般的なコンピュータサイエンスコースであれば、「最も美しい」のゲームに数時間を費やす必要はありません。代わりに、スネーク/はしごが接続すべきフィールドの間に平文の線を描くだけで十分です。ヘビのための緑の線、はしごのための茶色の線。しかし、多分優先順位は異なります。特にこの問題について


、広く言えば、二つのオプションがある:グラフィカルオブジェクトとして蛇ペイント画像として

  • をヘビペイント

    MadProgrammerは画像を使用するアプローチをhis answerで示しました。それらは任意に回転させ、描き、拡大縮小することができます。実際には、画像がある場合、たとえば100x1000のサイズの場合、任意の2つのポイントにまたがることができます。したがって、画面上にポイント(200,400)と(700,1100)がある場合、画像の上の中心点が(200,400)に位置するように画像の向きとスケーリングを計算し、下の中心ポイントは(700,1100)にあります。これは、「1つのフィールドで始まり、別のフィールドで終わるはしごを描きたい」ときに現れる可能性が高い要件です。

    ヘビに関して私が見た問題は、画像の「内容」が開始点と終了点に依存しなければならないということでした。つまり、が閉じるの2つのフィールド間にペイントされているヘビは、2つの遠隔フィールド間にペイントされたものとはまったく異なる形状を持つ可能性があります。

    (同様に、はしご:の段数は、はしごが接続するフィールド間の距離に依存するはずです)。


    ここで、私はいくつかの「レクリエーションプログラミング」を行い、スネークペインティングクラスを作成しました。イメージと比較して違いは、スネークはグラフィックオブジェクトであり、特にShapeオブジェクトで構成されていることです。トリッキーな部分はヘビの体です:いくつかの波と特定の厚さが必要で、テール部分を除いて体に沿って厚さがほぼ一定でなければなりません....

    もう一度:多くの場合、の自由度があります。もちろん、これは「スネークボディを描く」というこの問題にどのように取り組むことができるかを(主に私自身のために)すぐに書き留められたスニペットです。

    結果は、あなたが任意の点間の頭と尾を中心にドラッグすることができヘビです:SmallSnake

    私は(コンパイル時)の変数のように要約されて言及した自由度のいくつかの

    Snakeクラス。一つは、例えば、頭と尾点との間の距離に基づいて、「波」の数を調整できます。

    LongSnake

    しかし、これらは私が本当アーティストに任せるものですが、 - )

    コードは、ビット原油であり、主にコメントアウト、多分誰かがそれにもかかわらず人見つけ:

    import java.awt.Color; 
    import java.awt.Graphics; 
    import java.awt.Graphics2D; 
    import java.awt.RenderingHints; 
    import java.awt.Shape; 
    import java.awt.event.MouseEvent; 
    import java.awt.event.MouseListener; 
    import java.awt.event.MouseMotionListener; 
    import java.awt.geom.AffineTransform; 
    import java.awt.geom.Ellipse2D; 
    import java.awt.geom.Path2D; 
    import java.awt.geom.Point2D; 
    
    import javax.swing.JFrame; 
    import javax.swing.JPanel; 
    import javax.swing.SwingUtilities; 
    
    public class SnakeDrawing 
    { 
        public static void main(String[] args) 
        { 
         SwingUtilities.invokeLater(() -> createAndShowGUI()); 
        } 
    
        private static void createAndShowGUI() 
        { 
         JFrame f = new JFrame(); 
         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    
         f.getContentPane().add(new SnakeDrawingPanel()); 
    
         f.setSize(800, 800); 
         f.setLocationRelativeTo(null); 
         f.setVisible(true); 
        } 
    } 
    
    class Snake 
    { 
        private Point2D point0 = new Point2D.Double(100,500); 
        private Point2D point1 = new Point2D.Double(700,500); 
    
        double bodyWidth = 10; 
        int waves = 4; 
        double waveHeight = 0.05; 
        double tailStart = 0.8; 
        double headLength = 20; 
        double headWidth = 16; 
        double eyeRadius = 6; 
        double irisRadius = 3; 
    
        private Shape body; 
        private Shape head; 
        private Shape eyeR; 
        private Shape eyeL; 
        private Shape irisR; 
        private Shape irisL; 
    
        void setPoints(Point2D point0, Point2D point1) 
        { 
         this.point0.setLocation(point0); 
         this.point1.setLocation(point1); 
    
         AffineTransform at = AffineTransform.getRotateInstance(
          currentAngleRad(), point0.getX(), point0.getY()); 
         at.translate(point0.getX(), point0.getY()); 
    
         createBody(at); 
         createHead(at); 
        } 
    
        void draw(Graphics2D g) 
        { 
         g.setColor(new Color(0,128,0)); 
         g.fill(body); 
         g.fill(head); 
         g.setColor(Color.WHITE); 
         g.fill(eyeR); 
         g.fill(eyeL); 
         g.setColor(Color.BLACK); 
         g.fill(irisR); 
         g.fill(irisL); 
        } 
    
        private void createBody(AffineTransform at) 
        { 
         double distance = point1.distance(point0); 
         int steps = 100; 
         Path2D body = new Path2D.Double(); 
         Point2D previousPoint = null; 
         for (int i=0; i<steps; i++) 
         { 
          double alpha = (double)i/(steps-1); 
          Point2D point = computeCenterPoint(alpha, distance); 
          if (previousPoint != null) 
          { 
           Point2D bodyPoint = 
            computeBodyPoint(alpha, point, previousPoint); 
           if (i==1) 
           { 
            body.moveTo(bodyPoint.getX(), bodyPoint.getY()); 
           } 
           else 
           { 
            body.lineTo(bodyPoint.getX(), bodyPoint.getY()); 
           } 
          } 
          previousPoint = point; 
         } 
         previousPoint = null; 
         for (int i=steps-1; i>=0; i--) 
         { 
          double alpha = (double)i/(steps-1); 
          Point2D point = computeCenterPoint(alpha, distance); 
          if (previousPoint != null) 
          { 
           Point2D bodyPoint = 
            computeBodyPoint(alpha, point, previousPoint); 
           body.lineTo(bodyPoint.getX(), bodyPoint.getY()); 
          } 
          previousPoint = point; 
         } 
         this.body = at.createTransformedShape(body); 
        } 
    
        private Point2D computeBodyPoint(
         double alpha, Point2D point, Point2D previousPoint) 
        { 
         double dx = point.getX() - previousPoint.getX(); 
         double dy = point.getY() - previousPoint.getY(); 
         double rdx = -dy; 
         double rdy = dx; 
         double d = Math.hypot(dx, dy); 
         double localBodyWidth = bodyWidth; 
         if (alpha > tailStart) 
         { 
          localBodyWidth *= (1 - (alpha - tailStart)/(1.0 - tailStart)); 
         } 
         double px = point.getX() + rdx * (1.0/d) * localBodyWidth; 
         double py = point.getY() + rdy * (1.0/d) * localBodyWidth; 
         return new Point2D.Double(px, py); 
        } 
    
        private Point2D computeCenterPoint(
         double alpha, double distance) 
        { 
         double r = alpha * Math.PI * 2 * waves; 
         double verticalScaling = 1 - (alpha * 2 - 1) * (alpha * 2 - 1); 
         double y = Math.sin(r) * distance * waveHeight * verticalScaling; 
         double x = alpha * distance; 
         return new Point2D.Double(x,y); 
        } 
    
        private void createHead(AffineTransform at) 
        { 
         Shape head = new Ellipse2D.Double(
          -headLength, -headWidth, 
          headLength + headLength, 
          headWidth + headWidth); 
         this.head = at.createTransformedShape(head); 
    
         Shape eyeR = new Ellipse2D.Double(
          -headLength * 0.5 - eyeRadius, 
          -headWidth * 0.6 - eyeRadius, 
          eyeRadius + eyeRadius, 
          eyeRadius + eyeRadius); 
         Shape eyeL = new Ellipse2D.Double(
          -headLength * 0.5 - eyeRadius, 
          headWidth * 0.6 - eyeRadius, 
          eyeRadius + eyeRadius, 
          eyeRadius + eyeRadius); 
         this.eyeR = at.createTransformedShape(eyeR); 
         this.eyeL = at.createTransformedShape(eyeL); 
    
         Shape irisR = new Ellipse2D.Double(
          -headLength * 0.4 - eyeRadius, 
          -headWidth * 0.6 - irisRadius, 
          irisRadius + irisRadius, 
          irisRadius + irisRadius); 
         Shape irisL = new Ellipse2D.Double(
          -headLength * 0.4 - eyeRadius, 
          headWidth * 0.6 - irisRadius, 
          irisRadius + irisRadius, 
          irisRadius + irisRadius); 
         this.irisR = at.createTransformedShape(irisR); 
         this.irisL = at.createTransformedShape(irisL); 
        } 
    
        private double currentAngleRad() 
        { 
         double dx = point1.getX() - point0.getX(); 
         double dy = point1.getY() - point0.getY(); 
         double angleRad = Math.atan2(dy, dx); 
         return angleRad; 
        } 
    } 
    
    class SnakeDrawingPanel extends JPanel 
        implements MouseListener, MouseMotionListener 
    { 
        private Point2D point0 = new Point2D.Double(100,500); 
        private Point2D point1 = new Point2D.Double(700,500); 
        private Point2D draggedPoint = null; 
        private Snake snake = new Snake(); 
    
        SnakeDrawingPanel() 
        { 
         addMouseListener(this); 
         addMouseMotionListener(this); 
        } 
    
        @Override 
        protected void paintComponent(Graphics gr) 
        { 
         super.paintComponent(gr); 
         Graphics2D g = (Graphics2D)gr; 
         g.setRenderingHint(
          RenderingHints.KEY_ANTIALIASING, 
          RenderingHints.VALUE_ANTIALIAS_ON); 
    
         g.setColor(Color.WHITE); 
         g.fillRect(0, 0, getWidth(), getHeight()); 
    
         snake.setPoints(point0, point1); 
         snake.draw(g); 
        } 
    
    
        @Override 
        public void mouseDragged(MouseEvent e) 
        { 
         if (draggedPoint != null) 
         { 
          draggedPoint.setLocation(e.getPoint()); 
          repaint(); 
         } 
        } 
    
        @Override 
        public void mouseMoved(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mouseClicked(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mousePressed(MouseEvent e) 
        { 
         draggedPoint = null; 
         double thresholdSquared = 10*10; 
    
         if (e.getPoint().distanceSq(point0) < thresholdSquared) 
         { 
          draggedPoint = point0; 
         } 
         if (e.getPoint().distanceSq(point1) < thresholdSquared) 
         { 
          draggedPoint = point1; 
         } 
        } 
    
        @Override 
        public void mouseReleased(MouseEvent e) 
        { 
         draggedPoint = null; 
        } 
    
        @Override 
        public void mouseEntered(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mouseExited(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
    } 
    

    EDIT:MadProgrammerによって解答の一例/拡張として

    、ここにあなたが与えられた二つの点の間の画像を描画することを可能にする方法が含まれているプログラムです。再び

    import java.awt.Color; 
    import java.awt.Graphics; 
    import java.awt.Graphics2D; 
    import java.awt.RenderingHints; 
    import java.awt.event.MouseEvent; 
    import java.awt.event.MouseListener; 
    import java.awt.event.MouseMotionListener; 
    import java.awt.geom.AffineTransform; 
    import java.awt.geom.Ellipse2D; 
    import java.awt.geom.Point2D; 
    import java.awt.image.BufferedImage; 
    import java.io.File; 
    import java.io.IOException; 
    
    import javax.imageio.ImageIO; 
    import javax.swing.JFrame; 
    import javax.swing.JPanel; 
    import javax.swing.SwingUtilities; 
    
    public class LadderDrawing 
    { 
        public static void main(String[] args) 
        { 
         SwingUtilities.invokeLater(() -> createAndShowGUI()); 
        } 
    
        private static void createAndShowGUI() 
        { 
         JFrame f = new JFrame(); 
         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    
         f.getContentPane().add(new LadderDrawingPanel()); 
    
         f.setSize(800, 800); 
         f.setLocationRelativeTo(null); 
         f.setVisible(true); 
        } 
    } 
    
    
    class LadderDrawingPanel extends JPanel 
        implements MouseListener, MouseMotionListener 
    { 
        private Point2D point0 = new Point2D.Double(300,300); 
        private Point2D point1 = new Point2D.Double(500,700); 
        private Point2D draggedPoint = null; 
    
        private BufferedImage ladderImage; 
    
        LadderDrawingPanel() 
        { 
         addMouseListener(this); 
         addMouseMotionListener(this); 
    
         try 
         { 
          ladderImage = ImageIO.read(new File("ladder.png")); 
         } 
         catch (IOException e) 
         { 
          e.printStackTrace(); 
         } 
        } 
    
        @Override 
        protected void paintComponent(Graphics gr) 
        { 
         super.paintComponent(gr); 
         Graphics2D g = (Graphics2D)gr; 
         g.setRenderingHint(
          RenderingHints.KEY_ANTIALIASING, 
          RenderingHints.VALUE_ANTIALIAS_ON); 
    
         g.setColor(Color.WHITE); 
         g.fillRect(0, 0, getWidth(), getHeight()); 
    
         g.setColor(Color.RED); 
         paintDot(g, point0, 8); 
         paintDot(g, point1, 8); 
    
         drawImageBetweenPoints(g, ladderImage, point0, point1); 
        } 
    
        private static void paintDot(Graphics2D g, Point2D p, double radius) 
        { 
         g.fill(new Ellipse2D.Double(
          p.getX() - radius, p.getY() - radius, 
          radius + radius, radius + radius)); 
        } 
    
        private static void drawImageBetweenPoints(
         Graphics2D g, BufferedImage image, Point2D p0, Point2D p1) 
        { 
         AffineTransform at = new AffineTransform(); 
         at.concatenate(AffineTransform.getTranslateInstance(
          p0.getX(), p0.getY())); 
    
         double dx = p1.getX() - p0.getX(); 
         double dy = p1.getY() - p0.getY(); 
         double angleRad = Math.atan2(dy, dx) - Math.PI * 0.5; 
         at.concatenate(AffineTransform.getRotateInstance(angleRad)); 
    
         double distance = p1.distance(p0); 
         double scalingY = distance/image.getHeight(); 
    
         // Default: Uniform scaling 
         double scalingX = scalingY; 
    
         // For keeping the width of the image 
         //scalingX = 1.0; 
    
         // For scaling to a fixed width: 
         //double desiredWidth = 50; 
         //scalingX = desiredWidth/image.getWidth(); 
    
         at.concatenate(AffineTransform.getScaleInstance(scalingX, scalingY)); 
    
         at.concatenate(AffineTransform.getTranslateInstance(
          -image.getWidth() * 0.5, 0)); 
    
         AffineTransform oldAT = g.getTransform(); 
         g.transform(at); 
         g.drawImage(image, 0, 0, null); 
         g.setTransform(oldAT); 
        } 
    
    
        @Override 
        public void mouseDragged(MouseEvent e) 
        { 
         if (draggedPoint != null) 
         { 
          draggedPoint.setLocation(e.getPoint()); 
          repaint(); 
         } 
        } 
    
        @Override 
        public void mouseMoved(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mouseClicked(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mousePressed(MouseEvent e) 
        { 
         draggedPoint = null; 
         double thresholdSquared = 10*10; 
    
         if (e.getPoint().distanceSq(point0) < thresholdSquared) 
         { 
          draggedPoint = point0; 
         } 
         if (e.getPoint().distanceSq(point1) < thresholdSquared) 
         { 
          draggedPoint = point1; 
         } 
        } 
    
        @Override 
        public void mouseReleased(MouseEvent e) 
        { 
         draggedPoint = null; 
        } 
    
        @Override 
        public void mouseEntered(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mouseExited(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
    } 
    

    LadderImage

    偶然にも、関連するメソッドが呼び出されたdrawImageBetweenPoints:だから、与えられたラダーイメージのために、あなたは基本的に画像のトップとボトムの中心点を中心にドラッグすることができます私は、手動描画はより柔軟になると考えています(とくにラダーの場合はそれほど難しくありません)。へのはしごのステップ数を動的に選択できるので、はポイントの距離に基づいて調整します。たとえば:

    LadderManual01

    LadderManual02

    それはバーやステップの位置を計算し、ストロークと形状のビットを再生するための数学のビットに沸く:

    import java.awt.BasicStroke; 
    import java.awt.Color; 
    import java.awt.Graphics; 
    import java.awt.Graphics2D; 
    import java.awt.RenderingHints; 
    import java.awt.Shape; 
    import java.awt.Stroke; 
    import java.awt.event.MouseEvent; 
    import java.awt.event.MouseListener; 
    import java.awt.event.MouseMotionListener; 
    import java.awt.geom.Ellipse2D; 
    import java.awt.geom.Line2D; 
    import java.awt.geom.Point2D; 
    
    import javax.swing.JFrame; 
    import javax.swing.JPanel; 
    import javax.swing.SwingUtilities; 
    
    public class LadderDrawingManual 
    { 
        public static void main(String[] args) 
        { 
         SwingUtilities.invokeLater(() -> createAndShowGUI()); 
        } 
    
        private static void createAndShowGUI() 
        { 
         JFrame f = new JFrame(); 
         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    
         f.getContentPane().add(new LadderDrawingManualPanel()); 
    
         f.setSize(800, 800); 
         f.setLocationRelativeTo(null); 
         f.setVisible(true); 
        } 
    } 
    
    
    class LadderDrawingManualPanel extends JPanel 
        implements MouseListener, MouseMotionListener 
    { 
        private Point2D point0 = new Point2D.Double(300,300); 
        private Point2D point1 = new Point2D.Double(500,700); 
        private Point2D draggedPoint = null; 
    
        LadderDrawingManualPanel() 
        { 
         addMouseListener(this); 
         addMouseMotionListener(this); 
        } 
    
        @Override 
        protected void paintComponent(Graphics gr) 
        { 
         super.paintComponent(gr); 
         Graphics2D g = (Graphics2D)gr; 
         g.setRenderingHint(
          RenderingHints.KEY_ANTIALIASING, 
          RenderingHints.VALUE_ANTIALIAS_ON); 
    
         g.setColor(Color.WHITE); 
         g.fillRect(0, 0, getWidth(), getHeight()); 
    
         g.setColor(Color.RED); 
         paintDot(g, point0, 8); 
         paintDot(g, point1, 8); 
    
         drawLadderBetweenPoints(g, point0, point1); 
        } 
    
        private static void paintDot(Graphics2D g, Point2D p, double radius) 
        { 
         g.fill(new Ellipse2D.Double(
          p.getX() - radius, p.getY() - radius, 
          radius + radius, radius + radius)); 
        } 
    
        private static void drawLadderBetweenPoints(
         Graphics2D g, Point2D p0, Point2D p1) 
        { 
         final double ladderWidth = 40; 
         final double distanceBetweenSteps = 30; 
         final double barWidth = 5; 
    
         double dx = p1.getX() - p0.getX(); 
         double dy = p1.getY() - p0.getY(); 
         double distance = p1.distance(p0); 
    
         double dirX = dx/distance; 
         double dirY = dy/distance; 
    
         double offsetX = dirY * ladderWidth * 0.5; 
         double offsetY = -dirX * ladderWidth * 0.5; 
    
         Line2D lineR = new Line2D.Double(
          p0.getX() + offsetX, 
          p0.getY() + offsetY, 
          p1.getX() + offsetX, 
          p1.getY() + offsetY); 
    
         Line2D lineL = new Line2D.Double(
          p0.getX() - offsetX, 
          p0.getY() - offsetY, 
          p1.getX() - offsetX, 
          p1.getY() - offsetY); 
    
         drawBar(g, lineL, barWidth); 
         drawBar(g, lineR, barWidth); 
    
         int numSteps = (int)(distance/distanceBetweenSteps); 
         for (int i=0; i<numSteps; i++) 
         { 
          double stepOffsetX = (i+1) * distanceBetweenSteps; 
          double stepOffsetY = (i+1) * distanceBetweenSteps; 
    
          Line2D step = new Line2D.Double(
           p0.getX() + stepOffsetX * dirX - offsetX, 
           p0.getY() + stepOffsetY * dirY - offsetY, 
           p0.getX() + stepOffsetX * dirX + offsetX, 
           p0.getY() + stepOffsetY * dirY + offsetY); 
          drawBar(g, step, barWidth); 
         } 
        } 
    
        private static void drawBar(Graphics2D g, Line2D line, double barWidth) 
        { 
         Stroke stroke = new BasicStroke(
          (float)barWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); 
         Shape bar = stroke.createStrokedShape(line); 
         g.setColor(new Color(200,100,0)); 
         g.fill(bar); 
         g.setColor(Color.BLACK); 
         g.draw(bar); 
        } 
    
    
        @Override 
        public void mouseDragged(MouseEvent e) 
        { 
         if (draggedPoint != null) 
         { 
          draggedPoint.setLocation(e.getPoint()); 
          repaint(); 
         } 
        } 
    
        @Override 
        public void mouseMoved(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mouseClicked(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mousePressed(MouseEvent e) 
        { 
         draggedPoint = null; 
         double thresholdSquared = 10*10; 
    
         if (e.getPoint().distanceSq(point0) < thresholdSquared) 
         { 
          draggedPoint = point0; 
         } 
         if (e.getPoint().distanceSq(point1) < thresholdSquared) 
         { 
          draggedPoint = point1; 
         } 
        } 
    
        @Override 
        public void mouseReleased(MouseEvent e) 
        { 
         draggedPoint = null; 
        } 
    
        @Override 
        public void mouseEntered(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
        @Override 
        public void mouseExited(MouseEvent e) 
        { 
         // Nothing to do here 
        } 
    
    }