So I'm writing a code that allows a user to throw an imaginary object at an initial angle and speed to see if they can come close to hitting a ball (that is positioned based on user input).
However, I'm having trouble drawing the curve of the users inputted angle and speed of the imaginary object.
I've used a mathematical formula to calculate the total time and range of said object. That is:
πππππ= π£02sinβ‘(2ππ/180)π
π‘ππ‘ππ π‘πππ= 2π£0sinβ‘(ππ/180)π
I've already tried attempting to put range and total time into an arc and plotting it that way. But that didn't seem to work.
Here's the code:
import java.awt.AWTEvent;
import java.awt.*;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.util.Scanner;
import java.awt.geom.QuadCurve2D;
public class BallGame extends JFrame {
public static void main (String[]args)
{
Scanner cool= new Scanner(System.in);
double angle, speed, range, totalTime;
{
JFrame frame = new JFrame (" Throwing Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,700);
}
{
System.out.println("Please enter the location of the ball (0 < X < 1)");
StdDraw.setPenRadius(0.06);
StdDraw.setPenColor(StdDraw.BLUE);
double x, y;
y = 0;
x = cool.nextDouble();
StdDraw.point(x, y);
}
System.out.println("Please enter an angle of your choosing:");
angle = cool.nextDouble();
System.out.println("Please enter the speed at wish you which to throw the ball");
speed = cool.nextDouble();
double g;
g = 9.8;
range = Math.pow(speed, 2) * Math.sin(2 * angle * (Math.PI / 180) / g);
totalTime = (2 * speed * Math.sin(angle * Math.PI / 180)) / g;
For drawing a curve you need to calculate horizontal (x) and vertical (y) position, as a function of time, start point, start speed and angle.
In other words, calculate the horizontal distance, and vertical distance.
The equations are well known and widely available.
You use these equations to repeatedly calculate x,y and then repaint.
See the following demonstration. Not the comments :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BalisticCurve extends JFrame {
private static final double G = 9.8; //positive because Y axis is positive going down
private int animationSpeed = 5; //millis. The smaller the faster
private static int size = 900, ballDiameter = 10;
private double startX, startY, ballX, ballY;
private double xSpeed, ySpeed, lastPointX, lastPointY;
private double time, deltaTime = 0.01 ; //in seconds
private List<Point2D> curvePoints= new ArrayList<>();
private Timer timer;
BalisticCurve(){
super("Balistic Curve");
DrawBoard board = new DrawBoard();
add(board, BorderLayout.CENTER);
ballX= lastPointX = startX = 50;
ballY = lastPointY = startY = size - 100;
getUserInput();
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
timer = new Timer(animationSpeed, new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
board.moveBall();
board.repaint();
if(! inBounds()) {
timer.stop();
}
}
});
timer.start();
}
private void getUserInput() {
double angle = 45;//todo replace with user input + verification
double speed = 100;
xSpeed = speed * Math.cos(angle * (Math.PI / 180));
ySpeed = speed * Math.sin(angle * (Math.PI / 180));
}
private boolean inBounds() {
//ignore if ball exceeds height
if((ballX < 0) || (ballX > (getWidth()))
|| ( ballY > (getHeight() - ballDiameter) ) ) {
return false;
}
return true;
}
class DrawBoard extends JPanel {
public DrawBoard() {
setPreferredSize(new Dimension(size, size));
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.RED);
g2d.fillOval((int)ballX,(int)ballY,ballDiameter,ballDiameter);
if((Math.abs(lastPointX - ballX)>=1) && (Math.abs(lastPointY - ballY)>=1) ) {
curvePoints.add(new Point2D.Double(ballX, ballY));
lastPointX = ballX; lastPointY = ballY;
}
drawCurve(g2d);
}
private void drawCurve(Graphics2D g2d) {
g2d.setColor(Color.BLUE);
for(int i=0; i < (curvePoints.size()-1); i++) {
Point2D from = curvePoints.get(i);
Point2D to = curvePoints.get(i+1);
g2d.drawLine((int)from.getX(),(int)from.getY(), (int)to.getX(), (int)to.getY());
}
}
private void moveBall() {
ballX = startX + (xSpeed * time);
ballY = startY - ((ySpeed *time)-(0.5 *G * Math.pow(time, 2))) ;
time += deltaTime;
}
}
public static void main(String[] args) {
new BalisticCurve();
}
}
Don't hesitate to ask what is not clear enough.
Related
Given a list of n circles, each of diameter d, I want to generate an n-gon (polygon of n lengths), with side lengths d, and draw a circle on each of its edges.
I encountered this problem while developing an application.
The formula for the radius of the polygon with N sides, given a length a for each side, is
My code
Game Frame
import javax.swing.JFrame;
public class gameFrame extends JFrame{
static int width = 400;
static int height = 400;
public static void main(String[] args) {
gameFrame frame = new gameFrame();
gamePanel panel = new gamePanel();
frame.add(panel);
frame.setTitle("Tutorial");
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(true);
panel.initializeList();
panel.fpsTimer.start();
}
}
Game Panel
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Arc2D;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
public class gamePanel extends JPanel{
static ArrayList<Point2D> coordinates = new ArrayList<Point2D>();
static int d = 20;
Timer fpsTimer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//paint the circles with the coordinates in list 'coordinates'
for(Point2D point : coordinates) {
g2d.setColor(Color.BLACK);
Shape circle = new Arc2D.Double(point.x,
point.y,
d,
d,
0 , 360, Arc2D.CHORD);
g2d.fill(circle);
}
}
public void initializeList() {
Point2D center = new Point2D(0,0);
int n = 15; // number of sides of polygon
float alpha = 360/ n; // angle of each triangle in the polygon
float angle = 0; // incremental angle for the loop
float side = d; // desired length of each side
float radius = (float) (side / (2*Math.sin(Math.PI / n))); // R = a / (2*(sin(PI/n))) formula
//verifying that the circle radius isn't larger than the frame
if(!(radius >= gameFrame.width || radius >= gameFrame.height)) {
//center of the circle
center.x = (gameFrame.width)/2;
center.y = (gameFrame.height)/2;
for(int i = 0 ; i < n ; i++) {
coordinates.add(new Point2D((center.x + Math.sin(angle)*radius),
(center.y -Math.cos(angle)*radius)));
angle += alpha;
}
}
}
}
Point2D (for simplicity)
public class Point2D {
double x;
double y;
public Point2D(double x , double y) {
this.x = x;
this.y = y;
}
}
The outputs and reflection
For n=15 and d=20 as shown above, the output is
Some circles overlap.
Surprisingly, if I modify angle += alpha to angle += alpha+0.295; in GamePanel initializeList(), I get the desired result :
For n=14 the output is even scarier :
I have spent a ridiculous amount of time on this bug. Does anyone have any idea what is going wrong?
Java Math uses angles in radians. So calculate alpha in radians like this:
double alpha = Math.toRadians(360.0/ n);
Just update the line and it should fix the issue.
Also, for more accuracy use double type instead of float for each variable.
Below is my current algorithm to align the rectangle (representing symbol) in the center of the canvas space (representing icon). It is only the algorithm I am interested in so ignore the rest of the code as it is merely for demonstration purposes as a visual aid.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class IconSymbol extends JFrame {
public IconSymbol(double iWH, double s, double w, double h) {
getContentPane().add(new Canvas((int)iWH, s, w, h));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize((int)iWH, (int)iWH);
setVisible(true);
}
public static void main(String arg[]) {
IconSymbol is = new IconSymbol(100, 0.9, 50, 50);
}
class Canvas extends JPanel {
// STIPULATED
double iconWH = 0;
double sScale = 0;
double sWidth = 0;
double sHeight = 0;
// CALCULATED
double padX = 0;
double padY = 0;
double xOffSet = 0;
double yOffSet = 0;
public Canvas(double iWH,double sS,double sW,double sH) {
this.iconWH = iWH;
this.sScale = sS;
this.sWidth = sW;
this.sHeight = sH;
}
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.setBackground(Color.WHITE);
g2D.setPaint(Color.BLUE);
Shape icon = new Rectangle.Double(0,0,(int)iconWH,(int)iconWH);
g2D.fill(icon);
g2D.setPaint(Color.BLACK);
int width = (int)iconWH / 10;
int height= (int)iconWH / 10;
for(int row=0;row<10;row++){
for(int col=0;col<10;col++){
g.drawRect(row*width,col*height,width,height);
}
}
Point off = algorithm();
g2D.setPaint(Color.RED);
Shape s = new Rectangle.Double(off.x,off.y,(int)sWidth,(int)sHeight);
AffineTransform tran = AffineTransform.getScaleInstance(sScale, sScale);
g2D.fill(tran.createTransformedShape(s));
}
public Point algorithm(){
// ALGORITHM WITH EXACT NEEDED PARAMETERS
padX = (sWidth - ((sWidth * sScale))) / 2;
padY = (sHeight - ((sHeight * sScale))) / 2;
xOffSet = padX + ((iconWH - (sWidth * sScale)) / 2);
yOffSet = padX + ((iconWH - (sHeight * sScale)) / 2);
Point point = new Point((int)xOffSet, (int)yOffSet);
return point;
}
}
}
The problem with your code is that the scale transform tran is scaling the calculated origin of the rectangle, off, as well as sWidth and sHeight. If you want to keep with your current scheme you need to apply the inverse of the scale transform to the calculated offset in your algorithm method:
public Point algorithm(){
// ALGORITHM WITH EXACT NEEDED PARAMETERS
xOffSet = ((iconWH - (sWidth * sScale)) / 2) / sScale;
yOffSet = ((iconWH - (sHeight * sScale)) / 2) / sScale;
Point point = new Point((int)xOffSet, (int)yOffSet);
return point;
}
Note that I removed padX and padY as they weren't required for calculating the offset.
I drew a line that is at an angle based on a slider.
I am trying to make the line's end Y coordinate a certain number (let's say 300), even if it is at an angle.
Any ideas on how to do this? Here is the work on my line so far:
double angle = intAngle;
angle = angle * Math.PI / 180;
double length = 300;
graphics.setColor(Color.RED);
double startX = 300;
double startY = 100;
double endX = startX + length * Math.cos(angle);
double endY = startY + length * Math.sin(angle);
double end2X;
double end2Y;
double dblAngle;
double angle2;
int intAngle2;
double start2X = endX;
double start2Y = endY;
intAngle2 = 180 - intAngle;
angle2 = intAngle2;
angle2 = (angle2 * Math.PI / 180);
end2X = (start2X - length * Math.cos(angle2));
end2Y = (start2Y - length * Math.sin(angle2));
int intEndX = (int)endX;
int intEndY = (int)endY;
if(blnButton == true){
graphics.draw(new Line2D.Double(startX, startY, endX, endY));
graphics.draw(new Line2D.Double(start2X, start2Y, end2X, end2Y));
}
There's probably a simpler way, but basically, you can calculate two points on a circle based on the angle and the inverse of the angle (angle - 360)
With a circle with a radius of 150, this will give you a line of 300, for example
The red line is the line from the center of the circle to point on the circle represented by the given angel. The blue is the inverse. Each line is 150 pixels line, meaning together, they are 300 pixels in length.
This examples draws the separately, but realistically, they could be draw as a single line
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.geom.Ellipse2D;
import java.awt.geom.Line2D;
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();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
DrawPane drawPane = new DrawPane();
add(drawPane);
JSlider slider = new JSlider(0, 100);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
drawPane.setAngleInDegrees(360d * (slider.getValue() / 100d));
}
});
slider.setValue(0);
}
}
public class DrawPane extends JPanel {
private double angle;
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Radius of the circle
double r = 150;
// Degrees to radians...
double radians = Math.toRadians(angle);
// The end point on the circle...
int endX = (int) Math.round(r * Math.cos(radians));
int endY = (int) Math.round(r * Math.sin(radians));
// The start point on the circle, 360 degress from the
// start angle
radians = Math.toRadians(angle - 360);
int startX = (int) Math.round(r * Math.cos(radians));
int startY = (int) Math.round(r * Math.sin(radians));
// Offset for the ellipse (center of the screen)
double x = (getWidth() / 2d) - r;
double y = (getWidth() / 2d) - r;
g2d.setColor(Color.LIGHT_GRAY);
g2d.draw(new Ellipse2D.Double(x, y, r * 2, r * 2));
// Center of the circle...
x = (getWidth() / 2d);
y = (getWidth() / 2d);
// One single line
//g2d.setColor(Color.BLACK);
//g2d.draw(new Line2D.Double(x - startX, y - startY, x + endX, y + endY));
g2d.setColor(Color.RED);
g2d.draw(new Line2D.Double(x, y, x - startX, y - startY));
g2d.setColor(Color.BLUE);
g2d.draw(new Line2D.Double(x, y, x + endX, y + endY));
g2d.dispose();
}
public void setAngleInDegrees(double value) {
if (angle != value) {
angle = Math.min(Math.max(value, 0), 360);
repaint();
}
}
}
}
or something along those lines...
I am a beginner at Java, only been coding for a year. My task is to create distortions to any image given. I have been having a lot of trouble with the bulge effect lately. I have been researching all around google and I found these links very helpful:
https://math.stackexchange.com/questions/266250/explanation-of-this-image-warping-bulge-filter-algorithm
Image Warping - Bulge Effect Algorithm
I tried the algorithm that these two links gave me, but I ended up with nothing.
Let's say I have imported an image that is 100 pixels by 100 pixels, from the code below, am I using the algorithm correctly:
//modifiedImage is a global variable and contains the image that is 100x100
public BufferedImage buldge(){
double X = 0;
double Y = 0;
BufferedImage anImage = new BufferedImage (1000, 1000, BufferedImage.TYPE_INT_ARGB);
for(int x = 0; x < modifiedImage.getWidth(); x++){
for(int y = 0; y < modifiedImage.getHeight(); y++){
int rgb = modifiedImage.getRGB(x, y);
double newRadius = 0;
X = x - x/2;
Y = y - y/2;
double radius = Math.sqrt(X*X + Y*Y);
double angle = Math.atan2(X, Y);
newRadius = Math.pow(radius,1.5);
X = (int)(newRadius*Math.sin(angle));
Y = (int)(newRadius*Math.cos(angle));
anImage.setRGB((int)X, (int)Y,rgb);
}
}
return anImage;
}
The problem is that this code doesn't really bulge the image in the middle. I have made a new BufferedImage of dimensions 1000x1000 because the pixels from the original one gets extended really far and some are extended beyond 1000x1000. If anyone would help me show the problems in this code concerning the bulge effect, I would greatly appreciate it.
I think one (main) part of the problem is that you are computing the radius of the bulge effect in pixels. Although I have not read all anwers in the threads that you linked, it seems like they are referring to texture coordinates - that is, to values between 0 and 1.
Apart from that: With the current approach, you will have a sampling problem. Imagine that one pixel at the center of the input image will be "stretched" so that it covers an area of, say, 10x10 pixels in the output image. But still, you are only computing one new position for this pixel.
Imagine it like you are taking pixels from the input image, and move them to a new position in the output image - but you have to do it the other way around: You have to check each pixel in the output image, and compute which pixel of the input image was moved there.
I created a small example: It allows moving a "magnifying glass" over the image with the mouse. With the mouse wheel, you can change the strength of the distortion. With SHIFT+MouseWheel, you can change the size of the magnifying glass.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.beans.Transient;
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 ImageBulgeTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(1, 1));
frame.getContentPane().add(new ImageBulgePanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class ImageBulgePanel extends JPanel
{
private BufferedImage input;
private BufferedImage output;
private double bulgeStrength = 0.3;
private double bulgeRadius = 100;
ImageBulgePanel()
{
try
{
input = ImageIO.read(new File("lena512color.png"));
}
catch (IOException e1)
{
e1.printStackTrace();
}
addMouseMotionListener(new MouseAdapter()
{
#Override
public void mouseMoved(MouseEvent e)
{
updateImage(e.getX(), e.getY());
}
});
addMouseWheelListener(new MouseWheelListener()
{
#Override
public void mouseWheelMoved(MouseWheelEvent e)
{
if ((e.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) ==
InputEvent.SHIFT_DOWN_MASK)
{
bulgeRadius += 10 * e.getWheelRotation();
System.out.println("bulgeRadius "+bulgeRadius);
}
else
{
bulgeStrength += 0.1 * e.getWheelRotation();
bulgeStrength = Math.max(0, bulgeStrength);
System.out.println("bulgeStrength "+bulgeStrength);
}
updateImage(e.getX(), e.getY());
}
});
}
#Override
#Transient
public Dimension getPreferredSize()
{
if (isPreferredSizeSet())
{
return super.getPreferredSize();
}
return new Dimension(input.getWidth(), input.getHeight());
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if (output != null)
{
g.drawImage(output, 0, 0, null);
}
}
private void updateImage(int x, int y)
{
if (output == null)
{
output = new BufferedImage(
input.getWidth(), input.getHeight(),
BufferedImage.TYPE_INT_ARGB);
}
computeBulgeImage(input, x, y,
bulgeStrength, bulgeRadius,
output);
repaint();
}
private static void computeBulgeImage(
BufferedImage input, int cx, int cy,
double bulgeStrength, double bulgeRadius,
BufferedImage output)
{
int w = input.getWidth();
int h = input.getHeight();
for(int x = 0; x < w; x++)
{
for(int y = 0; y < h; y++)
{
int dx = x-cx;
int dy = y-cy;
double distanceSquared = dx * dx + dy * dy;;
int sx = x;
int sy = y;
if (distanceSquared < bulgeRadius * bulgeRadius)
{
double distance = Math.sqrt(distanceSquared);
boolean otherMethod = false;
otherMethod = true;
if (otherMethod)
{
double r = distance / bulgeRadius;
double a = Math.atan2(dy, dx);
double rn = Math.pow(r, bulgeStrength)*distance;
double newX = rn*Math.cos(a) + cx;
double newY = rn*Math.sin(a) + cy;
sx += (newX - x);
sy += (newY - y);
}
else
{
double dirX = dx / distance;
double dirY = dy / distance;
double alpha = distance / bulgeRadius;
double distortionFactor =
distance * Math.pow(1-alpha, 1.0 / bulgeStrength);
sx -= distortionFactor * dirX;
sy -= distortionFactor * dirY;
}
}
if (sx >= 0 && sx < w && sy >= 0 && sy < h)
{
int rgb = input.getRGB(sx, sy);
output.setRGB(x, y, rgb);
}
}
}
}
}
I'm making a game in java where enemy sprites spiral to the center and damage the main tower. The only thing I'm having problems with is the formula to make the sprite spiral. All I found on the internet it this: http://scratch.mit.edu/projects/1439249/
That is sort of what I want to do but I want to make them spiral to a point from outside the JFrame, not from a point within the JFrame.
I am in Secondary 4 and I don't have to much knowledge about such formulas yet and sorry if I have problems understanding the formulas. Thanks in advance!
One simple way of making a sprite appear to spiral is to pretend that it is attached to an arm, like the hand of a clock, that rotates around the center of the spiral. As that arm rotates, slowly move the sprite down the arm towards the center. What you end up with is a classic Archimedan Spiral
I can mock up some code for you, but that's going to take a few minutes.
Okay, here's the code.
public static double getArmX(double length, double angle) {
return Math.cos(angle) * length;
}
public static double getArmY(double length, double angle) {
return Math.sin(angle) * length;
}
These are the core of the math. They return the x and y values of an entity that is at the specified distance from the center (length) and angle from the center (angle).
Now, I don't know how you have your code set up, but lets pretend we have a double named spiralProgress that represents how far into its spiral your entity is. At spiralProgress == 0, the entity is just starting, and at spiralProgress == 1, the entity is at the center.
Here is what the code to get the x and y for the entity would look like:
double startingRadius = 64;
double rotations = 10;
double x = getArmX(startingRadius * (1-t), t * rotations * Math.PI * 2);
double y = getArmY(startingRadius * (1-t), t * rotations * Math.PI * 2);
In that snippet, startingRadius is how many units (pixels, if thats what x and y means in your program), the entity should start away from the center, and rotations is how many times the entity should loop around the center before reaching it.
The coordinates this returns are for a spiral around {0, 0}, so if you want to spiral around some other point, say {screenWidth / 2, screenHeight / 2}, you'd add screenWidth / 2 to x and screenHeight / 2 to y.
Here is a full Java program that demonstrates this math. Click the mouse anywhere in the window to reset the spiral.
package net.eonz.stackoverflow.spiral;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable, MouseListener {
private static final long serialVersionUID = 1L;
public static final String NAME = "untitled";
public static final int HEIGHT = 600;
public static final int WIDTH = 600;
public static final int SCALE = 1;
private boolean running = false;
public void start() {
running = true;
new Thread(this).start();
this.addMouseListener(this);
}
public void stop() {
running = false;
}
public void run() {
long last = System.currentTimeMillis();
while (running) {
long now = System.currentTimeMillis();
double dt = (now - last) / 1000.0;
last = now;
update(dt);
render();
}
}
double t = 0;
public void update(double dt) {
t += dt / 16;
if (t > 1)
t = 1;
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
/* SPIRAL MATH IS HERE */
double startingRadius = this.getHeight() * 0.40;
double rotations = 10;
double x = getArmX(startingRadius * (1 - t), t * rotations * Math.PI
* 2);
double y = getArmY(startingRadius * (1 - t), t * rotations * Math.PI
* 2);
g.setColor(Color.black);
g.fillRect((int) (x - 8) + this.getWidth() / 2,
(int) (y - 8) + this.getHeight() / 2, 16, 16);
/* END SPIRAL MATH */
g.dispose();
bs.show();
}
public static double getArmX(double length, double angle) {
return Math.cos(angle) * length;
}
public static double getArmY(double length, double angle) {
return Math.sin(angle) * length;
}
#Override
public void mouseClicked(MouseEvent e) {
this.t = 0;
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
public static void main(String[] args) {
Game game = new Game();
game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame frame = new JFrame(Game.NAME);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(game, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
game.start();
}
}
I am new to java programming too and as part of my course I recently had to program a spiral.
Here is the solution file from my course.
This will draw a simple spiral.
I hope this helps you. It also has comments to help you understand what is happening.
enjoy
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawSpiral2 extends JPanel
{
// draws a square shape that continually spirals outward
public void paintComponent( Graphics g )
{
super.paintComponent( g );
g.setColor( Color.GREEN );
// draw a green spiral
int x = getWidth() / 2;
// x coordinate of upperleft corner
int y = getHeight() / 2;
// y coordinate of upperleft corner
int radiusStep = 20;
// distance the radius changes
int diameter = 0; // diameter of the arc
int arc = 180; // amount and direction of arc to sweep
// draws individual lines in to form a spiral
for ( int i = 0; i < 20; i++ )
{
if ( i % 2 == 1 ) // move the x position every other repetition
x -= 2 * radiusStep;
y -= radiusStep; // move the y position
diameter += 2 * radiusStep; // increase the diameter
g.drawArc( x, y, diameter, diameter, 0, arc );
// draw the arc
arc = -arc; // reverse the direction of the arc
} // end for
} // end method paintComponent
} // end class DrawSpiral2
Here is the test file.
public class DrawSpiralTest2
{
public static void main( String args[] )
{
DrawSpiral2 panel = new DrawSpiral2();
JFrame application = new JFrame();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
application.add( panel );
application.setSize( 300, 300 );
application.setVisible( true );
} // end main
} // end class DrawSpiralTest2