Related
How i want it to look like:
The circles move along with the arrow around the center circle.
How it is looking at the moment:
I want to draw a 2 lines between two circles. however these circles move all around the screen and i dont know a methodical way to draw lines between them. For example, I always have the top left corner of the two circles i want to draw a line between but thats it. I need help to draw a line in java that will adjust based on its position so that the lines move around the edge as the circles move
for (int z = 0; z < lines.size(); z++) {
if (lines.get(z).getfState().equals(states.get(a).getText()) && !lines.get(z).getfState().equals(lines.get(z).getnState())) {
transition.get(z).setIcon(null);
for (int x = 0; x < states.size(); x++) {
if (states.get(x).getText().equals(lines.get(z).getnState()) && states.get(a).getText().equals(lines.get(z).getfState())) {
int xbegin = (int) states.get(a).getBounds().getX();
int ybegin = (int) states.get(a).getBounds().getY();
int xend = (int) states.get(x).getBounds().getX();
int yend = (int) states.get(x).getBounds().getY();
if (xbegin > xend) {
Path2D.Double rect = new Path2D.Double(drawArrowLine(xbegin, ybegin, xend, yend, 10, 7));
OutlineIcon transit = new OutlineIcon(drawArrowLine(xbegin, ybegin, xend + 30, yend, 10, 7), Color.BLACK);
transition.get(z).setIcon(transit);
transition.get(z).setBounds(rect.getBounds().x, rect.getBounds().y, rect.getBounds().width + 20, rect.getBounds().height + 20);
jPanel2.revalidate();
jPanel2.repaint();
} else {
if (xend - xbegin < 75) {
xbegin = xbegin - 20;
xend = xend - 20;
}
xbegin = xbegin + 5;
ybegin = ybegin + 25;
xend = xend + 5;
yend = yend + 25;
Path2D.Double rect = new Path2D.Double(drawArrowLine(xbegin, ybegin, xend - 10, yend, 10, 7));
OutlineIcon transit = new OutlineIcon(drawArrowLine(xbegin, ybegin, xend - 10, yend, 10, 7), Color.BLACK);
transition.get(z).setIcon(transit);
transition.get(z).setBounds(rect.getBounds().x, rect.getBounds().y, rect.getBounds().width + 20, rect.getBounds().height + 20);
jPanel2.revalidate();
jPanel2.repaint();
}
}
}
} else if (lines.get(z).getnState().equals(states.get(a).getText()) && !lines.get(z).getfState().equals(lines.get(z).getnState())) {
transition.get(z).setIcon(null);
for (int x = 0; x < states.size(); x++) {
if (states.get(x).getText().equals(lines.get(z).getfState()) && states.get(a).getText().equals(lines.get(z).getnState())) {
int xend = (int) states.get(a).getBounds().getX();
int yend = (int) states.get(a).getBounds().getY();
int xbegin = (int) states.get(x).getBounds().getX();
int ybegin = (int) states.get(x).getBounds().getY();
if (xbegin > xend) {
Path2D.Double rect2 = new Path2D.Double(drawArrowLine(xbegin, ybegin, xend, yend, 10, 7));
OutlineIcon transit = new OutlineIcon(drawArrowLine(xbegin, ybegin, xend + 30, yend, 10, 7), Color.BLACK);
transition.get(z).setIcon(transit);
transition.get(z).setBounds(rect2.getBounds().x, rect2.getBounds().y, rect2.getBounds().width + 20, rect2.getBounds().height + 20);
jPanel2.revalidate();
jPanel2.repaint();
} else {
if (xend - xbegin < 75) {
xbegin = xbegin + 20;
xend = xend + 20;
}
xbegin = xbegin + 5;
ybegin = ybegin + 25;
xend = xend + 5;
yend = yend + 25;
Path2D.Double rect2 = new Path2D.Double(drawArrowLine(xbegin, ybegin, xend - 10, yend, 10, 7));
OutlineIcon transit = new OutlineIcon(drawArrowLine(xbegin, ybegin, xend - 10, yend, 10, 7), Color.BLACK);
transition.get(z).setIcon(transit);
transition.get(z).setBounds(rect2.getBounds().x, rect2.getBounds().y, rect2.getBounds().width + 20, rect2.getBounds().height + 20);
jPanel2.revalidate();
jPanel2.repaint();
}
}
}
public static Path2D.Double createArrowForLine(
int fromPointx,
int fromPointy,
double rotationDeg,
double length,
double wingsAngleDeg) {
double ax = fromPointx;
double ay = fromPointy;
double radB = Math.toRadians(-rotationDeg + wingsAngleDeg);
double radC = Math.toRadians(-rotationDeg - wingsAngleDeg);
Path2D resultPath = new Path2D.Double();
resultPath.moveTo(length * Math.cos(radB) + ax, length * Math.sin(radB) + ay);
resultPath.lineTo(ax, ay);
resultPath.lineTo(length * Math.cos(radC) + ax, length * Math.sin(radC) + ay);
return (Path2D.Double) resultPath;
}
Although there have been some hiccups in the question, and the code provided so far looks questionable, the core of the question as it stands now is quite interesting...
There are different options for solving this. From the images that you provided so far, it looks like the circles always have the same size, which makes things far simpler. For circles with different sizes, you'd really have to compute the tangents of the circles, in the desired direction, mutually considering the radius of the other circle. Of course, this is possible, but a bit less trivial.
For the case that you have equally-sized circles, you can
Compute the difference of the centers of two circles
Divide this by the distance, to obtain the (normalized) direction
Rotate this direction by 90°
Scale the rotated direction vector by the radius
Add the scaled and rotated vector to the circle center
This will yield one endpoint of such a line. The rotation about 90° can be done once in clockwise and once in counterclockwise direction, to obtain the "upper" and "lower" endpoint for the line, respectively.
Image was updated with the EDIT, see below
The actual computation is done in the computeLine method of the MCVE below. Note that this example uses the "simple" approach, although it uses circles of slightly different sizes. The effect is that, when the difference between the sizes of two circles is too large (compared to the distance between the circles, basically), then the lines may slightly intersect the circles. But the solution should be a reasonable trade-off between simplicity and general applicability. Particularly, for equally-sized circles, there will be no intersections at all.
Code was updated with the EDIT, see below
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.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LinesAtCirclesTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel linesAtCirclesTestPanel = new LinesAtCirclesTestPanel();
f.getContentPane().add(linesAtCirclesTestPanel);
f.setSize(400,400);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class LinesAtCirclesTestPanel extends JPanel
implements MouseListener, MouseMotionListener
{
private Point2D draggedCenter;
private List<Point2D> centers = new ArrayList<Point2D>();
private List<Double> radii = new ArrayList<Double>();
public LinesAtCirclesTestPanel()
{
addMouseListener(this);
addMouseMotionListener(this);
addCircle(100, 100, 30);
addCircle(200, 300, 50);
addCircle(300, 200, 40);
}
private void addCircle(double x, double y, double radius)
{
centers.add(new Point2D.Double(x,y));
radii.add(radius);
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (int i=0; i<centers.size(); i++)
{
Point2D center0 = centers.get(i);
double radius0 = radii.get(i);
Shape ellipse = new Ellipse2D.Double(
center0.getX() - radius0, center0.getY() - radius0,
radius0 + radius0, radius0 + radius0);
g.setColor(Color.LIGHT_GRAY);
g.fill(ellipse);
g.setColor(Color.BLACK);
g.draw(ellipse);
}
g.setColor(Color.RED);
for (int i=0; i<centers.size() - 1; i++)
{
Point2D center0 = centers.get(i);
double radius0 = radii.get(i);
Point2D center1 = centers.get(i+1);
double radius1 = radii.get(i+1);
g.draw(createArrow(computeLine(center0, radius0, center1, radius1, true)));
g.draw(createArrow(computeLine(center0, radius0, center1, radius1, false)));
}
}
private static Shape createArrow(Line2D line)
{
double dx = line.getX2() - line.getX1();
double dy = line.getY2() - line.getY1();
double angleToX = Math.atan2(dy, dx);
final double angleRad = Math.toRadians(30);
final double headLength = 20.0f;
double dxL = Math.cos(Math.PI + angleToX + angleRad) * headLength;
double dyL = Math.sin(Math.PI + angleToX + angleRad) * headLength;
double dxR = Math.cos(Math.PI + angleToX - angleRad) * headLength;
double dyR = Math.sin(Math.PI + angleToX - angleRad) * headLength;
Path2D arrow = new Path2D.Double();
arrow.moveTo(line.getX1(), line.getY1());
arrow.lineTo(line.getX2(), line.getY2());
arrow.lineTo(line.getX2() + dxL, line.getY2() + dyL);
arrow.moveTo(line.getX2(), line.getY2());
arrow.lineTo(line.getX2() + dxR, line.getY2() + dyR);
return arrow;
}
private static Line2D computeLine(
Point2D center0, double radius0,
Point2D center1, double radius1,
boolean upper)
{
double dx = center1.getX() - center0.getX();
double dy = center1.getY() - center0.getY();
double invLength = 1.0 / Math.hypot(dx, dy);
double dirX = dx * invLength;
double dirY = dy * invLength;
double rotDirX = dirY;
double rotDirY = -dirX;
if (upper)
{
rotDirX = -dirY;
rotDirY = dirX;
}
double x0 = center0.getX() + rotDirX * radius0;
double y0 = center0.getY() + rotDirY * radius0;
double x1 = center1.getX() + rotDirX * radius1;
double y1 = center1.getY() + rotDirY * radius1;
if (upper)
{
return new Line2D.Double(x1, y1, x0, y0);
}
return new Line2D.Double(x0, y0, x1, y1);
}
#Override
public void mousePressed(MouseEvent e)
{
draggedCenter = null;
for (int i=0; i<centers.size(); i++)
{
Point2D center = centers.get(i);
double radius = radii.get(i);
if (e.getPoint().distance(center) < radius)
{
draggedCenter = center;
}
}
}
#Override
public void mouseReleased(MouseEvent e)
{
draggedCenter = null;
}
#Override
public void mouseDragged(MouseEvent e)
{
if (draggedCenter == null)
{
return;
}
draggedCenter.setLocation(e.getPoint());
repaint();
}
#Override
public void mouseMoved(MouseEvent e)
{
// Not used
}
#Override
public void mouseClicked(MouseEvent e)
{
// Not used
}
#Override
public void mouseEntered(MouseEvent e)
{
// Not used
}
#Override
public void mouseExited(MouseEvent e)
{
// Not used
}
}
EDIT in response to the comment:
The original code computed Line2D objects. Creating an arrow from a line is, in the simplest case, basically done with a bit of trigonometry, and many resources exist for this on the web.
In response to the comment, I extended the example to show simple arrows, as depicted in the above image.
However, when taking a closer look at this, one may notice several degrees of freedom for such an arrow:
Should the head length be absolute or relative to the arrow?
Should the head width be absolute or relative to the arrow?
(Or: What should be the angle of the arrow head?)
Should the arrow head be filled, or consist of lines?
Should the "trunk" of the arrow be a single line, or an outline shape?
What should be the width of the trunk?
...
In order to cover some of these degrees of freedom, I created an ArrowCreator class a while ago, and there's also a sample showing how it may be used.
I have a problem with my JApplet and my whole point of using it was due to that Buffered Reader already exist in it by default.
So my program is going to move a ball, but it creates many different pictures in different locations as it's suppose to do but I don't know how to erase them afterwards. This is what it looks like:
Here is my code:
private Image img;
double bollx = 150, bolly = 690;
double dy = 30, dx = 30;
double x , y;
int diameter = 23;
int click = 0, varjeClick;
JPanel panel;
int yBounce = 0, xBounce = 0;
public void init(){
setSize(1900, 900);
panel = new JPanel();
panel.setLocation(50, 50);
panel.setSize(1800, 700);
//panel.setLayout(null);
panel.addMouseListener(this);
panel.setBackground(Color.white);
this.add(panel);
img = getImage(getCodeBase(), "basketboll.png");
}
public void start(){
Thread t = new Thread(this);
t.start();
}
public void paint(Graphics g){
//super.paintComponents(g);
g.drawImage(img, (int)bollx, (int)bolly, panel);
}
public void flyttaBoll(){
//om stilla eller inte
if(click == 0){
bollx = 150;
bolly = 690;
}
else{
gravity();
bollx += dx*0.02;
bolly += dy*0.02;
}
if(bollx >= (panel.getWidth() - diameter*2.2)){
bollx = panel.getWidth() - diameter*2.200000001;
dx *= -0.9 ;
}
if(bollx <= 0 + diameter){
bollx = diameter + 1;
dx *= -0.9 ;
}
if(bolly >= panel.getHeight() - diameter*2.2){
bolly = panel.getHeight() - diameter*2.200000001;
dy *= -0.7;
yBounce++;
if(yBounce >= 130){
click = 0;
yBounce = 0;
varjeClick = 0;
}
}
if(bolly <= 0 + diameter){
bolly = diameter + 1;
dy *= -0.7;
}
}
public void gravity(){
if(varjeClick <= 7){
dy += 9.82;
}
else{
dy -= 9.82;
}
}
public void run() {
while(true){
flyttaBoll();
repaint();
try{Thread.sleep(8);}catch(Exception e){}
}
}
public void mousePressed(MouseEvent e){
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
x = b.getX() - diameter/2;
y = b.getY() - diameter/2;
dx = x - bollx;
dy = y - bolly;
flyttaBoll();
}
I tried to take away some irrelevant code for less confusion and I am really sorry that I used Swedish but I hope you can see past that.
to start off, I'm making a simple game in Java that involves a blue rectangle that can be moved with arrow keys and seven falling circles of varying color, radius, and falling speed. Essentially, whenever the rectangle comes in contact with one of these circles, the rectangle will "lose" a life, which will be indicated by 3 rectangles on the top right of a JFrame that I haven't drawn yet. Every time the rectangle is hit by one of these circles, one of the rectangles will disappear, and when the blue rectangle is hit once more, a red "Game Over" text will appear in the middle of the frame.
Now then, although I'm having trouble getting the colors and speed to randomize each time the circles hit the bottom, I'll leave those for a future question. My main concern is the hit detection between the circles and the blue rectangle. I know that I need to define a certain method, but I'm unsure on how to go about doing it, and how to test it for each of the seven circles over and over while they're falling and having their Y value constantly change.
How could I go about doing this? Anyway, here's my main and circles classes for this project. I'm aware that there's a lot of junk code that isn't being used in the main class as well. I'll clean it up after I just figure this out.
**Main class (Keyexample)
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.Random;
public class Keyexample extends JPanel implements ActionListener, KeyListener{
Timer t = new Timer(5, this);
private Circle[] Circles = new Circle[7];
private javax.swing.Timer t2;
private Circle newc, c1, c2, c3, c4, c5, c6, c7;
double x = 100, y = 100;
double changeX = 0, changeY = 0;
private int cx = 10, cy = 0;
private int newcx = 0, newcy = 0;
private Random rand = new Random();
private Random colorc = new Random();
private int n = rand.nextInt(8);
public keyExample() {
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
Random colorc = new Random();
Random radiusc = new Random();
int r1 = radiusc.nextInt(12);
int r2 = radiusc.nextInt(12);
int r3 = radiusc.nextInt(12);
int r4 = radiusc.nextInt(12);
int r5 = radiusc.nextInt(12);
int r6 = radiusc.nextInt(12);
int r7 = radiusc.nextInt(12);
Color cc1 = new Color(colorc.nextInt(255), colorc.nextInt(255),
colorc.nextInt(255));
Color cc2 = new Color(colorc.nextInt(255), colorc.nextInt(255),
colorc.nextInt(255));
Color cc3 = new Color(colorc.nextInt(255), colorc.nextInt(255),
colorc.nextInt(255));
Color cc4 = new Color(colorc.nextInt(255), colorc.nextInt(255),
colorc.nextInt(255));
Color cc5 = new Color(colorc.nextInt(255), colorc.nextInt(255),
colorc.nextInt(255));
Color cc6 = new Color(colorc.nextInt(255), colorc.nextInt(255),
colorc.nextInt(255));
Color cc7 = new Color(colorc.nextInt(255), colorc.nextInt(255),
colorc.nextInt(255));
//creating the 7 circles and spacing them out
c1 = new Circle(cx, cy, r1, cc1);
c2 = new Circle(cx + 50, cy, r2, cc2);
c3 = new Circle(cx + 100, cy, r3, cc3);
c4 = new Circle(cx + 150, cy, r4, cc4);
c5 = new Circle(cx + 200, cy, r5, cc5);
c6 = new Circle(cx + 300, cy, r6, cc6);
c7 = new Circle(cx + 400, cy, r7, cc7);
Circles[0] = c1;
Circles[1] = c2;
Circles[2] = c3;
Circles[3] = c4;
Circles[4] = c5;
Circles[5] = c6;
Circles[6] = c7;
t2 = new javax.swing.Timer(33, new CircleListener());
t2.start();
}
//painting rectangle and circles
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.fill(new Rectangle2D.Double(x, y, 40, 40));
for (int i = 0; i < Circles.length; i++){
Color circlecolor = new Color(rand.nextInt(255), rand.nextInt(255),
rand.nextInt(255));
//circle color starts spazzing out here. constantly changing while falling
g2.setColor(circlecolor);
Circles[i].fill(g);
}
}
public void createCircle(){
}
public void actionPerformed(ActionEvent e) {
repaint();
x += changeX;
y += changeY;
changeX = 0;
changeY = 0;
}
private class CircleListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
Random rand = new Random();
int move = 2 + rand.nextInt(10);
int move2 =2 + rand.nextInt(10);
int move3 =2 + rand.nextInt(10);
int move4 =2 + rand.nextInt(10);
int move5 =2 + rand.nextInt(10);
int move6 =2 + rand.nextInt(10);
c1.move(0, n);
position(c1);
c2.move(0, move);
position(c2);
c3.move(0, move2);
position(c3);
c4.move(0, move3);
position(c4);
c5.move(0, move4);
position(c5);
c6.move(0, move5);
position(c6);
c7.move(0, move6);
position(c7);
repaint();
}
public void position(Circle cp) {
int height = getHeight();
int loc = cp.centerX;
int speed = 3 + rand.nextInt(10);
int radiuss = cp.radius;
Rectangle bound = cp.Bounds();
if (bound.topY + bound.width > height){
cp.centerY = 0;
//moving circle back to the top
cp.move(0, speed);
//randomizing speed of circle after moving to top, not working
cp.radius = 5 + rand.nextInt(20);
//randomizing radius of circle after moving to top, does work
}
}
}
public void up() {
if (y != 0){
changeY = -3.5;
changeX = 0;
}
}
public void down() {
if (y <= 350) {
changeY = 3.5;
changeX = 0;
}
}
public void left() {
if (x >=0) {
changeX = -3.5;
changeY = 0;
}
}
public void right() {
if (x <= 550) {
changeX = 3.5;
changeY = 0;
}
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
up();
}
if (code == KeyEvent.VK_DOWN) {
down();
}
if (code == KeyEvent.VK_RIGHT) {
right();
}
if (code == KeyEvent.VK_LEFT) {
left();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
**Circle class
import java.awt.*;
import java.util.Random;
public class Circle{
public int centerX, centerY, radius;
public Color color;
public Circle (int x, int y, int r, Color c){
centerX = x;
centerY = y;
radius = r;
Random random = new Random();
}
public void draw(Graphics g){
Color oldColor = g.getColor();
g.setColor(color);
g.drawOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.setColor(oldColor);
}
public void fill(Graphics g){
Color oldColor = g.getColor();
g.setColor(color);
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.setColor(oldColor);
}
public boolean containsPoint(int x, int y){
int xSquared = (x - centerX) * (x - centerX);
int ySquared = (y - centerY) * (y - centerY);
int radiusSquared = radius * radius;
return xSquared + ySquared - radiusSquared <=0;
}
public void move(int xAmount, int yAmount){
centerX = centerX + xAmount;
centerY = centerY + yAmount;
}
public Rectangle Bounds(){
int x = centerX - radius;
int y = centerY - radius;
return new Rectangle(x, y, radius * 2, radius * 2, Color.red);
}
}
You want to break the problem into two parts: the first - see if there is "definitely no collision". This happens when the center of the circle is more than a radius away from the edges. It's a very fast test, and will be true most of the time:
if(left > x + radius ||
right < x - radius ||
etc.) { // no collision }
The second - if you fail this test, you may still not hit. That depends on whether both x and y are sufficient for overlap. Within this, there are two situations:
A corner of the rectangle is inside the circle: easy to compute (distance from one corner to center of circle < r)
An edge is inside the circle. This means that in one direction (say X) the center lies between the edges; and in the other direction an edge is less than radius away.
This is general, without actual code. I assume you can write the code from here.
You can detect collisions by simple if else conditions on the circle's and rectangle's co ordinates on screen.
distance(circle, Rectangle) <= circle.radius + Rectangle.radius
You can implement distance helper function using the simple distance formula between two points.
link
I am basically coding this basic arcade game and i need the circle to shoot out small rectangles that looks like bullets or missiles to hit the bad guys whenever the space bar is hit but i cant figure out how.
Heres my code so far:
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class main extends Applet implements Runnable, KeyListener {
private Image i;
private Graphics doubleG;
// x and y are used to set (x,y) positions
// dx and dy are the changes in position
private int x = 850;
private int y = 850;
private int x2 = 100;
private int y2 = 100;
private int dx = 50;
private int radius = 30;
private int dx2 = 4;
private int dy2 = 4;
private int x3 = 100;
private int y3 = 200;
private int dx3 = 5;
private int dy3 = 5;
private int x4 = 100;
private int y4 = 300;
private int dx4 = 3;
private int dy4 = 3;
public void init(){
setSize(1920,1080);
setBackground(Color.black);
addKeyListener(this);
}
public void start(){
Thread thread = new Thread(this);
thread.start();
}
public void run() {
while(true){
//Enemy
if(x2 + dx2 > this.getWidth() - radius - 1){
x2 = this.getWidth() - radius - 1;
dx2 = -dx2;
}
if(x2 + dx2 < 0 + radius){
x2 = 0 + radius;
dx2 = -dx2;
}
x2 += dx2;
// Enemy
if(x3 + dx3 > this.getWidth() - radius - 1){
x3 = this.getWidth() - radius -1;
dx3 = -dx3;
}
if(x3 + dx3 < 0 + radius){
x = 0 + radius;
dx3 = -dx3;
}
x3 += dx3;
// Enemy
if(x4 + dx4 > this.getWidth() - radius - 1){
x4= this.getWidth() - radius -1;
dx4 = -dx4;
}
if(x4 + dx4 < 0 + radius){
x4 = 0 + radius;
dx4 = -dx4;
}
x4 += dx4;
// EVERYTHING ABOVE KEEPS ASTEROIDS IN THE SCREEN ALLOWING IT TO BOUNCE OFF WALLS
repaint();
try{
Thread.sleep(17);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
public void stop(){
}
public void update(Graphics g){
// this function stops the flickering problem every time the ball moves by copying the image instead of repainting it
if(i == null){
i = createImage(this.getSize().width, this.getSize().height);
doubleG = i.getGraphics();
}
doubleG.setColor(getBackground());
doubleG.fillRect(0,0,this.getSize().width, this.getSize().height);
doubleG.setColor(getForeground());
paint(doubleG);
g.drawImage(i,0,0,this);
}
public void paint(Graphics g){
g.setColor(Color.BLUE);
g.fillOval(x, y, radius*2, radius*2);
g.setColor(Color.RED);
g.fillOval(x2, y2, radius + 10, radius + 10);
g.setColor(Color.RED);
g.fillOval(x3,y3, radius + 10, radius + 10);
g.setColor(Color.RED);
g.fillOval(x4, y4, radius + 10, radius + 10);
}
public void moveRight(){
if (dx-1 > -20){
dx += 1;
}
if(x + dx > this.getWidth() - radius - 1){
x = this.getWidth() - radius - 1;
dx = -dx;
}
x += dx;
}
public void moveLeft(){
if(dx - 1 > -20){
dx -= 1;
}
if(x + dx < 0 + radius){
x = 0 + radius;
dx = -dx;
}
x -= dx;
}
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
switch(e.getKeyCode()){
case KeyEvent.VK_LEFT:
moveLeft();
break;
case KeyEvent.VK_RIGHT:
moveRight();
break;
}
}
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
KeyListener will only raise KeyEvents if the component it is registered to is focusable AND has foucs.
You never call super.paint, expect some serious paint artifacts
Avoid overriding paint of top level containers (like Applet)
Consider using Swing based components over AWT, apart from been more update to date and more widely used, Swing components are also double buffered by default. Use a combination of JApplet and JPanel as the main drawing surface, overriding it's paintComponent method. In this case, also consider using a javax.swing.Timer over Thread, unless you want to try and maintain a variable delay between updates. This would also allow you to use the key bindings API overcoming the focus issues related to KeyListener
EDIT: updated code and question
I added main() method as stated in aswers but I still can't export it.
I am running my program as Java Applet, and apparently I need to use Java Application to run it standalone, but when I change run configuration to Application i get these errors:
Exception in thread "main" java.lang.NullPointerException
at acm.graphics.GImage.determineSize(GImage.java:564)
at acm.graphics.GImage.setImage(GImage.java:173)
at acm.graphics.GImage.<init>(GImage.java:115)
at acm.graphics.GImage.<init>(GImage.java:54)
at Pong.createTexture(Pong.java:160)
at Pong.run(Pong.java:81)
at Pong.main(Pong.java:55)
I need to export my project from Eclipse as a standalone runnable JAR, but when i go to export -> java -> JAR file i dont see any classes to select and im getting stuck at this (screen) window. I only have one class in my project.
This is not relevant anymore but I'll leave it here to keep edit history
import java.awt.Color;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.util.Random;
import acm.graphics.GImage;
import acm.graphics.GLabel;
import acm.graphics.GObject;
import acm.graphics.GOval;
import acm.graphics.GRect;
import acm.program.GraphicsProgram;
/* TO DO LIST
* ------------------
* Corner Bounce
*
*
*
*/
#SuppressWarnings("serial")
public class Pong extends GraphicsProgram {
public double mouseY;
private static final double PAUSE = 1000 / 96.0;
private Random rand = new Random();
private boolean AI_GODMODE = false;
// ball
public double startX;
public double startY;
private static final double BALL_SIZE = 20;
private static final double SPEED = 5;
private double ballHorizontalSpeed = SPEED * 1.5;
private double ballVerticalSpeed = SPEED;
// paddle
private static int HEIGHT = 150;
private static int WIDTH = 15;
private static int COUNTER = 0;
private static int AI_SPEED = 10; // AI difficulty 1-20
// label
public int AI_SCORE = 0;
public int PLAYER_SCORE = 0;
public int TOTAL_GAMES = 0;
private float TRANSPARENCY = 0.0f;
// counters
private static final int PADDING = 10;
private static final int MODIFIER = 3;
public static void main(String[] args) {
Pong p = new Pong();
p.run();
}
public void run() {
addMouseListeners();
// counters setup
GLabel counter = new GLabel(String.valueOf(COUNTER));
GLabel aiScore = new GLabel(String.valueOf(AI_SCORE));
GLabel average = new GLabel(String.valueOf("Avg: 0"));
GLabel playerScore = new GLabel(String.valueOf(COUNTER));
Color labelC = new Color(0, 0.0f, 0.0f, TRANSPARENCY);
Color scoreC = new Color(0, 0.0f, 0.0f, 0.1f);
counter.setFont("Impact-600");
aiScore.setFont("Impact-100");
average.setFont("Impact-50");
playerScore.setFont("Impact-100");
counter.setColor(labelC);
aiScore.setColor(scoreC);
playerScore.setColor(scoreC);
average.setColor(scoreC);
counter.setLocation(getWidth() / 2 - counter.getWidth() / 2,
getHeight() / 2 + counter.getHeight() / 3.2);
counter.sendToFront();
// make objects
GImage paddleLeftTexture = createTexture("texture.png", WIDTH + 1,
HEIGHT + 1);
GImage paddleRightTexture = createTexture("texture2.png", WIDTH + 1,
HEIGHT + 1);
GImage ballTexture = createTexture("ballTexture.png", (int) BALL_SIZE,
(int) BALL_SIZE);
GImage greenFlash = createTexture("greenFlash.png", 100, 300);
GImage blueFlash = createTexture("blueFlash.png", 100, 300);
GOval ball = makeBall();
GRect paddleLeft = makePaddle();
GRect paddleRight = makePaddle();
greenFlash.setLocation(-200, 0);
blueFlash.setLocation(-200, 0);
// generate GUI
drawGraphics(ball, paddleLeftTexture, paddleRightTexture, ballTexture,
greenFlash, blueFlash, counter, paddleLeft, paddleRight,
aiScore, playerScore, average);
// game start
bounce(labelC, aiScore, playerScore, counter, ball, paddleLeft,
paddleRight, paddleLeftTexture, paddleRightTexture,
ballTexture, greenFlash, blueFlash, average);
}
public void bounce(Color labelC, GLabel aiScore, GLabel playerScore,
GLabel counter, GOval ball, GRect paddleLeft, GRect paddleRight,
GImage paddleLeftTexture, GImage paddleRightTexture,
GImage ballTexture, GImage greenFlash, GImage blueFlash,
GLabel average) {
preGameSetup(ball, paddleRight, paddleRightTexture, counter);
updateAiScore(aiScore);
updatePlayerScore(playerScore);
updateAverage(average);
while (true) {
moveBall(ballHorizontalSpeed, ballVerticalSpeed, ball, ballTexture);
movePlayerPaddle(paddleLeft, paddleLeftTexture);
moveAiPaddle(ball, paddleRight, paddleRightTexture);
detectHit(ball, paddleRight, paddleLeft, counter, labelC);
if (TRANSPARENCY >= 0.0f) {
TRANSPARENCY -= TRANSPARENCY / 100f;
}
labelC = new Color(0, 0.0f, 0.0f, TRANSPARENCY);
counter.setColor(labelC);
if (detectBallOffScreen(ball)) {
ballOffScreen(ball, ballTexture, aiScore, playerScore,
greenFlash, blueFlash, average);
COUNTER = 0;
bounce(labelC, aiScore, playerScore, counter, ball, paddleLeft,
paddleRight, paddleLeftTexture, paddleRightTexture,
ballTexture, greenFlash, blueFlash, average);
}
pause(PAUSE);
}
}
public static GRect makePaddle() {
GRect result = new GRect(0, 0, WIDTH, HEIGHT);
result.setFilled(true);
result.setColor(Color.BLACK);
return result;
}
public static GOval makeBall() {
GOval result = new GOval(150, 100, BALL_SIZE, BALL_SIZE);
result.setFilled(true);
result.setColor(Color.WHITE);
return result;
}
private GImage createTexture(String importedImage, int width, int height) {
Image importResult = getImage(getCodeBase(), importedImage);
GImage textureResult = new GImage(importResult);
textureResult.setSize(width, height);
return textureResult;
}
public void mouseMoved(MouseEvent e) {
mouseY = e.getY();
}
private boolean ballHitBottom(GOval ball) {
double bottomY = ball.getY() + ball.getHeight();
return bottomY >= getHeight();
}
private boolean ballHitTop(GOval ball) {
double topY = ball.getY();
return topY <= 0;
}
private boolean ballHitPaddleRight(GOval ball, GRect paddle) {
double rightX = ball.getX() + ball.getWidth();
double rightY = ball.getY() + ball.getHeight() / 2;
double paddlePosX = paddle.getX();
double paddlePosY = paddle.getY();
if (rightX >= paddlePosX && rightY >= paddlePosY
&& rightY <= paddlePosY + paddle.getHeight())
return true;
else
return false;
}
private boolean detectBallOffScreen(GOval ball) {
if (ball.getX() < 2 * WIDTH - BALL_SIZE
|| ball.getX() > getWidth() - 2 * WIDTH)
return true;
else
return false;
}
private boolean ballHitPaddleLeft(GOval ball, GRect paddle) {
double leftX = ball.getX();
double leftY = ball.getY();
double paddlePosX = paddle.getX() + WIDTH;
double paddlePosY = paddle.getY();
if (leftX <= paddlePosX && leftY >= paddlePosY
&& leftY <= paddlePosY + paddle.getHeight())
return true;
else
return false;
}
/*
* private boolean ballHitPaddleBorder(GOval ball, GRect paddle) { ; if
* (ball.getX() > paddle.getX() - BALL_SIZE && ball.getX() < paddle.getX() +
* WIDTH && ball.getY() > paddle.getY() && ball.getY() < paddle.getY() +
* ballVerticalSpeed) return true; else if (ball.getX() > paddle.getX() -
* BALL_SIZE && ball.getX() < paddle.getX() + WIDTH && ball.getY() >
* paddle.getY() + HEIGHT && ball.getY() < paddle.getY() + HEIGHT -
* ballVerticalSpeed) return true; else return false; }
*/
private void preGameSetup(GObject ball, GObject paddleRight,
GObject paddleRightTexture, GLabel counter) {
startX = rand.nextInt((int) (getWidth() * 0.8))
+ (int) (0.1 * getWidth()); // zapobiega pojawieniu się piłki po
// lewej stronie lewej paletki
startY = rand.nextInt(getHeight());
ball.setLocation(startX, startY);
paddleRightTexture.setLocation(getWidth() - MODIFIER * WIDTH, startY
- HEIGHT / 2);
paddleRight.setLocation(getWidth() - MODIFIER * WIDTH, startY - HEIGHT
/ 2);
paddleRightTexture.sendToFront();
counter.setLabel(String.valueOf(COUNTER));
counter.setLocation(getWidth() / 2 - counter.getWidth() / 2,
getHeight() / 2 + counter.getHeight() / 3.2);
ballHorizontalSpeed = SPEED * 1.5;
ballVerticalSpeed = SPEED;
}
private void updateAiScore(GLabel aiScore) {
aiScore.setLabel(String.valueOf(AI_SCORE));
aiScore.setLocation(getWidth() - aiScore.getWidth() - MODIFIER * WIDTH
- PADDING, getHeight() - PADDING);
}
private void updatePlayerScore(GLabel playerScore) {
playerScore.setLabel(String.valueOf(PLAYER_SCORE));
playerScore.setLocation(MODIFIER * WIDTH + PADDING, getHeight()
- PADDING);
}
private void updateScore(GLabel counter, Color labelC) {
counter.setLabel(String.valueOf(COUNTER));
counter.setLocation(getWidth() / 2 - counter.getWidth() / 2,
getHeight() / 2 + counter.getHeight() / 3.2);
TRANSPARENCY = 0.1f;
labelC = new Color(0, 0.0f, 0.0f, TRANSPARENCY);
counter.setColor(labelC);
}
private void updateAverage(GLabel average) {
if (TOTAL_GAMES == 0) {
average.setLabel("Round: 1 Avg: 0");
} else {
average.setLabel("Round: " + String.valueOf(TOTAL_GAMES + 1) + " Avg: "
+ String.valueOf((int) ((AI_SCORE + PLAYER_SCORE) / TOTAL_GAMES)));}
average.setLocation(getWidth() / 2 - average.getWidth() / 2,
getHeight() - PADDING);
}
private void drawGraphics(GObject ball, GObject paddleLeftTexture,
GObject paddleRightTexture, GObject ballTexture,
GObject greenFlash, GObject blueFlash, GObject counter,
GObject paddleLeft, GObject paddleRight, GObject aiScore,
GObject playerScore, GLabel average) {
add(ball);
add(paddleLeftTexture);
add(paddleRightTexture);
add(ballTexture);
add(greenFlash);
add(blueFlash);
add(counter);
add(paddleLeft);
add(paddleRight);
add(aiScore);
add(playerScore);
add(average);
}
private void detectHit(GOval ball, GRect paddleRight, GRect paddleLeft,
GLabel counter, Color labelC) {
if (ballHitBottom(ball) && ballVerticalSpeed >= 0) {
ballVerticalSpeed *= -1;
}
if (ballHitTop(ball) && ballVerticalSpeed <= 0) {
ballVerticalSpeed *= -1;
}
if (ballHitPaddleRight(ball, paddleRight)) {
ballHorizontalSpeed *= -1;
}
if (ballHitPaddleLeft(ball, paddleLeft)) {
ballHorizontalSpeed *= -1;
COUNTER++;
updateScore(counter, labelC);
boolean bool = rand.nextBoolean();
if (bool)
if (ballHorizontalSpeed > 0)
ballHorizontalSpeed += 1;
else
ballHorizontalSpeed -= 1;
else if (ballVerticalSpeed > 0)
ballVerticalSpeed += 0.5;
else
ballVerticalSpeed -= 0.5;
}
/*
* if(ballHitPaddleBorder(ball, paddleLeft)){ ballVerticalSpeed *= -1; }
*
* if(ballHitPaddleBorder(ball, paddleRight)){ ballVerticalSpeed *= -1;
* }
*/
}
private void ballOffScreen(GOval ball, GObject ballTexture, GLabel aiScore,
GLabel playerScore, GObject greenFlash, GObject blueFlash,
GLabel average) {
if (ball.getX() < 2 * WIDTH - BALL_SIZE) { // left
double pos = ball.getY() - greenFlash.getHeight() / 2;
ballTexture.move(-ballTexture.getWidth() * 2, 0);
AI_SCORE += COUNTER;
TOTAL_GAMES++;
updateAiScore(aiScore);
updateAverage(average);
for (int i = 20; i < 100; i += 5) {
greenFlash.setLocation(-i, pos);
pause(25);
}
} else { // right
double pos = ball.getY() - blueFlash.getHeight() / 2;
ballTexture.move(ballTexture.getWidth() * 2, 0);
PLAYER_SCORE += COUNTER;
TOTAL_GAMES++;
updatePlayerScore(playerScore);
updateAverage(average);
for (int i = 20; i < 100; i += 5) {
blueFlash.setLocation(getWidth() - blueFlash.getWidth() + i,
pos);
pause(25);
}
}
}
private void moveBall(double ballHorizontalSpeed, double ballVerticalSpeed,
GObject ball, GObject ballTexture) {
ball.move(ballHorizontalSpeed, ballVerticalSpeed);
ballTexture.setLocation(ball.getX(), ball.getY());
ballTexture.sendToFront();
}
private void movePlayerPaddle(GObject paddleLeft, GObject paddleLeftTexture) {
if (mouseY < getHeight() - HEIGHT) { // Player
paddleLeft.setLocation(2 * WIDTH, mouseY);
paddleLeftTexture.setLocation(2 * WIDTH, mouseY);
paddleLeftTexture.sendToFront();
} else {
paddleLeft.setLocation(2 * WIDTH, getHeight() - HEIGHT);
paddleLeftTexture.setLocation(2 * WIDTH, getHeight() - HEIGHT);
paddleLeftTexture.sendToFront();
}
}
private void moveAiPaddle(GOval ball, GRect paddleRight,
GImage paddleRightTexture) {
if (AI_GODMODE == true) { // modeSelector
if (ball.getY() < getHeight() - HEIGHT / 2
&& ball.getY() > HEIGHT / 2) {
paddleRight.setLocation(getWidth() - MODIFIER * WIDTH,
ball.getY() - HEIGHT / 2);
paddleRightTexture.setLocation(getWidth() - MODIFIER * WIDTH,
ball.getY() - HEIGHT / 2);
paddleRightTexture.sendToFront();
} else if (ball.getY() <= HEIGHT / 2) {
paddleRight.setLocation(getWidth() - MODIFIER * WIDTH, 0);
paddleRightTexture.setLocation(getWidth() - MODIFIER * WIDTH,
-0);
paddleRightTexture.sendToFront();
} else {
paddleRight.setLocation(getWidth() - MODIFIER * WIDTH,
getHeight() - HEIGHT);
paddleRightTexture.setLocation(getWidth() - MODIFIER * WIDTH,
getHeight() - HEIGHT);
paddleRightTexture.sendToFront();
}
} else { // end godMode if
double targetY = ball.getY() + BALL_SIZE / 2;
if (targetY < getHeight() - HEIGHT / 2 && targetY > HEIGHT / 2) {
if (targetY < paddleRight.getY() + HEIGHT / 2) {
paddleRight.move(0, -AI_SPEED);
paddleRightTexture.move(0, -AI_SPEED);
} else if (targetY > paddleRight.getY() + HEIGHT / 2) {
paddleRight.move(0, AI_SPEED);
paddleRightTexture.move(0, AI_SPEED);
}
} // end normalMode if
} // end modeSelector if
} // end moveAiPaddle void
} // end class
Judging from the linked image, your class Pong does not have a main method. It simply cant be exported as a runnable jar file, because you could never run it. Add a main method, or export to a standard java jar file (File -> Export -> Java -> JAR file). The jar file it produces using the latter method will NOT be runnable if there is no main method, period. You have to have a main method in order to run this code stand alone, because that is the entry point for the application.
Per your comment, You will need to create an instance of the Pong class inside of the main method and invoke its run() method:
public static void main(String[] args) {
Pong p = new Pong();
p.run();
}
If the run method of the Pong class is static, you wont need an instance, and you could do this:
public static void main(String[] args) {
Pong.run();
}
You should be exporting it as a "Runnable JAR file" instead of a "JAR file". Once you choose this you should be able to use a drop down menu called "Launch configuration:", and then you can choose your export destination.
I am using Eclipse Kepler. It may not be the same for different versions.
Your project should contain class with main method so that you can see your project in Launch Configuration drop down list. (Eclipse Kepler)