I'm working on a bouncing ball program. I have successfully made a ball that goes up and down. I have set so that the ball are unable to go out of bounds so when it hits the edge of the screen, it simply bounces back up and so on.
Now, the thing is, I want the ball to eventually stop moving. For example, I start the program, the ball drops and bounces back up to maybe 80% of it's starting height. And when it comes down again it will accelerate due to gravity and then go back up but maybe only reach about 60% of it's original height, and eventually it will stop moving.
How do I create such a thing? I've googled for hours but found nothing of help. So now I implore you to give me a hand. Also, if you do decide to give me a handy tip, please try to be specific and very clear. I have not been programming for that long. Thanks in advance.
Here is my code:
EDIT: OBSERVE that I don't have a main method for this class since I don't need it. I'm running it through another class via an object.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Game extends JPanel implements ActionListener{
int DIAMETER = 40;
int yPos;
int yVel = 3;
int GRAVITY =1;
Timer tm = new Timer(5,this);
public void paintComponent(Graphics g){
super.paintComponent(g);
//Setting the characteristics for the ball
g.setColor(Color.red);
g.fillOval(0, yPos, DIAMETER, DIAMETER);
tm.start();
repaint();
}
public void actionPerformed(ActionEvent e) {
//If it decides to go out of the screen, change direction.
if(yPos<0 || yPos>430)yVel=-yVel;
//This basically is the "engine". It moves the ball.
yPos = yPos + yVel;
}
}
Take some energy out of the system.
Just as it hits the ground, the kinetic energy is E = 0.5 * m * v * v where m is the mass and v the speed.
Reduce E by a certain amount, say new_E = 0.8 * E. Then compute the new initial upward speed using the kinetic energy formula rearranged.
That is surprisingly realistic. Of course, you don't really need the 0.5 coefficient but I've retained it there to keep the physicists happy. You also don't need m either.
Related
I'm making a program where you have a server and a client, and the idea is that you draw on the client jpanel, and the coordinates will then be sent to the server, which will sort of mimic the drawing. I've done that, but the problem is now, that my drawing mechanism is pretty bad. Right now I'm just using an oval that gets drawn over and over again on the coordinate of the mouse, which sometimes leaves spaces between the ovals if you move the mouse too fast.
To better illustrate, here's an SS: http://gyazo.com/6ed1017e9efd6beaa4b5d56052fda260
As you can see, it's only consistent when you move the mouse relatively slow, but as soon as you move it a bit fast, it leaves spaces.
How do I prevent this from happening?
Right now the client just sends x and y coordinates, so here's the server side code:
package com.company;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server extends JPanel{
static MouseData mouseReceive;
static Draw draw;
static int x;
static int y;
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Server server = new Server();
JFrame frame = new JFrame("Server");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(server);
frame.setSize(1024, 600);
frame.setVisible(true);
draw = new Draw(x,y);
ServerSocket serverSock = new ServerSocket(1234);
Socket s = serverSock.accept();
ObjectInputStream in = new ObjectInputStream(s.getInputStream());
while(true) {
mouseReceive = (MouseData) in.readObject();
draw = new Draw(mouseReceive.mouseX,mouseReceive.mouseY);
}
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
draw.display(g);
repaint();
}
}
And here's my draw class:
package com.company;
import java.awt.*;
/**
* Created by John on 21/04/2015.
*/
public class Draw {
int xLoc;
int yLoc;
Draw(int x, int y){
xLoc = x;
yLoc = y;
}
public void display(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.fillOval(xLoc,yLoc,7,7);
}
}
I tried finding someone else having the same problem on this site through the search function, but I had no luck in doing so :( If I missed it however, please direct me to that topic!
If anyone could help me out, I'd appreciate it a whole lot! Have a nice day :)
Presuming the Client is using a MouseListener (or MouseMotionListener): the MouseListener can only fire as fast as a certain interval. For example when the mouse is constantly moved your listener will receive a MouseEvent for every interval rather than every pixel. As a result, moving the mouse fast may result in drawing items that are not adjacent to each other. AFAIK, you cannot increase the speed, but you can draw lines between two sequential points making them look continuous (eg by using a List of each event location and using g.drawLine on each two adjacent points in the List).
Other notes:
You should override paintComponent rather than the paint method.
I would recommend calling super.paintComponent in this method. This will clear the component (hence your code will then only draw the last point - see (3))
I would recommend keeping a List of locations to use for drawing, which you can iterate over and draw each circle (or draw a line between adjacent points)
Do NOT call repaint within your painting methods. The idea here is that when a new item is received from the Client, add it to the List in (3) and then call repaint.
I want to make a program in Java to rotate a Newton's Disc at high speed so that it appears white. But the timer class has a minimum delay of 1 millisecond only. Can I speed things up somehow (maybe I can pass something like 0.084 as delay somehow?)? Also the image flickers. Any way to get rid of it? Here's the code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class NDisc extends JPanel implements ActionListener
{
Timer a;
double angle=0;//To store value of angle of rotation in radians
ImageIcon c;
Image dbImage;
Graphics dbg;
public NDisc()
{
a=new Timer(1,this);//Change delay here to increase or decrease the speed of rotation
c=new ImageIcon("ND4.png");
a.start();
}
public void paintComponent(Graphics g)
{
Graphics2D g2=(Graphics2D)g;
super.paintComponent(g);
g2.rotate(angle,300,300);//300,300 is the center of the screen which I need as the point about which the disc rotates
c.paintIcon(this, g2,100,100);//Image dimensions in (300,300) and JFrame size in main() is (600,600), so I paint the image at (100,100) thus making the center of the JFrame and the image coincide
angle+=0.001;//To increment angle of rotation for the animation to take place
}
public void actionPerformed(ActionEvent e)
{
repaint();
}
public static void main(String args[])
{
NDisc obj2=new NDisc();
JFrame obj=new JFrame("Physics");
obj.add(obj2);
obj.setSize(600,600);
obj.setLocationRelativeTo(null);
obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
obj.setResizable(true);
obj.setVisible(true);
}
}
You've got it wrong. For an animation you really need no more than ~25 fps. What you need is to adjust the work done between animations.
Simply replace
angle+=0.001;
by something configurable and you're done. But let's do it better:
angle = speed * System.currentTimeMillis() - startTime;
This works even when you can't keep the pace given by the timer. The disadvantage is that you can't stop the time. But this has a simple solution, too (ask if you need it).
I got the head, one arm and the body. I am trying to make another arm using the same first two coordinates, which starts at the bottom of the head, but a negative last (but same number) last two coordinates. I assumed that if I made a negative version, it would just make an opposite version of the line. Instead, its just sticking straight up! I am confused on why this is happening.
import javax.swing.JComponent;
import java.awt.*;
import java.awt.geom.*;
public class StickFigure extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Ellipse2D.Double head = new Ellipse2D.Double(5, 10, 50, 50);
g2.draw(head);
Line2D.Double body=new Line2D.Double(30,60, 30,150);
g2.draw(body);
Line2D.Double arm1=new Line2D.Double(30,60,75,75);
g2.draw(arm1);
Line2D.Double arm2=new Line2D.Double(30,60,-75,-75);
g2.draw(arm2);
}
}
That is the code that is giving me trouble. I am using a viewer which is the following:
import javax.swing.JFrame;
public class Viewer
{
public static void main(String[] arg)
{
JFrame frame = new JFrame();
frame.setSize(1000,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
StickFigure fig1=new StickFigure();
frame.add(fig1);
frame.setVisible(true);
}
}
Please let me know what I am doing wrong, I would greatly appreciate it.
Line2D.Double arm2=new Line2D.Double(30,60,-75,-75);
You need to think about what you're saying with -75 and -75. Remember those make a coordinate, and (0, 0) represents the top left corner in Swing (unless you're explicitly telling it not to). Those coordinates are offscreen to the northwest.
Try something like:
Line2D.Double arm2=new Line2D.Double(30,60, 45,75);
Try using a positive y last coordinate for both:
Line2D.Double arm1=new Line2D.Double(30,60,75,75);
g2.draw(arm1);
Line2D.Double arm2=new Line2D.Double(30,60,-75,75);
g2.draw(arm2);
You are right that -75 -75 "would just make an opposite version of the line", but when you alter both coordinates you get radial simmetry, that is simmetry around a point (the neck) hence one of your arm is low and the other is up. You want axial symmetry in this case, and for that you only need to flip one coordinate; since people's axis of symmetry is the spine, and it is vertical (y-direction) you need to flip coordinate x only.
I have two JPanels. One panel has a 100x100 rectangle drawn at 0,0. And the other has a 100x100 rectangle drawn at 100, 100. My problem is that when both JPanels are drawn on the JFrame's content pane, one JPanel (the last one drawn) covers the other, hiding its graphics. Below is oversimplified code drawing two rectangles and the things I've tried.
package playground;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Playground{
public Playground(){
JFrame frame = new JFrame("My Frame");
frame.setSize(400, 400);
JPanel backPanel = new JPanel(){;
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
Rectangle2D rect = new Rectangle2D.Double(0, 0, 100, 100);
g2.draw(rect);
}
};
JPanel frontPanel = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
Rectangle2D rect = new Rectangle2D.Double(150, 150, 100, 100);
g2.draw(rect);
}
};
frontPanel.setOpaque(true); //Does nothing
frontPanel.setBackground(new Color(0, 0, 0, 0)); //Does nothing
frontPanel.setForeground(new Color(0, 0, 0, 0)); //Erases the rectangle drawn
frame.getContentPane().add(backPanel);
frame.getContentPane().add(frontPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args){
System.out.println("Hello World");
new Playground();
}
}
If anyone cares why I want to do this,
I'm creating the game breakout. I am a novice programmer and I have no knowledge of gaming theory. So I decided the smartest way to avoid a lot of rendering and buffering is to have four JPanels. A static JPanel at the very back with an image drawn on it (fun background image). A JPanel with the paddle drawn on it. A JPanel with bricks drawn on it. And a JPanel with a ball drawn on it. My rationale is that I won't have to redraw the paddle if it is not being moved, the background, and bricks that are not being hit. If a brick lets say is hit, I will update an arrayList of bricks and call repaint on the corresponding JPanel.
I am a novice programmer and I have no knowledge of gaming theory.
Ok, we can work with that.
So I decided the smartest way to avoid a lot of rendering and buffering is to have four JPanels.
You've just unnecessarily complicated your program.
Think of a JPanel as a canvas. You want to draw the entire Breakout game; bricks, paddle, and ball, on one JPanel canvas. Don't worry, you'll be able to redraw the entire canvas fast enough to get 60 frames per second if you want.
The way to do this is to create a Brick class, a Paddle class, and a Ball class. You create a Game Model class that contains one instance of the Paddle class, one instance pf the Ball class, and a List of instances of the Brick class.
The Brick class would have fields to determine its position in the wall, the number of points scored when the ball collides with the brick, the color of the brick, and a draw method that knows how to draw one brick.
The ball class would have fields to determine its x, y position, its direction, its velocity, and a draw method that knows how to draw the ball.
The Paddle class would have fields to determine its x, y position, its direction, its velocity, and a draw method that knows haw to draw the paddle.
The Game Model class would have methods to determine when the ball collides with a brick, determine when the ball collides with a brick, determine when the ball collides with a wall, and a draw method that calls the other model class draw methods to draw a ball, a paddle, and a wall of bricks.
This should be enough for now to get you started going in the right direction.
Edited to answer questions:
How would I implement a draw method in all these classes?
Here's an example Ball class. I haven't tested the moveBall method, so it might need some adjustment
import java.awt.Graphics;
import java.awt.geom.Point2D;
public class Ball {
private Point2D position;
/** velocity in pixels per second */
private double velocity;
/**
* direction in radians
* <ul>
* <li>0 - Heading east (+x)</li>
* <li>PI / 2 - Heading north (-y)</li>
* <li>PI - Heading west (-x)</li>
* <li>PI * 3 / 2 - Heading south (+y)</li>
* </ul>
* */
private double direction;
public Point2D getPosition() {
return position;
}
public void setPosition(Point2D position) {
this.position = position;
}
public double getVelocity() {
return velocity;
}
public void setVelocity(double velocity) {
this.velocity = velocity;
}
public double getDirection() {
return direction;
}
public void setDirection(double direction) {
this.direction = direction;
}
public void moveBall(long milliseconds) {
Point2D oldPosition = position;
// Calculate distance of ball motion
double distance = velocity / (1000.0D * milliseconds);
// Calculate new position
double newX = distance * Math.cos(direction);
double newY = distance * Math.sin(direction);
newX = oldPosition.getX() + newX;
newY = oldPosition.getY() - newY;
// Update position
position.setLocation(newX, newY);
}
public void draw(Graphics g) {
int radius = 3;
int x = (int) Math.round(position.getX());
int y = (int) Math.round(position.getY());
// Draw circle of radius and center point x, y
g.drawOval(x - radius, y - radius, radius + radius, radius + radius);
}
}
The draw method draws the ball wherever it actually is located. That's all the draw method does.
Actually moving the ball is the responsibility of the Game Model class. The method for moving the ball is included in this class because the information necessary to move the ball is stored in the Ball class.
I gave the ball a radius of 3, or a diameter of 6 pixels. You may want to make the ball bigger, and use the fillOval method instead of drawOval.
should I just call repaint() at a 30ms interval
Basically, yes.
In psudeocode, you create a game loop
while (running) {
update game model();
draw game();
wait;
}
First, you update the game model. I gave you a Ball class. You would have similar classes for the paddle and bricks. They all have draw methods.
Your Game model class calls all of these draw methods in the proper order. In Breakout, you would draw the boundaries first, then the bricks, then the paddle, and finally, the ball.
Your JPanel (canvas) calls the one draw method in the Game Model class.
I don't have an example game to show you, but if you read the article Sudoku Solver Swing GUI, you'll see how to put together a Swing GUI and you'll see how model classes implement draw methods.
I suggest that you stop working on Breakout for a while and go through the Oracle Swing Tutorial. Don't skip any sections in your haste to write a program. Go through the entire tutorial so you understand how Swing works before you try and use it.
I have a task to draw a circle and then fill in with the most amount of circles without touching the sides. I can draw the circle, and I can make loops to pack the circle in a hexagonal/honeycomb format, but can't control whether they are inside or outside the circle.
I have used this: g.drawOval(50, 50, 300, 300); to specify my circle. Given I'm actually specifying a square as my boundaries I can't actually determine where the circle boundaries are. So I'm basically packing the square full of circles rather than the circle full of circles.
Can some please point me in the right direction? I'm new to java so not sure if I have done this the complete wrong way. My code is below. I have another class for the frame and another with the main in it.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class DrawCircle extends JPanel
{
private int width, height, diameter;
public DrawFrame d;
public DrawCircle()
{
width = 400;
height = 400;
diameter = 300;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.blue);
g.drawOval(50, 50, 300, 300);
for(int i=50; i<200; i=i+20)
{
for(int j=50; j<350; j=j+10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=60; i<200; i=i+20)
{
for(int j=55; j<350; j=j+10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=330; i>190; i=i-20)
{
for(int j=340; j>40; j=j-10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=340; i>190; i=i-20)
{
for(int j=345; j>40; j=j-10)
{
g.drawOval(j, i, 10, 10);
}
}
}
}
All those magic numbers make me cringe a bit. You're new to Java, and it's homework, so I understand why you're doing it, but I would not recommend it if you do much programming in the future.
You need an algorithm or recipe for deciding when a small circle on the inside falls outside the big one you're trying to pack. Think about the ways you might do this:
If the distance between the center of the big circle and the small circle is is greater than the difference in their radii, the small circle will overlap the big circle or fall completely outside it.
You can add this check to your code: Just before you draw the circle, perform this check. Only draw if that circle passes.
Don't worry about Java for a second; draw yourself a picture on a piece of paper, draw that enclosing and packed circle, and see if that statement is correct. Then think about any corner situations that it might not cover, just as a check.
I'll make two more recommendations. First, do this by hand without a computer once so you'll see what the "right" answer might look like. Second, see if you can separate the calculation of the circles from the drawing part. It might make your job easier, because you can concentrate on one thing at a time. It's called "decomposition". You solve complex problems by breaking them up into smaller, more manageable pieces. In this case, it's also called "model-view separation". You might need to know that someday.
Maybe another way to think about this problem would be to imagine a 2D arrangement of circles, packed in their closest arrangement, extending to infinity in both the x- and y-directions. Now take your enclosing circle, put it on top of the 2D arrangement, and eliminate all the circles that overlap the big circle. I don't know if it'll be optimal, but it's easy to visualize.