をヘビペイント
MadProgrammerは画像を使用するアプローチをhis answerで示しました。それらは任意に回転させ、描き、拡大縮小することができます。実際には、画像がある場合、たとえば100x1000のサイズの場合、任意の2つのポイントにまたがることができます。したがって、画面上にポイント(200,400)と(700,1100)がある場合、画像の上の中心点が(200,400)に位置するように画像の向きとスケーリングを計算し、下の中心ポイントは(700,1100)にあります。これは、「1つのフィールドで始まり、別のフィールドで終わるはしごを描きたい」ときに現れる可能性が高い要件です。
ヘビに関して私が見た問題は、画像の「内容」が開始点と終了点に依存しなければならないということでした。つまり、が閉じるの2つのフィールド間にペイントされているヘビは、2つの遠隔フィールド間にペイントされたものとはまったく異なる形状を持つ可能性があります。
(同様に、はしご:の段数は、はしごが接続するフィールド間の距離に依存するはずです)。
ここで、私はいくつかの「レクリエーションプログラミング」を行い、スネークペインティングクラスを作成しました。イメージと比較して違いは、スネークはグラフィックオブジェクトであり、特にShape
オブジェクトで構成されていることです。トリッキーな部分はヘビの体です:いくつかの波と特定の厚さが必要で、テール部分を除いて体に沿って厚さがほぼ一定でなければなりません....
もう一度:多くの場合、の自由度があります。もちろん、これは「スネークボディを描く」というこの問題にどのように取り組むことができるかを(主に私自身のために)すぐに書き留められたスニペットです。
結果は、あなたが任意の点間の頭と尾を中心にドラッグすることができヘビです:
私は(コンパイル時)の変数のように要約されて言及した自由度のいくつかの
Snake
クラス。一つは、例えば、頭と尾点との間の距離に基づいて、「波」の数を調整できます。
しかし、これらは私が本当アーティストに任せるものですが、 - )
コードは、ビット原油であり、主にコメントアウト、多分誰かがそれにもかかわらず人見つけ:
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
}
}
:
偶然にも、関連するメソッドが呼び出されたdrawImageBetweenPoints
:だから、与えられたラダーイメージのために、あなたは基本的に画像のトップとボトムの中心点を中心にドラッグすることができます私は、手動描画はより柔軟になると考えています(とくにラダーの場合はそれほど難しくありません)。へのはしごのステップ数を動的に選択できるので、はポイントの距離に基づいて調整します。たとえば:
それはバーやステップの位置を計算し、ストロークと形状のビットを再生するための数学のビットに沸く:
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
}
}
'BufferedImage'を描画し、それを' JLabel'に描画します。 'ImageIcon'に変換するか、' paintComponet'をオーバーライドしてください。少なくともこれは私が通常やる方法です。 http://stackoverflow.com/a/2710035/4434762に例があります。 – Sarvadi
親愛なるSarvadiを助けていただきありがとうございますが、ヘビの幾何学的形状を描く方法はわかりません。ヘビにはいくつかの円弧があり、どのように描画するのか分かりません。 – Narges
シンプルな2Dゲームを作るための最良の選択肢は、JavaFXのCanvasをGraphicsContextと共に使用していると思います。 SwingのGraphics2Dよりも速くて完全です。 – Nasso