I want an circular movement of an image in JAVA, i thought I have the solution but it doesn't work and i'm a bit clueless now.
For calculating the points it needs to go im using pythagoras to calculate the height (point B).
if it does one round im satisfied but more rounds would be cool.
The image size is around 500 x 300 pixels.
Here's my code :
package vogel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class Vogel extends Component {
private int x;
private int r;
private int b;
BufferedImage img;
public vogel() {
try {
img = ImageIO.read(new File("F:/JAVA/workspace/School/src/vogel/vogel.png"));
} catch (IOException e) {
}
r = 60;
x = 10;
}
#Override
public void paint(Graphics g) {
for(int i = -x; i <= x; i++) {
b = (int)Math.sqrt(r^2 - i^2);
g.drawImage(img, x, b, this);
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Vogel");
f.setSize(1000,1000);
f.add(new Vogel());
f.setVisible(true);
for (int number = 1; number <= 1500000; number++) {
f.repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
}
}
}
Using your loop in the paint(Graphics) method, it draws 21 birds with one repaint.
You should do it with an angle stored in an object variable and use the Math.sin() and Math.cos() function calculate the x and y position. The angle should be increased with every repaint().
To add:
// To control the radius of moving
private final double MAX_X = 200;
private final double MAX_Y = 200;
private double angle = 0;
#Override
public void paint(Graphics g) {
// increase angle (should be a double value)
angle += 0.1;
// rotate around P(0/0), assuming that 0° is vector (1/0)
int x = (int) (Math.cos(angle) * MAX_X);
int y = (int) (Math.sin(angle) * MAX_Y);
// move P to center of JFrame (width and height = 1000)
x += 500;
y += 500;
// image is 500x300, calc upper left corner
x -= 250;
y -= 150;
// draw
g.drawImage(img, x, y, null);
}
To remove:
private double x, b, r;
So this is the code, try it.
Addition to Sibbo's code to convert angle to rads
private double angle = 0.1;
#Override
public void paint(Graphics g) {
// increase angle (should be a double value
double random = angle * 2.0 * Math.PI/360.0; //this will convert it to rads
// rotate around P(0/0)
int x = (int) (Math.cos(random) * MAX_X);
int y = (int) (Math.sin(random) * MAX_Y);
// move P to center of JFrame (width and height = 1000)
x += 500;
y += 500;
// image is 500x300, calc upper left corner
x -= 250;
y -= 150;
angle++
// draw
g.drawImage(img, x, y, null);
}
Related
I'm trying to write a code that approximates the value of PI.
What I'm doing is:
drawing a circle inside a rectangle
drawing random points inside the rectangle and circle
calculating the ratio between rect/cicle
calculating 4/ratio
that should be PI
This my code:
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Random;
public class Main extends Frame {
int width = 800;
ArrayList<Point> list = new ArrayList<Point>();
public void points(Graphics g) {
int numPoint = 10000000;
for (int i = 0; i < numPoint; i++) {
int min = 23;
int max = 23 + width;
Random rand = new Random();
int x = rand.nextInt(width);
int y = (int) (Math.random() * (max - min + 1) + min);
Point temp = new Point(x, y);
list.add(temp);
if (inCircle(temp)) {
g.setColor(Color.green);
} else {
g.setColor(Color.blue);
}
g.drawLine(x, y, x, y);
}
}
public void paint(Graphics g) {
g.fillRect(0, 0, 1000, 1000);
int x = width / 2;
int y = width / 2 + 23;
int radius = width / 2;
g.setColor(Color.WHITE);
g.drawOval(x - radius, y - radius, radius * 2, radius * 2);
g.drawRect(0, 23, width, width);
points(g);
calculatingPI();
}
public void calculatingPI() {
double inCircle = 0;
double inRect = list.size();
for (Point p : list) {
if (inCircle(p)) {
inCircle++;
}
}
double ratio = inRect / inCircle;
System.out.print("PI is approximated to: " + 4 / ratio + " ");
}
public boolean inCircle(Point p) {
Point center = new Point(width / 2, width / 2 + 23);
return center.distance(p) <= width / 2;
}
public static void main(String[] args) {
Frame frame = new Main();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
// circle coordinates.
frame.setSize(800, 1000);
frame.setVisible(true);
}
}
It works quite fine, even if most of the time the number is around 1,13 which is not a great approx.
The question is:
The more I decrease the size of the rectangle and circle, (without changing the number of points), the less PI becomes accurate. I don't understand, why is that? Is there a problem in my code?
Shouldn't it be the opposite? The smallest the area, the more points are accurate, the more PI is accurate. Why is isn't it the case?
You are using integer pixels. This means the smaller you make your "circle", the worse it approximates a true circle. For example here's the circle within a 3x3 pixel square: it does not look circular at all.
█
███
█
To get a better approximation, use double floating point numbers instead of integers. Use Point2D.Double instead of the Point class:
ArrayList<Point2D.Double> list = new ArrayList<>();
To generate the random points:
double x = Math.random() * width;
double y = Math.random() * (max - min) + min;
Point2D.Double temp = new Point2D.Double(x, y);
Note that where you had max-min+1, the +1 has to be removed.
To test if the point is within the circle:
public boolean inCircle(Point2D.Double p) {
Point2D.Double center = new Point2D.Double(width / 2d, width / 2d + 23);
return center.distance(p) <= width / 2d;
}
I'm trying to learn how to make a 2D Game without Game Engines, anyways I already created a background scrolling right now my goal is to make my character jump. But the thing is whenever I start my app the character is spinning up and down and it will just go away to the background.
Here's my character code
public class Deer extends GameCharacter {
private Bitmap spritesheet;
private double dya;
private boolean playing;
private long startTime;
private boolean Jump;
private Animate Animation = new Animate();
public Deer(Bitmap res, int w, int h, int numFrames) {
x = 20;
y = 400;
dy = 0;
height = h;
width = w;
Bitmap[] image = new Bitmap[numFrames];
spritesheet = res;
for (int i = 0; i < image.length; i++)
{
image[i] = Bitmap.createBitmap(spritesheet, i*width, 0, width, height);
}
Animation.setFrames(image);
Animation.setDelay(10);
startTime = System.nanoTime();
}
public void setJump(boolean b){
Jump = b;
}
public void update()
{
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>100)
{
}
Animation.update();
if(Jump){
dy = (int)(dya+=5.5);
}
else{
dy = (int)(dya+=5.5);
}
if(dy>14)dy = 14;
if(dy>14)dy = -14;
y += dy*2;
dy = 0;
}
public void draw(Canvas canvas)
{
canvas.drawBitmap(Animation.getImage(),x,y,null);
}
public boolean getPlaying(){return playing;}
public void setPlaying(boolean b){playing = b;}
public void resetDYA(){dya = 0;}
}
x - character's horizontal position
y - character's vertical position
dx - character's horizontal acceleration
dy - character's vertical acceleration
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN) {
if(!deer.getPlaying()) {
deer.setPlaying(true);
}
deer.setJump(true);
return true;
}
return super.onTouchEvent(event);
}
I can't say for sure if this is the only problem because you have other suspicious code but it looks like you jump no matter what.
if(Jump){
dy = (int)(dya+=5.5);
} else {
dy = (int)(dya+=5.5);
}
If Jump is true you set the vertical acceleration. But you also set the vertical acceleration to the same value if Jump is false. You also don't show in your code where Jump is ever set to false.
Another odd bit of code is:
if(dy>14)dy = 14;
if(dy>14)dy = -14;
Here, if dy>14 you set it to 14. Then you check dy>14 immediately after. Of course, this time it's false. But because those two conditions are the same the second one will never pass since the one before it ensures it won't. The only other option is they both fail. IOW, you'll never be able to enter the second if.
All that aside, I'm not sure why you're taking this approach. You can simply rely on physics equations with constant acceleration, give an initial velocity, check for a collision with the ground (or at least the original height), and just let it run. For example:
// These are the variables you need.
int x = 200, y0 = 0, y = 0, velocity = 15;
double t = 0.0, gravity = -9.8;
// This is the statement that should run when you update the GUI.
// It is the fundamental equation for motion with constant acceleration.
// The acceleration is the gravitational constant.
y = (int) (y0 + velocity * t + .5 * gravity * t * t);
if (y < 0) {
y = y0 = 0;
//Stop jumping!
Jump = false;
} else {
// Swap the y values.
y0 = y;
// Increase the time with the frame rate.
t += frameRate;
}
// Draw the character using the y value
The best part about this is you don't need to worry about when you get to the maximum height because the equation will automatically bring you down. It also looks more natural as if the mechanics are real. Try it out.
A simple Swing example that you can play around with. Note that the values are different to deal with the way the components are drawn to the screen. Normally, you would deal with that with transformations but this will do for the task.
public class Main {
static Timer timer;
Main() {
JFrame frame = new JFrame("Hello sample");
frame.setSize(new Dimension(550, 550));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new MyPanel();
frame.add(panel);
frame.setVisible(true);
timer = new Timer(5, (e) -> panel.repaint());
timer.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(Main::new);
}
class MyPanel extends JPanel {
int x = 200, y0 = 300, y = 0, w = 200, h = 200, v = -8;
double t = 0.0, gravity = 9.8;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
y = (int) (y0 + v * t + .5 * gravity * t * t);
if (y > 300) {
y = y0 = 300;
// To prevent it from stopping comment the timer.stop() and
// uncomment the t = 0.0 statements.
//t = 0.0;
timer.stop();
} else {
y0 = y;
t += .025;
}
g.drawOval(x, y, w, h);
}
}
}
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 having issues with the balls that I display in my JFrame window. Here's the main idea of my application:
Point object (with coordinates x and y) --> Vector object (a class I wrote that has the x and y components of a vector, as well as a few methods... gets its location and head/tail points from the Point object) --> Ball object (the position, velocity, and acceleration vectors are collected in an ArrayList, also has radius and color attributes) --> ContainerBox object (contains the balls, defines the min/max x and y for collision detection purposes).
I'm working toward having one ball centered in the window and the other orbiting the first, but right now I'm just trying to get my objects to play nicely. I'm very new to OOP principles and this is the first time I've written a program using classes in this way.
Everything works perfectly, the JFrame comes up and displays the balls... the problem is that the balls won't show up in the right places. No matter what I put in for the x and y coordinates of the balls (either explicitly or using the objects), they always show up in the upper left-hand corner of the screen. Here's a pic of what I get: Picture Here
I don't know whether it's the vectors or the collision detection or what... any ideas? Thanks a lot for reading and replying!
EDIT: Here's some of the code that I'm using (sorry to put so much, I have no idea where the problem is):
EDIT AGAIN: Added the ball class that I forgot.
package chaneyBouncingBall;
import java.util.*;
public class Point
{
float x;
float y;
public Point(float x, float y)
{
this.x = x;
this.y = y;
}
}
package chaneyBouncingBall;
import java.util.ArrayList;
public class Chaney2DVector
{
float x;
float y;
Point fromLocation;
public Chaney2DVector(float x,
float y)
{
this.x = x;
this.y = y;
}
public Chaney2DVector(Point point1,
Point point2)
{
fromLocation = new Point(point1.x, point1.y);
this.x = point2.x - point1.x;
this.y = point2.y - point1.y;
}
}
package chaneyBouncingBall;
import java.awt.*;
import java.util.*;
public class Ball
{
float x, y;
float velX, velY;
float accelX, accelY;
float radius;
private Color color;
public Ball(float x, float y, float velX,
float velY, float accelX,
float accelY, float radius,
Color color)
{
Chaney2DVector position = new Chaney2DVector(x, y);
Chaney2DVector velocity = new Chaney2DVector(velX, velY);
Chaney2DVector acceleration = new Chaney2DVector(accelX, accelY);
ArrayList posVelAcc = new ArrayList();
posVelAcc.add(position);
posVelAcc.add(velocity);
posVelAcc.add(acceleration);
this.radius = radius;
this.color = color;
}
public void draw(Graphics g)
{
g.setColor(color);
g.fillOval((int)(x - radius), (int)(y - radius),
(int)(2 * radius), (int)(2 * radius));
}
public void moveOneStepWithCollisionDetection( ContainerBox box)
{
float ballMinX = box.minX + radius;
float ballMinY = box.minY + radius;
float ballMaxX = box.maxX - radius;
float ballMaxY = box.maxY - radius;
x = x + velX;
y = y + velY;
if (x < ballMinX)
{
velX = -velX;
x = ballMinX;
}
else if (x > ballMaxX)
{
velX = -velX;
x = ballMaxX;
}
if (y < ballMinY)
{
velY = -velY;
y = ballMinY;
}
else if (y > ballMaxY)
{
velY = -velY;
y = ballMaxY;
}
}
}
package chaneyBouncingBall;
import java.awt.*;
/**
* A rectangular container box, containing the bouncing ball.
*/
public class ContainerBox {
int minX, maxX, minY, maxY; // Box's bounds (package access)
private Color colorFilled; // Box's filled color (background)
private Color colorBorder; // Box's border color
private static final Color DEFAULT_COLOR_FILLED = Color.BLACK;
private static final Color DEFAULT_COLOR_BORDER = Color.YELLOW;
/** Constructors */
public ContainerBox(int x, int y, int width, int height, Color colorFilled, Color colorBorder) {
minX = x;
minY = y;
maxX = x + width - 1;
maxY = y + height - 1;
this.colorFilled = colorFilled;
this.colorBorder = colorBorder;
}
/** Constructor with the default color */
public ContainerBox(int x, int y, int width, int height) {
this(x, y, width, height, DEFAULT_COLOR_FILLED, DEFAULT_COLOR_BORDER);
}
/** Set or reset the boundaries of the box. */
public void set(int x, int y, int width, int height) {
minX = x;
minY = y;
maxX = x + width - 1;
maxY = y + height - 1;
}
/** Draw itself using the given graphic context. */
public void draw(Graphics g) {
g.setColor(colorFilled);
g.fillRect(minX, minY, maxX - minX - 1, maxY - minY - 1);
g.setColor(colorBorder);
g.drawRect(minX, minY, maxX - minX - 1, maxY - minY - 1);
}
}
package chaneyBouncingBall;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
/**
* The control logic and main display panel for game.
*/
public class BallWorld extends JPanel {
private static final int UPDATE_RATE = 50; // Frames per second (fps)
private Ball ball; // A single bouncing Ball's instance
private Ball ball2;
private ContainerBox box; // The container rectangular box
private DrawCanvas canvas; // Custom canvas for drawing the box/ball
private int canvasWidth;
private int canvasHeight;
/**
* Constructor to create the UI components and init the game objects.
* Set the drawing canvas to fill the screen (given its width and height).
*
* #param width : screen width
* #param height : screen height
*/
public BallWorld(int width, int height) {
canvasWidth = width;
canvasHeight = height;
boolean stationary = true;
Random rand = new Random();
int angleInDegree = rand.nextInt(360);
int radius = 50;
int radius2 = 25;
// double accelAngle;
float x1 = rand.nextInt(canvasWidth - radius * 2 - 20) + radius + 10;
float y1 = rand.nextInt(canvasHeight - radius * 2 - 20) + radius + 10;
float x2 = rand.nextInt(canvasWidth - radius * 2 - 20) + radius + 10;
float y2 = rand.nextInt(canvasHeight - radius * 2 - 20) + radius + 10;
// float x = 100;
// float y = 100;
float velX1 = 0;
float velY1 = 0;
float accelX1 = 0;
float accelY1 = 0;
float velX2 = 0;
float velY2 = 0;
float accelX2 = 0;
float accelY2 = 0;
ball = new Ball(canvasWidth / 2, canvasHeight / 2, velX1, velY1, accelX1, accelY1,
radius, Color.BLUE);
ball2 = new Ball(x2, y2, velX2, velY2, accelX2, accelY2, radius / 5, Color.YELLOW);
// Init the Container Box to fill the screen
box = new ContainerBox(0, 0, canvasWidth, canvasHeight, Color.BLACK, Color.WHITE);
// Init the custom drawing panel for drawing the game
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
// Handling window resize.
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
Component c = (Component)e.getSource();
Dimension dim = c.getSize();
canvasWidth = dim.width;
canvasHeight = dim.height;
// Adjust the bounds of the container to fill the window
box.set(0, 0, canvasWidth, canvasHeight);
}
});
// Start the ball bouncing
gameStart();
}
/** Start the ball bouncing. */
public void gameStart() {
// Run the game logic in its own thread.
Thread gameThread = new Thread() {
public void run() {
while (true) {
// Execute one time-step for the game
gameUpdate();
// Refresh the display
repaint();
// Delay and give other thread a chance
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException ex) {}
}
}
};
gameThread.start(); // Invoke GaemThread.run()
}
/**
* One game time-step.
* Update the game objects, with proper collision detection and response.
*/
public void gameUpdate() {
ball.moveOneStepWithCollisionDetection(box);
ball2.moveOneStepWithCollisionDetection(box);
}
/** The custom drawing panel for the bouncing ball (inner class). */
class DrawCanvas extends JPanel {
/** Custom drawing codes */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // Paint background
// Draw the box and the ball
box.draw(g);
ball.draw(g);
ball2.draw(g);
// Display ball's information
g.setColor(Color.WHITE);
g.setFont(new Font("Courier New", Font.PLAIN, 12));
// g.drawString("Ball " + ball.toString(), 20, 30);
}
/** Called back to get the preferred size of the component. */
#Override
public Dimension getPreferredSize() {
return (new Dimension(canvasWidth, canvasHeight));
}
}
}
package chaneyBouncingBall;
import javax.swing.JFrame;
public class Main
{
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame("Matt Chaney's Gravity App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new BallWorld(550, 450));
frame.pack();
frame.setVisible(true);
}
});
}
}
In the constructor of your Ball class, you don't assign all the instance variables to their parameters, these need to be added.
public Ball(float x, float y, float velX, float velY, float accelX, float accelY, float radius, Color color) {
...
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.accelX = accelX;
this.accelY = accelY;
}
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