I am working on an assignment and I'm almost done, however, there is a bullet that tells me to draw a line between the adjacent components to approximate the distance between them. I searched for the answer everywhere, and none of them worked.
Here's the code, I cut out the unimportant things, thanks in advance!
//IMPORTS
public class AssignLIRRBranches implements Runnable
{
static final String title = "LIRR Map";
static final String RK = "Ronkonkoma";
static final String MONTAUK = "Montauk";
static final String PJ = "Port_Jefferson";
static int width = 1200;
static int height = 600;
static int mapwidth = width-100;
static int mapheight = height-50;
double scalingFactorx;
double scalingFactory;
double scalingFactor;
double drawingX;
double drawingY;
double drawingY2;
MapPanel mapPanel = new MapPanel(new Font("Arial", Font.ITALIC, 12), false, Color.black, "kek", 12, 12, 12, 12);
JFrame application;
BoxLayout boxLayout;
Station station;
List<Station> stations = new ArrayList<Station>();
String[] larray;
JComboBox jbc;
public void run()
{
/* build the GUI */
application = new JFrame();
jbc = new JComboBox();
jbc.addItem(RK);
jbc.addItem(MONTAUK);
jbc.addItem(PJ);
boxLayout = new BoxLayout(application.getContentPane(), BoxLayout.Y_AXIS);
jbc.setMaximumSize(new Dimension(150, 15));
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.setTitle(title);
application.setSize(width, height);
application.setLayout(boxLayout);
mapPanel.setPreferredSize(new Dimension(mapwidth, mapheight));
application.add(mapPanel);
application.add(jbc);
application.setMinimumSize(application.getSize());
application.pack();
application.setMinimumSize(null);
application.setVisible(true);
}
void readStations(String path) throws FileNotFoundException, IOException {
/* read all stations */
try{ BufferedReader br = new BufferedReader(new FileReader(path));
String l;
while((l = br.readLine()) != null) {
larray = l.split(" ");
if(larray[2].equals(RK) || larray[2].equals(MONTAUK) || larray[2].equals(PJ)) {
/* construct and save Station instances */
station = new Station(Integer.parseInt(larray[0]), larray[1], larray[2], Double.parseDouble(larray[4]), Double.parseDouble(larray[5]));
stations.add(station);
}
}
} catch(NumberFormatException exc) {
System.out.println(exc);
}
}
public static void main(String[] args) throws FileNotFoundException, IOException {
String path = "lirr_sta_alpha.txt";
AssignLIRRBranches ars = new AssignLIRRBranches();
ars.readStations(path);
SwingUtilities.invokeLater(ars);
}
class Station {
int id = 0;
String NAME = " ";
String BRANCH = " ";
double latitude;
double longitude;
Station(int id, String NAME, String BRANCH, double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
this.NAME = NAME;
this.BRANCH = BRANCH;
this.id = id;
}
//GETTERS AND SETTERS
}
class MapPanel extends JPanel implements ComponentListener {
Font mapFont;
boolean resized = false;
Color mapColor = Color.black;
String currentBranch;
double minLong, minLat, maxLong, maxLat;
MapPanel(Font mapFont, boolean resized, Color mapColor, String currentBranch, double minLong, double minLat, double maxLong, double maxLat) {
/* construct the MapPanel */
this.mapFont = mapFont;
this.resized = resized;
this.mapColor = mapColor;
this.currentBranch = currentBranch;
this.minLong = minLong;
this.minLat = minLat;
this.maxLong = maxLong;
this.maxLat = maxLat;
}
void extents() {
minLong = Double.MAX_VALUE;
minLat = Double.MAX_VALUE;
maxLong = -Double.MIN_VALUE;
maxLat = -Double.MIN_VALUE;
for(Station station : stations){
/* calculate minimum and maximum longitude and latitude for staions of the current branch */
if(station.getBranch().equals(jbc.getSelectedItem())) {
if(station.getLatitude()>maxLat){
maxLat = station.getLatitude();
maxLong = station.getLongitude();
}
if(station.getLatitude()<minLat){
minLat = station.getLatitude();
minLong = station.getLongitude();
}
}
}
}
public void paint(Graphics gr) {
Graphics2D g2 = (Graphics2D)gr;
if (null == mapFont) {
}
/* get the desired font and calulate margin values */
else
/* set the current font */
if (resized) {
/* rescale, taking into account margins */
}
/* set the color */
gr.setColor(mapColor);
/* iterate through the stations */
for (int i = 0; i < stations.size(); i++) {
if(stations.get(i).getBranch().equals(jbc.getSelectedItem())) {
//System.out.println(jbc.getSelectedItem());
/* calculate the corrdinates and draw the station name */
extents();
scalingFactorx = mapwidth/(maxLat - minLat);
scalingFactory = mapheight/(maxLong - minLong);
scalingFactor = Math.min(scalingFactorx, scalingFactory);
drawingX = (stations.get(i).getLatitude() - minLat) * scalingFactorx/1.1;
drawingY = (stations.get(i).getLongitude() - minLong) * scalingFactory/1.1;
drawingY2 = mapheight - drawingY;
gr.drawString(stations.get(i).getName(), (int)drawingX, (int)drawingY2-25);
//THIS IS WHERE I WANT TO DRAW A LINE
//gr.drawLine(I already tried using a ListIterator, it didn't work, tried getting the next element and it's values, didn't work, what can I do?);
}
}
mapPanel.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
mapwidth = application.getWidth()-150;
mapheight = application.getHeight()-75;
application.repaint();
}
});
jbc.addActionListener (new ActionListener () {
public void actionPerformed(ActionEvent e) {
application.repaint();
}
});
}
}
}
Related
I am coding a little Asteroids game, but it seems to be lagging a little bit. I am using a swing.Timer in order to update my JFrame and display the graphics. I have two questions,
the first one being:
"Could the timer be the reason for the lags?" and the second one being:
"Is using a Timer the optimal way to handle game programming in Java, or is it not?"
When browsing the net, it seemed like everyone is using a Timer in order to handle animations, but I can't help but feel that it is a suboptimal way of doing this. Can someone pls explain this to me? Thank you in advance :)
Here is the code of my Timer, if it helps. First the Base class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Base implements ActionListener {
// Attributes
protected static int cd = 3; // Length of Countdown in seconds
private int nrOfAsteroids = 10; // Amount of Asteroids spawned
protected static int fps = 60; // Frames-per-second
// Various variables and constants
protected static BufferedImage image;
protected static int height;
protected static int width;
protected static boolean colorMode = false;
// Variables needed for Key-register
protected static boolean isWpressed = false;
private boolean isQpressed = false;
private boolean isEpressed = false;
private boolean isSpacePressed = false;
private boolean stop = false; // TODO remove after game is finished
// Various complex-objects
private static Base b = new Base();
private Asteroid[] a = new Asteroid[nrOfAsteroids];
private JFrame frame;
private JButton start;
private JButton colorButton;
private JLabel dummy;
private JLabel gameLabel;
protected static JLabel screen = new JLabel();
private ImageIcon icon;
private Timer t;
private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public static void main(String[] args) {
height = (int) (screenSize.height * 0.9);
width = (int) (screenSize.width * 0.9);
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
screen.setSize(width, height);
b.frameSetup();
} // end main
private void frameSetup() {
// Frame Setup
frame = new JFrame("yaaasssss hemorrhoids");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.BLACK);
frame.setBounds((int) (screenSize.width * 0.05), (int) (screenSize.height * 0.03), width, height);
frame.setLayout(new GridBagLayout());
// creating a "color" button
colorButton = new JButton("CLASSIC");
GridBagConstraints cb = new GridBagConstraints();
cb.weightx = 1;
cb.weighty = 1;
cb.gridx = 2;
cb.gridy = 0;
cb.anchor = GridBagConstraints.FIRST_LINE_END;
cb.insets = new Insets(10, 0, 0, 10);
colorButton.setPreferredSize(new Dimension(100, 30));
frame.add(colorButton, cb);
// creating a "ASTEROIDS" Label
gameLabel = new JLabel("ASSTEROIDS");
GridBagConstraints gl = new GridBagConstraints();
gl.weightx = 1;
gl.weighty = 1;
gl.gridwidth = 3;
gl.gridx = 0;
gl.gridy = 1;
gl.anchor = GridBagConstraints.CENTER;
gl.fill = GridBagConstraints.BOTH;
gameLabel.setPreferredSize(new Dimension(100, 30));
gameLabel.setFont(gameLabel.getFont().deriveFont(60.0f));
gameLabel.setForeground(Color.WHITE);
gameLabel.setHorizontalAlignment(SwingConstants.CENTER);
frame.add(gameLabel, gl);
// Dummy Component
dummy = new JLabel();
GridBagConstraints dc = new GridBagConstraints();
dummy.setPreferredSize(new Dimension(100, 30));
dc.weightx = 1;
dc.weighty = 1;
dc.gridx = 0;
dc.gridy = 0;
frame.add(dummy, dc);
// creating a "start" button
start = new JButton("START");
GridBagConstraints sb = new GridBagConstraints();
sb.weightx = 1;
sb.weighty = 1;
sb.gridx = 1;
sb.gridy = 2;
sb.anchor = GridBagConstraints.PAGE_START;
sb.insets = new Insets(15, 0, 0, 0);
start.setPreferredSize(new Dimension(100, 30));
frame.add(start, sb);
// Implementing a function to the buttons
start.addActionListener(this);
colorButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (colorButton.getText() == "CLASSIC") {
colorMode = true;
colorButton.setText("LSD-TRIP");
} else {
colorMode = false;
colorButton.setText("CLASSIC");
}
}
});
// Show Results
frame.setVisible(true);
}
private void addImage() {
// Implementing the Image
icon = new ImageIcon(image);
screen.setIcon(icon);
frame.add(screen);
}
protected void setWindowSize() {
width = frame.getBounds().width;
height = frame.getBounds().height;
screen.setSize(width, height);
}
#Override
public void actionPerformed(ActionEvent ae) {
// Cleaning the screen
frame.remove(start);
frame.remove(gameLabel);
frame.remove(colorButton);
frame.remove(dummy);
// Checking if Window has been resized, and acting according to it
setWindowSize();
// Creating the image
for (int i = 0; i < nrOfAsteroids; ++i) {
a[i] = new Asteroid();
}
gameStart();
}
private void gameStart() {
t = new Timer(1000/fps, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clearScreen();
for (int i = 0; i < nrOfAsteroids; ++i) {
a[i].drawAsteroid();
}
// Managing Controlls
if (isWpressed) {}
if (isQpressed) { }
if (isEpressed) { }
if (isSpacePressed) { }
if (stop) { }
// Updating the screen
b.addImage();
}
});
t.setInitialDelay(0);
actions();
t.start();
}
private void actions() {
// Defining all the constants for more order when handling the actions
final int focus = JComponent.WHEN_IN_FOCUSED_WINDOW;
String move = "Movement started";
String noMove = "Movement stopped";
String shoot = "Shooting started";
String noShoot = "Shooting stopped";
String turnLeft = "Rotation left started";
String noTurnLeft = "Rotation left stopped";
String turnRight = "Rotation right started";
String noTurnRight = "Rotation right stopped";
String stopIt = "stop"; // TODO remove when game is finished
// Getting the input and trigger an ActionMap
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("W"), move);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released W"), noMove);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("SPACE"), shoot);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released SPACE"), noShoot);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("Q"), turnLeft);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released Q"), noTurnLeft);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("E"), turnRight);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released E"), noTurnRight);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("S"), stopIt);
// Triggered ActionMaps perform an Action
screen.getActionMap().put(move, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isWpressed = true;
} });
screen.getActionMap().put(noMove, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isWpressed = false;
} });
screen.getActionMap().put(shoot, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isSpacePressed = true;
} });
screen.getActionMap().put(noShoot, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isSpacePressed = false;
} });
screen.getActionMap().put(turnLeft, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isQpressed = true;
} });
screen.getActionMap().put(noTurnLeft, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isQpressed = false;
} });
screen.getActionMap().put(turnRight, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isEpressed = true;
} });
screen.getActionMap().put(noTurnRight, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isEpressed = false;
} });
screen.getActionMap().put(stopIt, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
stop = true;
} });
} // end actions()
private void clearScreen() {
Graphics2D pen = image.createGraphics();
pen.clearRect(0, 0, Base.width, Base.height);
}
} // end class
Now the Asteroid class:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Polygon;
public class Asteroid {
// Attributes
private int amountOfCornerPoints = 12;
private int size = 50;
private int rotationSpeed = 2;
private int movementSpeed = 3;
// Fields needed to construct the Asteroid
private Polygon asteroidShape;
private int xCenter = (int) (Math.random() * Base.width);
private int yCenter = (int) (Math.random() * Base.height);
private int[] y = new int[amountOfCornerPoints];
private int[] x = new int[amountOfCornerPoints];
private int[] random = new int[amountOfCornerPoints];
private int rmax = 20; //Das Maximum für r
private int rmin = -rmax; //Das Minimum für r
// Field needed to transport the Asteroid
private boolean transporting = false;
// Field needed to rotate the Asteroid
private int cornerAddition = 0;
// Fields needed to detect Collision
// Fields needed to determine the direction of the Asteroid
private int direction = (int) Math.round((Math.random()*7));
private int xMove = 0;
private int yMove = 0;
// Fields for determining the color of the Asteroid
private Color col;
private int red = 255;
private int green = 255;
private int blue = 255;
public Asteroid() {
// Activating colorMode
if (Base.colorMode == true) {
do {
red = (int) Math.round((Math.random()*127));
green = (int) Math.round((Math.random()*127));
blue = (int) Math.round((Math.random()*127));
} while (red < 64 && green < 64 && blue < 64); }
col = new Color(red, green, blue);
// Zufallszahlen Generator
for (int i = 0; i < random.length; ++i) {
random[i] = (int) (Math.random()*rmax + rmin); }
asteroidShape = new Polygon();
whichDirection();
}
protected void drawAsteroid() {
move();
rotate();
int degreeHolder;
int degrees;
for (int i = 0; i < amountOfCornerPoints; ++i) {
degreeHolder = i*(360/amountOfCornerPoints) + cornerAddition;
if (degreeHolder >= 360) {
degrees = degreeHolder - 360;
} else {
degrees = degreeHolder;
}
x[i] = getXvalue(size + random[i])[degrees];
y[i] = getYvalue(size + random[i])[degrees];
}
asteroidShape.invalidate();
asteroidShape = new Polygon(x, y, amountOfCornerPoints);
Graphics2D pen = Base.image.createGraphics();
pen.setColor(col);
pen.draw(asteroidShape);
pen.dispose();
}
private void rotate() {
cornerAddition += rotationSpeed;
if (cornerAddition >= 360)
cornerAddition = cornerAddition - 360;
}
private void move() {
detectTransport();
xCenter += xMove;
yCenter += yMove;
}
private void detectTransport() {
boolean transportImmunity = false;
if (xCenter <= -size || xCenter >= Base.width + size) {
if (transportImmunity == false)
transporting = !transporting;
transportImmunity = true;
transport();
}
if (yCenter <= -size || yCenter >= Base.height + size) {
if (transportImmunity == false)
transporting = !transporting;
transportImmunity = true;
transport();
}
}
private void transport() {
while (transporting) {
xCenter -= xMove;
yCenter -= yMove;
detectTransport();
}
}
private void whichDirection() {
switch (direction) {
case 0: // Gerade Oben
xMove = 0;
yMove = -movementSpeed;
break;
case 1: // Diagonal Oben-rechts
xMove = movementSpeed;
yMove = -movementSpeed;
break;
case 2: // Gerade rechts
xMove = movementSpeed;
yMove = 0;
break;
case 3: // Diagonal Unten-rechts
xMove = movementSpeed;
yMove = movementSpeed;
break;
case 4: // Gerade Unten
xMove = 0;
yMove = movementSpeed;
break;
case 5: // Diagonal Unten-links
xMove = -movementSpeed;
yMove = movementSpeed;
break;
case 6: // Gerade links
xMove = -movementSpeed;
yMove = 0;
break;
case 7: // Diagonal Oben-links
xMove = -movementSpeed;
yMove = -movementSpeed;
break;
}
} // end WhichDirection
private int[] getXvalue(int radius) {
int[] xPoint = new int[360];
for (int i = 0; i < 360; ++i) {
double xplus = Math.cos(Math.toRadians(i+1)) * radius;
xPoint[i] = (int) Math.round(xCenter + xplus); }
return xPoint;
}
private int[] getYvalue(int radius) {
int[] yPoint = new int[360];
for (int i = 0; i < 360; ++i) {
double yPlus = Math.sin(Math.toRadians(i+1)) * radius;
yPoint[i] = (int) Math.round(yCenter - yPlus); }
return yPoint;
}
}
PS.: My computer is most likely not the cause, since it can run a lot bigger games with at least 100fps
Edit: None of the other methods, as for example the rotate() method, is causing the lag, as I have already tried the entire code with only the most essential methods and the result was the same.
Edit2: Maybe its worth noting, that the lag actually is only barely noticeable. However, for a game as small as an Asteroids is, there really shouldn't be any lag, especially if it only runs on 60 fps.
Edit3: MRE is added
I would suggest an/fps-limiting approach instead because the lag that can happen in the game gets amplified by the strict time intervals of the Timer class. After you set the frame to be visible add the following code(or something like it):
long time = System.nanoTime();
while(!gameOver) {
long nTime = System.nanoTime();
float diff = (nTime - time) * 0.000000001f;
if(diff > 1.0f / fps) {
time = nTime;
// do rendering here and multiply any speeds or accelerations by diff
}
}
I need to make directed graph from undirected. I can draw line-Edge, but I don't know how to make arrow:
public class Edge extends Group {
protected Cell source;
protected Cell target;
Line line;
public Edge(Cell source, Cell target) {
this.source = source;
this.target = target;
source.addCellChild(target);
target.addCellParent(source);
line = new Line();
line.startXProperty().bind(source.layoutXProperty().add(source.getBoundsInParent().getWidth() / 2.0));
line.startYProperty().bind(source.layoutYProperty().add(source.getBoundsInParent().getHeight() / 2.0));
line.endXProperty().bind(target.layoutXProperty().add( target.getBoundsInParent().getWidth() / 2.0));
line.endYProperty().bind(target.layoutYProperty().add( target.getBoundsInParent().getHeight() / 2.0));
getChildren().addAll(line);
}
You need to add 2 more lines to make an arrow head (or a Polygon with the same points for a filled arrow head).
Note that the direction of the arrow can be determined based on the difference between start and end of the line ends of the "main" connection. One end of each of the lines that make up the arrow head need to be at the same coordinates as the end of the main line. The other end can be calculated by combining a part in direction of the main line and a part ortogonal to the main line:
public class Arrow extends Group {
private final Line line;
public Arrow() {
this(new Line(), new Line(), new Line());
}
private static final double arrowLength = 20;
private static final double arrowWidth = 7;
private Arrow(Line line, Line arrow1, Line arrow2) {
super(line, arrow1, arrow2);
this.line = line;
InvalidationListener updater = o -> {
double ex = getEndX();
double ey = getEndY();
double sx = getStartX();
double sy = getStartY();
arrow1.setEndX(ex);
arrow1.setEndY(ey);
arrow2.setEndX(ex);
arrow2.setEndY(ey);
if (ex == sx && ey == sy) {
// arrow parts of length 0
arrow1.setStartX(ex);
arrow1.setStartY(ey);
arrow2.setStartX(ex);
arrow2.setStartY(ey);
} else {
double factor = arrowLength / Math.hypot(sx-ex, sy-ey);
double factorO = arrowWidth / Math.hypot(sx-ex, sy-ey);
// part in direction of main line
double dx = (sx - ex) * factor;
double dy = (sy - ey) * factor;
// part ortogonal to main line
double ox = (sx - ex) * factorO;
double oy = (sy - ey) * factorO;
arrow1.setStartX(ex + dx - oy);
arrow1.setStartY(ey + dy + ox);
arrow2.setStartX(ex + dx + oy);
arrow2.setStartY(ey + dy - ox);
}
};
// add updater to properties
startXProperty().addListener(updater);
startYProperty().addListener(updater);
endXProperty().addListener(updater);
endYProperty().addListener(updater);
updater.invalidated(null);
}
// start/end properties
public final void setStartX(double value) {
line.setStartX(value);
}
public final double getStartX() {
return line.getStartX();
}
public final DoubleProperty startXProperty() {
return line.startXProperty();
}
public final void setStartY(double value) {
line.setStartY(value);
}
public final double getStartY() {
return line.getStartY();
}
public final DoubleProperty startYProperty() {
return line.startYProperty();
}
public final void setEndX(double value) {
line.setEndX(value);
}
public final double getEndX() {
return line.getEndX();
}
public final DoubleProperty endXProperty() {
return line.endXProperty();
}
public final void setEndY(double value) {
line.setEndY(value);
}
public final double getEndY() {
return line.getEndY();
}
public final DoubleProperty endYProperty() {
return line.endYProperty();
}
}
Use
#Override
public void start(Stage primaryStage) {
Pane root = new Pane();
Arrow arrow = new Arrow();
root.getChildren().add(arrow);
root.setOnMouseClicked(evt -> {
switch (evt.getButton()) {
case PRIMARY:
// set pos of end with arrow head
arrow.setEndX(evt.getX());
arrow.setEndY(evt.getY());
break;
case SECONDARY:
// set pos of end without arrow head
arrow.setStartX(evt.getX());
arrow.setStartY(evt.getY());
break;
}
});
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
I recently got into LibGDX using the book "LibGDX Game Development By Example" (Pretty good one btw) and have been playing around with the tutorial projects for the last month.
One of these games is a FlappyBird-clone (of course it is) and I decided to add features, change sprites etc.
Now the problem is that the normal obstacle graphics (flowers) don't fit the new theme and need to be exchanged.
Doing so results in jiggering graphics for the new sprites.
I should point out that the code used to visualize these obstacles has not changed at all, simply exchanging the sprites causes this problem.
I tried a lot of different sprites and all that are not identical to the flowers seem to have this problem.
So whatever is the cause, the old flower sprites are unaffected, every other sprite is.
On to the code (Removed some Getters/Setters and other unrelated methods)
The Flower/Obstacle Class:
public class Flower
{
private static final float COLLISION_RECTANGLE_WIDTH = 13f;
private static final float COLLISION_RECTANGLE_HEIGHT = 447f;
private static final float COLLISION_CIRCLE_RADIUS = 33f;
private float x = 0;
private float y = 0;
private static final float MAX_SPEED_PER_SECOND = 100f;
public static final float WIDTH = COLLISION_CIRCLE_RADIUS * 2;
private static final float HEIGHT_OFFSET = -400.0f;
private static final float DISTANCE_BETWEEN_FLOOR_AND_CEILING = 225.0f;
private final Circle floorCollisionCircle;
private final Rectangle floorCollisionRectangle;
private final Circle ceilingCollisionCircle;
private final Rectangle ceilingCollisionRectangle;
private boolean pointClaimed = false;
private final TextureRegion floorTexture;
private final TextureRegion ceilingTexture;
float textureX,textureY;
public Flower(TextureRegion floorTexture, TextureRegion ceilingTexture)
{
this.floorTexture = floorTexture;
this.ceilingTexture = ceilingTexture;
this.y = MathUtils.random(HEIGHT_OFFSET);
this.floorCollisionRectangle = new Rectangle(x,y,COLLISION_RECTANGLE_WIDTH,COLLISION_RECTANGLE_HEIGHT);
this.floorCollisionCircle = new Circle(x + floorCollisionRectangle.width / 2, y + floorCollisionRectangle.height, COLLISION_CIRCLE_RADIUS);
this.ceilingCollisionRectangle = new Rectangle(x,floorCollisionCircle.y + DISTANCE_BETWEEN_FLOOR_AND_CEILING,COLLISION_RECTANGLE_WIDTH,
COLLISION_RECTANGLE_HEIGHT);
this.ceilingCollisionCircle = new Circle(x + ceilingCollisionRectangle.width / 2, ceilingCollisionRectangle.y, COLLISION_CIRCLE_RADIUS);
}
public void update(float delta)
{
setPosition(x - (MAX_SPEED_PER_SECOND * delta));
}
public void setPosition(float x)
{
this.x = x;
updateCollisionCircle();
updateCollisionRectangle();
}
private void updateCollisionCircle()
{
floorCollisionCircle.setX(x + floorCollisionRectangle.width / 2);
ceilingCollisionCircle.setX(x + ceilingCollisionRectangle.width / 2);
}
private void updateCollisionRectangle()
{
floorCollisionRectangle.setX(x);
ceilingCollisionRectangle.setX(x);
}
public void draw(SpriteBatch batch)
{
drawFloorFlower(batch);
drawCeilingFlower(batch);
}
private void drawFloorFlower(SpriteBatch batch)
{
textureX = floorCollisionCircle.x - floorTexture.getRegionWidth() / 2;
textureY = floorCollisionRectangle.getY() + COLLISION_CIRCLE_RADIUS;
batch.draw(floorTexture,textureX,textureY);
}
private void drawCeilingFlower(SpriteBatch batch)
{
textureX = ceilingCollisionCircle.x - ceilingTexture.getRegionWidth() / 2;
textureY = ceilingCollisionRectangle.getY() - COLLISION_CIRCLE_RADIUS;
batch.draw(ceilingTexture,textureX, textureY);
}
}
And the GameScreen/Main Class:
public class GameScreen extends ScreenAdapter
{
private static final float WORLD_WIDTH = 480;
private static final float WORLD_HEIGHT = 640;
private java.util.prefs.Preferences prefs;
private int highscore;
FlappeeBeeGame flappeeBeeGame;
private ShapeRenderer shapeRenderer;
private Viewport viewport;
private Camera camera;
private SpriteBatch batch;
private Flappee flappee;
private Flower flower;
private Array<Flower> flowers = new Array<Flower>();
private static final float GAP_BETWEEN_FLOWERS = 200.0f;
private boolean gameOver = false;
int score = 0;
BitmapFont bitmapFont;
GlyphLayout glyphLayout;
private TextureRegion background;
private TextureRegion flowerBottom;
private TextureRegion flowerTop;
private TextureRegion bee;
private TextureRegion smallCloud;
private TextureRegion lowCloud;
private Music music_background;
TextureAtlas textureAtlas;
List<Cloud> activeClouds = new ArrayList<Cloud>();
List<Cloud> cloudBarriers = new ArrayList<Cloud>();
private float cloud_minScale = 0.6f;
private float cloud_maxScale = 1.0f;
private float cloud_minY, cloud_maxY;
private float cloud_minDis, cloud_maxDis;
private float cloud_minSpeed = 17.0f;
private float cloud_maxSpeed = 27.0f;
private final float barrierCloud_speed = 150.0f;
private boolean inputBlocked = false;
private float blockTime = 0.5f;
private float remainingblockTime = blockTime;
public GameScreen(FlappeeBeeGame fpg)
{
flappeeBeeGame = fpg;
flappeeBeeGame.getAssetManager().load("assets/flappee_bee_assets.atlas",TextureAtlas.class);
flappeeBeeGame.getAssetManager().finishLoading();
textureAtlas = flappeeBeeGame.getAssetManager().get("assets/flappee_bee_assets.atlas");
prefs = java.util.prefs.Preferences.userRoot().node(this.getClass().getName());
highscore = prefs.getInt("highscore",0);
music_background = Gdx.audio.newMusic(Gdx.files.internal("assets/backgroundmusic.ogg"));
music_background.setLooping(true);
music_background.setVolume(0.5f);
music_background.play();
}
private void createNewFlower()
{
Flower newFlower = new Flower(flowerBottom,flowerTop);
newFlower.setPosition(WORLD_WIDTH + Flower.WIDTH);
flowers.add(newFlower);
}
private void checkIfNewFlowerIsNeeded()
{
if(flowers.size == 0)
{
createNewFlower();
}
else
{
Flower flower = flowers.peek();
if(flower.getX() < WORLD_WIDTH - GAP_BETWEEN_FLOWERS)
{
createNewFlower();
}
}
}
private void drawFlowers()
{
for(Flower flower : flowers)
{
flower.draw(batch);
}
}
private void removeFlowersIfPassed()
{
if(flowers.size > 0)
{
Flower firstFlower = flowers.first();
if(firstFlower.getX() < -Flower.WIDTH)
{
flowers.removeValue(firstFlower,true);
}
}
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
viewport.update(width,height);
}
#Override
public void show() {
super.show();
camera = new OrthographicCamera();
camera.position.set(WORLD_WIDTH / 2, WORLD_HEIGHT / 2, 0);
camera.update();
viewport = new FitViewport(WORLD_WIDTH,WORLD_HEIGHT, camera);
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
bitmapFont = new BitmapFont(Gdx.files.internal("assets/score_new.fnt"));
glyphLayout = new GlyphLayout();
background = textureAtlas.findRegion("bg");
flowerBottom = textureAtlas.findRegion("pipeBottom");
flowerTop = textureAtlas.findRegion("flowerTop");
bee = textureAtlas.findRegion("bee");
smallCloud = textureAtlas.findRegion("smallCloud");
lowCloud = textureAtlas.findRegion("lowerCloud");
flower = new Flower(flowerBottom,flowerTop);
flappee = new Flappee(bee,textureAtlas);
flappee.setPosition(WORLD_WIDTH/4,WORLD_HEIGHT/2);
cloud_minDis = smallCloud.getRegionWidth() / 4;
cloud_maxDis = smallCloud.getRegionWidth();
cloud_maxY = viewport.getWorldHeight() - smallCloud.getRegionHeight()/2;
cloud_minY = viewport.getWorldHeight() - smallCloud.getRegionHeight() * 2;
Cloud a = generateCloud(null);
Cloud b = generateCloud(a);
Cloud c = generateCloud(b);
Cloud d = generateCloud(c);
Cloud e = generateCloud(d);
activeClouds.add(a);
activeClouds.add(b);
activeClouds.add(c);
activeClouds.add(d);
activeClouds.add(e);
a = new Cloud(lowCloud,batch,0,0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
b = new Cloud(lowCloud,batch,lowCloud.getRegionWidth(),0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
c = new Cloud(lowCloud,batch,lowCloud.getRegionWidth()*2,0 - lowCloud.getRegionHeight()/4,barrierCloud_speed,1.0f);
cloudBarriers.add(a);
cloudBarriers.add(b);
cloudBarriers.add(c);
}
public Cloud generateCloud(Cloud formerCloud)
{
Cloud d;
if(formerCloud == null)
{
float randomVal = (float)Math.random();
d = new Cloud(smallCloud,batch,viewport.getWorldWidth(),
(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY,
randomVal * (cloud_maxSpeed-cloud_minSpeed) + cloud_minSpeed,
randomVal * (cloud_maxScale-cloud_minScale) + cloud_minScale);
return d;
}
float randomVal = (float)Math.random();
d = new Cloud(smallCloud,batch,formerCloud.getPosX() + ((float)
Math.random() * (cloud_maxDis - cloud_minDis) + cloud_minDis),(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY,
randomVal * (cloud_maxSpeed-cloud_minSpeed) + cloud_minSpeed,
randomVal * (cloud_maxScale-cloud_minScale) + cloud_minScale);
return d;
}
#Override
public void render(float delta) {
super.render(delta);
clearScreen();
shapeRenderer.setProjectionMatrix(camera.projection);
shapeRenderer.setTransformMatrix(camera.view);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.end();
draw(delta);
update(delta);
}
private void draw(float delta)
{
batch.setProjectionMatrix(camera.projection);
batch.setTransformMatrix(camera.view);
batch.begin();
batch.draw(background,0,0);
drawClouds(delta);
drawScore();
drawFlowers();
//drawDebug();
if(!gameOver)
{
flappee.draw(batch,delta);
}
drawBarrierClouds(delta);
batch.end();
}
private void updateClouds(float delta)
{
boolean move = false;
Cloud tmp = null;
for(Cloud c : cloudBarriers)
{
c.update(delta);
if(c.getPosX() <= -lowCloud.getRegionWidth())
{
tmp = c;
move = true;
}
}
if(move)
{
float positionX = cloudBarriers.get(cloudBarriers.size()-1).getPosX() + lowCloud.getRegionWidth();
if(positionX < viewport.getWorldWidth())
{
positionX = viewport.getWorldWidth();
}
tmp.setPos(positionX,0 - lowCloud.getRegionHeight()/4);
cloudBarriers.remove(tmp);
cloudBarriers.add(tmp);
tmp = null;
move = false;
}
for(Cloud c : activeClouds)
{
c.update(delta);
if(c.getPosX() <= -smallCloud.getRegionWidth())
{
tmp = c;
move = true;
}
}
if(move)
{
float randomVal = (float)Math.random();
float positionX = activeClouds.get(activeClouds.size()-1).getPosX() + ((float)
Math.random() * (cloud_maxDis - cloud_minDis) + cloud_minDis);
if(positionX < viewport.getWorldWidth())
{
positionX = viewport.getWorldWidth();
}
tmp.setPos(positionX,(float)Math.random() * (cloud_maxY - cloud_minY) + cloud_minY);
tmp.setSpeed(randomVal * (cloud_maxSpeed - cloud_minSpeed) + cloud_minSpeed);
tmp.setScale(randomVal * (cloud_maxScale - cloud_minScale) + cloud_minScale);
activeClouds.remove(tmp);
activeClouds.add(tmp);
move = false;
tmp = null;
}
}
private void drawBarrierClouds(float delta)
{
for(Cloud c : cloudBarriers)
{
c.render();
}
}
private void drawClouds(float delta)
{
for(Cloud c : activeClouds)
{
c.render();
}
}
private void clearScreen()
{
Gdx.gl.glClearColor(Color.BLACK.r,Color.BLACK.g,Color.BLACK.b, Color.BLACK.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
private void blockFlappeeLeavingTheWorld()
{
flappee.setPosition(flappee.getX(), MathUtils.clamp(flappee.getY(),0,WORLD_HEIGHT));
}
private void updateFlowers(float delta)
{
for(Flower flower : flowers)
{
flower.update(delta);
}
checkIfNewFlowerIsNeeded();
removeFlowersIfPassed();
}
private void update(float delta)
{
updateClouds(delta);
if(!gameOver) {
updateFlappee(delta);
updateFlowers(delta);
updateScore();
if (checkForCollision())
{
gameOver = true;
inputBlocked = true;
remainingblockTime = blockTime;
restart();
}
}
else
{
if((Gdx.input.isKeyJustPressed(Input.Keys.SPACE) || Gdx.input.isButtonPressed(Input.Buttons.LEFT)) && !inputBlocked)
{
gameOver = false;
score = 0;
}
if(inputBlocked)
{
if(remainingblockTime > 0)
{
remainingblockTime -= delta;
}
else
{
inputBlocked = false;
remainingblockTime = blockTime;
}
}
}
}
private void restart()
{
flappee.setPosition(WORLD_WIDTH / 4, WORLD_HEIGHT / 2);
flowers.clear();
}
#Override
public void dispose() {
super.dispose();
}
private boolean checkForCollision()
{
for(Flower flower : flowers)
{
if(flower.isFlappeeColliding(flappee))
{
if(score > highscore)
{
highscore = score;
prefs.putInt("highscore",highscore);
inputBlocked = true;
remainingblockTime = blockTime;
}
return true;
}
}
return false;
}
}
I'd love to give you a runnable jar but I've got some problems building a working version. Let's just say a jar is out of the question for now.
What I can give you are screenshots:
Jiggering Sprite View
Functional Flower Sprite View
The first image shows the problem: The new sprites (which are just debug) become edgy like the top of the sprite can't compete with the speed of its lower half.
The second image shows the old sprites for comparison: They don't show any of this behaviour, even if they are longer than the one on the screenshot.
So what do you people think?
What causes this behaviour and how should I fix it?
Thanks in advance for any help, I appreciate it :)
Greetz!
EDIT:
I kind of fixed it.
When switching to another computer and running the game the issue didn't come up anymore.
Specifically I went from Debian to Windows 10 and from NVIDIA Optimus to a standard desktop AMD-Card.
If you should encounter this problem try another PC with a different OS and/or GPU.
Sadly (if you were to google this question) I can't tell you how to solve it on the first machine or what exactly caused it, but at least it shouldn't come up on anyone else's computer when you send them your project.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
For my binary tree program, I have been using JTextFields as nodes and I have managed to make it so when I click left button and select two of the JTextFields, it will draw a line between them. The problem is if I want to drag the JtextField around, I want the line to be following as well between two of the midpoints of the JTextField. I don't know if it's possible with using only paintComponent or not. I did try it but it's like a one off thing and it will leave a trail of all the previously drawn lines.
Here, is the code so far, there are other classes so some of the bits won't work. The code has been fiddled around a bit as well for testing.
public class BinaryTreeMainPnl extends JPanel {
public static Graphics g1;
public int Width = 75;
public int Height = 45;
public String tempNode1 = "";
public int tempNode1Pos = 0;
public int tempNode2Pos = 0;
public String tempNode2 = "";
public static boolean leftBtnSelected;
public static boolean rightBtnSelected;
private static int x1, y1 = 50;
private static int x2, y2 = 500;
JToggleButton leftBtn = new JToggleButton("Left");
JToggleButton rightBtn = new JToggleButton("Right");
JTextField[] myArray = new JTextField[60];
ArrayList<String> nodeNames = new ArrayList<String>();
JFrame MainFrame;
JTextField txtFld1 = new JTextField("Enter Questions here");
JButton btn1 = new JButton("Submit");
public BinaryTreeMainPnl(JFrame frame) {
super();
setSize(800, 700);
MainFrame = frame;
readInput();
leftBtn.setFont(new Font("Arial", Font.BOLD, 15));
leftBtn.setForeground(Color.blue);
leftBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
rightBtn.setSelected(false);
leftBtnSelected = leftBtn.getModel().isSelected();
rightBtnSelected = false;
System.out.println(leftBtnSelected);
System.out.println(rightBtnSelected);
}
});
add(leftBtn);
rightBtn.setFont(new Font("Arial", Font.BOLD, 15));
rightBtn.setForeground(Color.green);
rightBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
leftBtn.setSelected(false);
rightBtnSelected = rightBtn.getModel().isSelected();
leftBtnSelected = false;
System.out.println(leftBtnSelected);
System.out.println(rightBtnSelected);
}
});
add(rightBtn);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
updateLine(g);
}
public void readInput() {
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
identifyNodeNames(txtFld1.getText());
displayNodes(nodeNames);
new TreeSorting().treeSort(nodeNames);
}
});
this.add(txtFld1);
this.add(btn1);
}
public void displayNodes(ArrayList<String> nodeNames) {
for (int i = 0; i < nodeNames.size(); i++) {
String currentSetText = nodeNames.get(i);
myArray[i] = new JTextField(currentSetText);
myArray[i].setEditable(false);
}
for (int i = 0; i < nodeNames.size(); i++) {
int I = i;
myArray[I].addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent evt) {
int x = evt.getX() + myArray[I].getX();
int y = evt.getY() + myArray[I].getY();
myArray[I].setBounds(x, y, myArray[I].getWidth(), myArray[I].getWidth());
System.out.println(myArray[I] + "dragged");
}
});
myArray[I].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent evt) {
if (leftBtnSelected) {
if (tempNode1.equals("")) {
tempNode1 = myArray[I].getText();
System.out.println(tempNode1 + "clicked");
} else {
tempNode2 = myArray[I].getText();
System.out.println(tempNode2 + "Clicked as well");
leftBtn.setSelected(false);
leftBtnSelected = false;
x1 = 40;
y1 = 40;
x2 = 400;
y2 = 400;
updateLine(g1);
System.out.println("asdasd");
}
}
if (rightBtnSelected) {
}
}
public void moveComponent(MouseEvent evt) {
}
});
System.out.println("I " + I);
System.out.println(myArray[I].getText());
add(myArray[I]);
}
MainFrame.revalidate();
}
public int findMidPoint(JTextField temp) {
Point p = temp.getLocation();
Dimension d = temp.getSize();
return p.x + (d.width) / 2;
}
int coun = 0;
public void updateLine(Graphics g) {
g.drawLine(x1, x2, y1, y2);
x1 = x1 + 10;
y1 = y1 + 10;
y2 = y2 + 10;
x2 = x2 + 10;
System.out.println("Line Updated" + coun);
coun++;
}
public void identifyNodeNames(String answer) {
int arrayCounter = 0;
int lastNodePosition = 0;
for (int i = 0; i < answer.length(); i++) {
char c = answer.charAt(i);
if (c == ',') {
nodeNames.add(arrayCounter, answer.substring(lastNodePosition, i + 1).replaceAll(",", "").replaceAll(" ", ""));
lastNodePosition = i + 1;
arrayCounter++;
}
if (i == answer.length() - 1) {
nodeNames.add(arrayCounter, answer.substring(lastNodePosition, answer.length()).replaceAll(" ", ""));
}
}
}
}
import java.util.ArrayList;
public class TreeSorting {
public static int arrayLength;
String[][] Child;
String root = "";
boolean nodeSorted = false;
int parentCounter = 1;
public void treeSort(ArrayList<String> passedQuestions) {
// declaring nodes
arrayLength = passedQuestions.size();
System.out.println(arrayLength + "ARRAY LENGTH");
Child = new String[arrayLength][3];
for (int i = 0; i < arrayLength; i++) {
Child[i][0] = passedQuestions.get(i);
}
//initially calling the mainprocess with parentCounter 1;
root = Child[0][0];
mainProcess(1);
}
public void mainProcess(int parentCounter) {
if (parentCounter < Child.length) {
System.out.println(parentCounter);
sortingTree(Child[parentCounter][0], root, 0); //where the next node is passed on the tree is sorted recursively
for (int i = 0; i < Child.length; i++) {
System.out.println(Child[i][0]);
System.out.println(Child[i][1] + "," + Child[i][2]);
}
}
}
public void sortingTree(String CurrentNode, String PreviousNode, int PreviousPosition) {
nodeSorted = false;// node is not sorted in the beginning
if (isAfter(CurrentNode.toLowerCase(), PreviousNode.toLowerCase())) {
System.out.println(Child[PreviousPosition][2]);
if (Child[PreviousPosition][2] == null) { //checks if the right of the node is empty, if found empty the node is placed there.
Child[PreviousPosition][2] = CurrentNode;
nodeSorted = true; // if the node finds a position in the array node is sorted.
} else {
sortingTree(CurrentNode, Child[PreviousPosition][2], getPositionInArray(Child[PreviousPosition][2]));
//if the array position was not empty, the loop will process again this time with the item found in the filled position.
}
} else if (Child[PreviousPosition][1] == null) { // if the left of the node is empty, the item will be placed there
Child[PreviousPosition][1] = CurrentNode;
nodeSorted = true;
} else {
sortingTree(CurrentNode, Child[PreviousPosition][1], getPositionInArray(Child[PreviousPosition][1]));
//if the array position was not empty, the loop will process again this time with the item found in the filled position.
}
if (nodeSorted) { // if the node finds a position in the array, the nodeCounter increments and the next node in the question is processed.
parentCounter++;
mainProcess(parentCounter);
}
}
public int getPositionInArray(String node) {
int position = 0;
loop:
for (int i = 0; i < Child.length; i++) {
if (Child[i][0].equals(node)) {
position = i;
break loop;
}
}
return position;
}
public boolean isAfter(String CurrentNode, String PreviousNode) {
int loopLength = determineLoopLength(CurrentNode, PreviousNode);
boolean result = false;
String tempCheck = "";
loop:
for (int i = 0; i < loopLength; i++) {
if ((int) CurrentNode.charAt(i) > (int) PreviousNode.charAt(i)) {
result = true;
break loop;
}
if ((int) CurrentNode.charAt(i) < (int) PreviousNode.charAt(i)) {
result = false;
break loop;
} else if (CurrentNode.charAt(i) == PreviousNode.charAt(i) && CurrentNode.length() > PreviousNode.length()) {
System.out.println("I'm here");
tempCheck = tempCheck + CurrentNode.charAt(i) + "";
if (i == loopLength - 1 && tempCheck.equals(PreviousNode)) {
result = true;
break loop;
}
}
}
return result;
}
public int determineLoopLength(String CurrentNode, String PreviousNode) {
int loopLength = 0;
if (CurrentNode.length() < PreviousNode.length()) {
loopLength = CurrentNode.length();
}
if (PreviousNode.length() < CurrentNode.length()) {
loopLength = PreviousNode.length();
} else {
loopLength = CurrentNode.length();
}
return loopLength;
}
}
WTF, been working on this,.....
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class DragMyFields extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 800;
private static final int COLS = 8;
private static final int DELTA_Y = 120;
private static final int MAX_DEPTH = 3;
private MySimpleTreeNode<JTextField> treeRoot = new MySimpleTreeNode<>();
private MyMouse myMouse = new MyMouse();
public DragMyFields() {
setLayout(null); // this is *** BAD ***
// much better would be to create a custom layout
JTextField field = new JTextField(COLS);
field.addMouseListener(myMouse);
field.addMouseMotionListener(myMouse);
field.setSize(field.getPreferredSize());
int x = (PREF_W - field.getPreferredSize().width) / 2;
int y = DELTA_Y;
field.setLocation(x, y);
add(field);
treeRoot.setNode(field);
recursiveCreateTree(treeRoot, MAX_DEPTH, x, y);
}
private void recursiveCreateTree(MySimpleTreeNode<JTextField> node, int depth, int x, int y) {
if (depth == 0) {
return;
}
JTextField leftField = new JTextField(COLS);
JTextField rightField = new JTextField(COLS);
MySimpleTreeNode<JTextField> leftNode = new MySimpleTreeNode<>(leftField);
MySimpleTreeNode<JTextField> rightNode = new MySimpleTreeNode<>(rightField);
node.setLeft(leftNode);
node.setRight(rightNode);
int multiplier = 4;
for (int i = 0; i < MAX_DEPTH - depth; i++) {
multiplier *= 2;
}
int xL = x - getPreferredSize().width / multiplier;
int xR = x + getPreferredSize().width / multiplier;
y += DELTA_Y;
leftField.setSize(leftField.getPreferredSize());
rightField.setSize(rightField.getPreferredSize());
leftField.setLocation(xL, y);
rightField.setLocation(xR, y);
leftField.addMouseListener(myMouse);
leftField.addMouseMotionListener(myMouse);
rightField.addMouseListener(myMouse);
rightField.addMouseMotionListener(myMouse);
add(leftField);
add(rightField);
recursiveCreateTree(leftNode, depth - 1, xL, y);
recursiveCreateTree(rightNode, depth - 1, xR, y);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
recursiveDraw(g, treeRoot);
}
private void recursiveDraw(Graphics g, MySimpleTreeNode<JTextField> node) {
MySimpleTreeNode<JTextField> left = node.getLeft();
MySimpleTreeNode<JTextField> right = node.getRight();
Point p = getNodeCenter(node);
if (left != null) {
Point p2 = getNodeCenter(left);
g.drawLine(p.x, p.y, p2.x, p2.y);
recursiveDraw(g, left);
}
if (right != null) {
Point p2 = getNodeCenter(right);
g.drawLine(p.x, p.y, p2.x, p2.y);
recursiveDraw(g, right);
}
}
private Point getNodeCenter(MySimpleTreeNode<JTextField> node) {
JTextField field = node.getNode();
Point location = field.getLocation();
Dimension size = field.getSize();
return new Point(location.x + size.width / 2, location.y + size.height / 2);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
Component source = null;
private Point pressedP;
private Point pressedLoc;
private Point parentP;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
source = e.getComponent();
parentP = source.getParent().getLocationOnScreen();
pressedLoc = source.getLocationOnScreen();
pressedP = e.getLocationOnScreen();
}
#Override
public void mouseReleased(MouseEvent e) {
moveComponent(e);
source = null;
pressedP = null;
pressedLoc = null;
}
#Override
public void mouseDragged(MouseEvent e) {
if (source == null) {
return;
}
moveComponent(e);
}
private void moveComponent(MouseEvent e) {
Point p = e.getLocationOnScreen();
int x = pressedLoc.x + p.x - pressedP.x - parentP.x;
int y = pressedLoc.y + p.y - pressedP.y - parentP.y;
Point newP = new Point(x, y);
source.setLocation(newP);
repaint();
}
}
private static void createAndShowGui() {
DragMyFields mainPanel = new DragMyFields();
JFrame frame = new JFrame("DragMyFields");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
class MySimpleTreeNode<T> {
private T node;
private MySimpleTreeNode<T> left;
private MySimpleTreeNode<T> right;
public MySimpleTreeNode() {
// default constructor
}
public MySimpleTreeNode(T node) {
this.node = node;
}
public void setNode(T node) {
this.node = node;
}
public T getNode() {
return node;
}
public MySimpleTreeNode<T> getLeft() {
return left;
}
public void setLeft(MySimpleTreeNode<T> left) {
this.left = left;
}
public MySimpleTreeNode<T> getRight() {
return right;
}
public void setRight(MySimpleTreeNode<T> right) {
this.right = right;
}
}
I have a model of planet (below) and paint the Sun in center of screen. Then I draw the planets using a new thread. Planets move is too fast and not means that it's a move on a circle. I tried to change the thread's sleep time and planet's velocity and does not matter - planets move too fast. Velocity > 3 - too fast speed.
I need result: Planets move slow and I can manage a planet's speed with her velocity (1, 3, 5, 10). Angle (position of planet) changes 1 time in second on small amount (1, 3, 5 degrees - velocity)
public class Planet
{
private String name;
private int id;
private double radius = 1.0;
private double radiusOrbit = 5.0;
private double velocity = 1;
private Color color;
private int angle = 0;
private String parent;
public Planet(String name, int id, double rad, double radOrbit, double velocity, Color color)
{
this.name = name;
this.id = id;
this.radius = rad;
this.radiusOrbit = radOrbit;
this.velocity = velocity;
this.color = color;
}
...getters and setters
}
Main Class
public class ShowCosmos2 {
public static void main(String[] args)
{
JFrame frame = new PlanetsFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class PlanetsFrame extends JFrame
{
private int width = Toolkit.getDefaultToolkit().getScreenSize().width;
private int height = Toolkit.getDefaultToolkit().getScreenSize().height;
public PlanetsFrame()
{
setSize(width, height);
setTitle("Planets");
setContentPane(new PlanetsCanvas(width, height));
Container contentPane = getContentPane();
contentPane.setBackground(Color.BLACK);
}
}
class PlanetsCanvas extends JPanel
{
private int width, height;
private int centerX = 0;
private int centerY = 0;
private Thread runner;
private boolean running = false;
Planet[] planets = {
new Planet("Venera", 1, 5.0, 50.0, 1, Color.GREEN),
new Planet("Mercury", 1, 3.0, 75.0, 1.5, Color.ORANGE),
new Planet("Earth", 1, 6.0, 100.0, 2, Color.BLUE),
new Planet("Jupiter", 1, 12.0, 150.0, 1, Color.RED)
};
public PlanetsCanvas(int w, int h)
{
width = w;
height = h;
centerX = (int)(w/2);
centerY = (int)(h/2);
}
protected void drawFrame(Graphics g)
{
//Sun
g.setColor(Color.YELLOW);
g.fillOval(width/2 - 25, height/2 - 25, 50, 50);
for (int i = 0; i < planets.length; i++)
{
Planet p = planets[i];
g.setColor(p.getColor());
int newX = (int)(centerX + Math.cos(p.getAngle())*p.getRadiusOrbit());
int newY = (int)(centerY - Math.sin(p.getAngle())*p.getRadiusOrbit());
g.fillOval((int)(newX-p.getRadius()),
(int)(newY-p.getRadius()),
(int)p.getRadius()*2, (int)p.getRadius()*2);
//int angle = (int)(p.getAngle() + p.getVelocity());
//if (angle >= 360) angle = 0;
//p.setAngle(angle);
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawFrame(g);
startAnimation();
}
public void startAnimation() {
runner = new Thread() {
public void run() {
try {
while (!Thread.interrupted()) {
repaint();
for(int i=0; i<planets.length; i++)
{
Planet p = planets[i];
int angle = (int)(p.getAngle() + p.getVelocity());
if (angle >= 360) angle = 0;
p.setAngle(angle);
}
Thread.sleep(500);
}
} catch (Exception e) {
}
}
};
runner.start();
running = true;
}
}
Most important -- don't start your animation from within paintComponent. The paintcomponent method will keep being called over and over again, meaning you're going to be creating more and more animation threads unnecessarily, when only one is what's called for. What's worse, you do not have complete control over when or even if paintComponent is called. So instead start your animation thread once and likely in your class's constructor.
Consider following points
Your startAnimation() method should be called once only and not in paintComponent() method which will instantiate a new thread on every repaint()
Apart from that keep the angle a double type as this will allow you to make arbitrarily small increments and decrements to it.
Thead.sleep() interval should be the single frame time.
Maintain a DAMPING_COFFICIENT to multiply to velocity when calculating new angle to slow down or speed up.
Here's modified slowed down code.
import java.awt.Color;
public class Planet {
private String name;
private int id;
private double radius = 1.0;
private double radiusOrbit = 5.0;
private double velocity = 1;
private Color color;
private double angle = 0;
private String parent;
public Planet(String name, int id, double rad, double radOrbit,
double velocity, Color color) {
this.name = name;
this.id = id;
this.radius = rad;
this.radiusOrbit = radOrbit;
this.velocity = velocity;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadiusOrbit() {
return radiusOrbit;
}
public void setRadiusOrbit(double radiusOrbit) {
this.radiusOrbit = radiusOrbit;
}
public double getVelocity() {
return velocity;
}
public void setVelocity(double velocity) {
this.velocity = velocity;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
public double getAngle() {
return angle;
}
public void setAngle(double angle) {
this.angle = angle;
}
}
Rest of the classes
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ShowCosmos2 {
public static void main(String[] args) {
JFrame frame = new PlanetsFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class PlanetsFrame extends JFrame {
private int width = Toolkit.getDefaultToolkit().getScreenSize().width;
private int height = Toolkit.getDefaultToolkit().getScreenSize().height;
public PlanetsFrame() {
setSize(width, height);
setTitle("Planets");
setContentPane(new PlanetsCanvas(width, height));
Container contentPane = getContentPane();
contentPane.setBackground(Color.BLACK);
}
}
class PlanetsCanvas extends JPanel {
private static final double DAMPING_COFFICIENT = 0.01;
private static final int FRAMES_PER_SECOND = 60;
private static final long FRAME_DURATION = (1000 / FRAMES_PER_SECOND);
private int width, height;
private int centerX = 0;
private int centerY = 0;
private Thread runner;
private boolean running = false;
Planet[] planets = { new Planet("Venera", 1, 5.0, 50.0, 1, Color.GREEN),
new Planet("Mercury", 1, 3.0, 75.0, 1.5, Color.ORANGE),
new Planet("Earth", 1, 6.0, 100.0, 2, Color.BLUE),
new Planet("Jupiter", 1, 12.0, 150.0, 1, Color.RED) };
public PlanetsCanvas(int w, int h) {
width = w;
height = h;
centerX = (int) (w / 2);
centerY = (int) (h / 2);
startAnimation();
}
protected void drawFrame(Graphics g) {
// Sun
g.setColor(Color.YELLOW);
g.fillOval(width / 2 - 25, height / 2 - 25, 50, 50);
for (int i = 0; i < planets.length; i++) {
Planet p = planets[i];
g.setColor(p.getColor());
int newX = (int) (centerX + Math.cos(p.getAngle())
* p.getRadiusOrbit());
int newY = (int) (centerY - Math.sin(p.getAngle())
* p.getRadiusOrbit());
g.fillOval((int) (newX - p.getRadius()),
(int) (newY - p.getRadius()), (int) p.getRadius() * 2,
(int) p.getRadius() * 2);
// int angle = (int)(p.getAngle() + p.getVelocity());
// if (angle >= 360) angle = 0;
// p.setAngle(angle);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawFrame(g);
}
public void startAnimation() {
runner = new Thread() {
public void run() {
try {
while (!Thread.interrupted()) {
repaint();
for (Planet p : planets) {
double angle = (p.getAngle() + p.getVelocity() * DAMPING_COFFICIENT);
//System.out.println(p.getName() + " : " + angle);
if (angle >= 360)
angle = 0;
p.setAngle(angle);
}
Thread.sleep(FRAME_DURATION);
}
} catch (Exception e) {
}
}
};
runner.start();
running = true;
}
}
.