I am trying to add numbers around the clock from 1 to 12. The clock is not drawing the numbers. I have the clock drawn and the hour, minute, and second hands drawn.
import java.util.Calendar;
import java.util.GregorianCalendar;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
public class ClockPane extends Pane {
private int hour;
private int minute;
private int second;
/** Construct a default clock with the current time */
public ClockPane() {
setCurrentTime();
}
/** Construct a clock with specified hour, minute, and second */
public ClockPane(int hour, int minute, int second) {
this.hour = hour;
this.minute = minute;
this.second = second;
}
/** Return hour */
public int getHour() {
return hour;
}
/** Set a new hour */
public void setHour(int hour) {
this.hour = hour;
paintClock();
}
/** Return minute */
public int getMinute() {
return minute;
}
/** Set a new minute */
public void setMinute(int minute) {
this.minute = minute;
paintClock();
}
/** Return second */
public int getSecond() {
return second;
}
/** Set a new second */
public void setSecond(int second) {
this.second = second;
paintClock();
}
/* Set the current time for the clock */
public void setCurrentTime() {
// Construct a calendar for the current date and time
Calendar calendar = new GregorianCalendar();
// Set current hour, minute and second
this.hour = calendar.get(Calendar.HOUR_OF_DAY);
this.minute = calendar.get(Calendar.MINUTE);
this.second = calendar.get(Calendar.SECOND);
paintClock(); // Repaint the clock
}
private void paintClock() {
// Initialize clock parameters
double clockRadius = Math.min(getWidth(), getHeight()) * 0.8 * 0.5;
double centerX = getWidth() / 2;
double centerY = getHeight() / 2;
// Draw circle
Circle circle = new Circle(centerX, centerY, clockRadius);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
// Draw hour markers
double numberRadius = clockRadius * 0.85;
for (int i = 1; i <= 12; i++) {
double numberX = centerX + numberRadius * Math.sin(i * 2 * Math.PI / 12);
double numberY = centerY - numberRadius * Math.cos(i * 2 * Math.PI / 12);
Text number = new Text(numberX - 5, numberY + 5, "" + i);
number.setFill(Color.BLACK);
getChildren().addAll(number);
}
// Draw second hand
double sLength = clockRadius * 0.8;
double secondX = centerX + sLength * Math.sin(second * (2 * Math.PI / 60));
double secondY = centerY - sLength * Math.cos(second * (2 * Math.PI / 60));
Line sLine = new Line(centerX, centerY, secondX, secondY);
sLine.setStroke(Color.RED);
// Draw minute hand
double mLength = clockRadius * 0.65;
double xMinute = centerX + mLength * Math.sin(minute * (2 * Math.PI / 60));
double minuteY = centerY - mLength * Math.cos(minute * (2 * Math.PI / 60));
Line mLine = new Line(centerX, centerY, xMinute, minuteY);
mLine.setStroke(Color.BLUE);
// Draw hour hand
double hLength = clockRadius * 0.5;
double hourX =
centerX + hLength * Math.sin((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
double hourY =
centerY - hLength * Math.cos((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
Line hLine = new Line(centerX, centerY, hourX, hourY);
hLine.setStroke(Color.GREEN);
getChildren().clear(); // Clear the pane
getChildren().addAll(circle, sLine, mLine, hLine);
}
#Override
public void setWidth(double width) {
super.setWidth(width);
paintClock();
}
#Override
public void setHeight(double height) {
super.setHeight(height);
paintClock();
}
}
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
public class DisplayClock extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a clock and a label
ClockPane clock = new ClockPane();
String timeString = clock.getHour() + ":" + clock.getMinute() + ":" + clock.getSecond();
Label lblCurrentTime = new Label(timeString);
// Place clock and label in border pane
BorderPane pane = new BorderPane();
pane.setCenter(clock);
pane.setBottom(lblCurrentTime);
BorderPane.setAlignment(lblCurrentTime, Pos.TOP_CENTER);
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 250, 250);
primaryStage.setTitle("DisplayClock"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
When I run the program the numbers are not showing on the clock. I check the imports. It's correct. The code is also correct. I don't know why it's not showing. What should I do to fix it?
Related
I am currently making an analog clock in java using AWT Package and Swing. But the digital clock overlay is currently flickering every once in a while and I'd like to fix that.
I've read about implementing double buffered in conjunction with repaint() but I am stuck on how to implement it.
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
public class Clock2d extends Applet {
GregorianCalendar cal;
Timer clockTimer = new Timer();
TimeZone clockTimeZone = TimeZone.getDefault();
public Clock2d() {
clockTimer.schedule(new TickTimerTask(), 0, 1000);
}
#Override
public void init() {
}
public void paint(Graphics g) {
g.setColor(Color.BLUE);
g.fillOval(40, 40, 220, 220);
g.setColor(Color.WHITE);
g.fillOval(50, 50, 200, 200);
double second = cal.get(Calendar.SECOND);
double minute = cal.get(Calendar.MINUTE);
double hours = cal.get(Calendar.HOUR);
for (int i = 0; i < 60; i++) {
int length = 90;
double rad = (i * 6) * (Math.PI) / 180;
if (i % 5 == 0) {
length = 82;
g.setColor(Color.BLUE);
} else {
g.setColor(Color.GRAY);
}
int x = 150 + (int) (95 * Math.cos(rad - (Math.PI / 2)));
int y = 150 + (int) (95 * Math.sin(rad - (Math.PI / 2)));
int x1 = 150 + (int) (length * Math.cos(rad - (Math.PI / 2)));
int y1 = 150 + (int) (length * Math.sin(rad - (Math.PI / 2)));
g.drawLine(x, y, x1, y1);
}
drawHands(g, second, minute, hours);
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
g.setColor(Color.BLUE);
g.setFont(new Font("Tahoma", Font.BOLD, 16));
g.drawString(sdf.format(cal.getTime()), 120, 20);
g.setFont(new Font("Arial", Font.BOLD, 10));
}
public void drawHands(Graphics g, double second, double minute, double hours) {
double rSecond = (second * 6) * (Math.PI) / 180;
double rMinute = ((minute + (second / 60)) * 6) * (Math.PI) / 180;
double rHours = ((hours + (minute / 60)) * 30) * (Math.PI) / 180;
g.setColor(Color.RED);
g.drawLine(150, 150, 150 + (int) (100 * Math.cos(rSecond - (Math.PI / 2))), 150 + (int) (100 * Math.sin(rSecond - (Math.PI / 2))));
g.setColor(Color.BLACK);
g.drawLine(150, 150, 150 + (int) (70 * Math.cos(rMinute - (Math.PI / 2))), 150 + (int) (70 * Math.sin((rMinute - (Math.PI / 2)))));
g.drawLine(150, 150, 150 + (int) (50 * Math.cos(rHours - (Math.PI / 2))), 150 + (int) (50 * Math.sin(rHours - (Math.PI / 2))));
}
class TickTimerTask extends TimerTask {
#Override
public void run() {
cal = (GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);
repaint();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Clock 2D");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(330, 330));
Clock2d clock2d = new Clock2d();
clock2d.setPreferredSize(new Dimension(320, 320));
clock2d.init();
frame.setLayout(new BorderLayout());
frame.getContentPane().add(clock2d, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
The code work exactly as intended aside from the occasional flickering of the Numbered Digital clock.
public class Clock2d extends Applet A java.awt.Applet is not only deprecated, but also not double buffered by default. Change that to extend a JPanel (which is).
Then change public void paint(Graphics g) { to public void paintComponent(Graphics g) { super.paintComponent(g); to respect the paint chain.
class TickTimerTask extends TimerTask use a javax.swing.Timer instead. It runs on the Event Dispatch Thread, and any calls to the GUI should be made on the EDT.
Here are those three points, expressed in the code. Do you see the 'flickering' artifacts in this version?
import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import javax.swing.*;
public class Clock2d extends JPanel {
TimeZone clockTimeZone = TimeZone.getDefault();
GregorianCalendar cal =
(GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);
ActionListener repaintListener = (ActionEvent e) -> {
cal = (GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);
repaint();
};
Timer clockTimer = new Timer(100, repaintListener);
public Clock2d() {
clockTimer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillOval(40, 40, 220, 220);
g.setColor(Color.WHITE);
g.fillOval(50, 50, 200, 200);
double second = cal.get(Calendar.SECOND);
double minute = cal.get(Calendar.MINUTE);
double hours = cal.get(Calendar.HOUR);
for (int i = 0; i < 60; i++) {
int length = 90;
double rad = (i * 6) * (Math.PI) / 180;
if (i % 5 == 0) {
length = 82;
g.setColor(Color.BLUE);
} else {
g.setColor(Color.GRAY);
}
int x = 150 + (int) (95 * Math.cos(rad - (Math.PI / 2)));
int y = 150 + (int) (95 * Math.sin(rad - (Math.PI / 2)));
int x1 = 150 + (int) (length * Math.cos(rad - (Math.PI / 2)));
int y1 = 150 + (int) (length * Math.sin(rad - (Math.PI / 2)));
g.drawLine(x, y, x1, y1);
}
drawHands(g, second, minute, hours);
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
g.setColor(Color.BLUE);
g.setFont(new Font("Tahoma", Font.BOLD, 16));
g.drawString(sdf.format(cal.getTime()), 120, 20);
g.setFont(new Font("Arial", Font.BOLD, 10));
}
public void drawHands(Graphics g, double second, double minute, double hours) {
double rSecond = (second * 6) * (Math.PI) / 180;
double rMinute = ((minute + (second / 60)) * 6) * (Math.PI) / 180;
double rHours = ((hours + (minute / 60)) * 30) * (Math.PI) / 180;
g.setColor(Color.RED);
g.drawLine(150, 150, 150 + (int) (100 * Math.cos(rSecond - (Math.PI / 2))), 150 + (int) (100 * Math.sin(rSecond - (Math.PI / 2))));
g.setColor(Color.BLACK);
g.drawLine(150, 150, 150 + (int) (70 * Math.cos(rMinute - (Math.PI / 2))), 150 + (int) (70 * Math.sin((rMinute - (Math.PI / 2)))));
g.drawLine(150, 150, 150 + (int) (50 * Math.cos(rHours - (Math.PI / 2))), 150 + (int) (50 * Math.sin(rHours - (Math.PI / 2))));
}
public static void main(String[] args) {
// Swing / AWT GUIs should be created & changed on the EDT ..
Runnable r = () -> {
JFrame frame = new JFrame("Clock 2D");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(330, 330));
Clock2d clock2d = new Clock2d();
clock2d.setPreferredSize(new Dimension(320, 320));
frame.setLayout(new BorderLayout());
frame.getContentPane().add(clock2d, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
};
// .. this is how we ensure that Runnable is on the EDT.
SwingUtilities.invokeLater(r);
}
}
Further tip re fonts:
g.setFont(new Font("Arial", Font.BOLD, 10));
Given the paint method is called repeatedly, it would be best to establish the fonts (both of them) when the class is constructed and store them a attributes of the class (which can be referenced in the methods).
But better to use logical fonts instead of something like 'Arial', like this:
g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 10));
Not only does that provide compile time checking, but it adapts across OS platforms. For example, the SANS_SERIF font would result in Arial on Windows and probably most *nix boxes, but on OS X the default SANS_SERIF (undecorated) font is Helvetica.
The other font, Tahoma, is more problematic. Again it's likely to be present on many Windows boxes, but it might be best to either test for it and have a list of backups, or supply the font with the clock app. (assuming you have distribution rights).
I am using this class :
import com.badlogic.gdx.graphics.g2d.TextureRegion;
public class ParallaxLayer {
// the Texture sitting on this layer
public TextureRegion region;
/**
* how much shall this layer (in percent) be moved if the whole background is moved
* 0.5f is half as fast as the speed
* 2.0f is twice the speed
*/
float ratioX, ratioY;
/**
* current position
*/
float positionX, positionY;
/**
*
* #param pRegion
* #param pRatioX
* #param pRatioY
*/
public ParallaxLayer(TextureRegion pRegion, float pRatioX, float pRatioY) {
region = pRegion;
ratioX = pRatioX;
ratioY = pRatioY;
}
/**
* move this layer
* #param pDelta
*/
protected void moveX(float pDelta) {
positionX += pDelta * ratioX;
}
/**
* move this layer
* #param pDelta
*/
protected void moveY(float pDelta) {
positionY += pDelta * ratioY;
}
}
and this class :
import com.badlogic.gdx.graphics.g2d.TextureRegion;
public class ParallaxLayer {
/**
* the Texture sitting on this layer
*/
public TextureRegion region;
/**
* how much shall this layer (in percent) be moved if the whole background is moved
* 0.5f is half as fast as the speed
* 2.0f is twice the speed
*/
float ratioX, ratioY;
/**
* current position
*/
float positionX, positionY;
/**
*
* #param pRegion
* #param pRatioX
* #param pRatioY
*/
public ParallaxLayer(TextureRegion pRegion, float pRatioX, float pRatioY) {
region = pRegion;
ratioX = pRatioX;
ratioY = pRatioY;
}
/**
* move this layer
* #param pDelta
*/
protected void moveX(float pDelta) {
positionX += pDelta * ratioX;
}
/**
* move this layer
* #param pDelta
*/
protected void moveY(float pDelta) {
positionY += pDelta * ratioY;
}
}
And in main class :
camera=new OrthographicCamera(400,240);
camera.position.x=200;
camera.position.y=120;
camera.update();
batch=new SpriteBatch();
layer1=atlas.findRegion("layer1");
layer2=atlas.findRegion("layer2");
layer3=atlas.findRegion("layer3");
ParallaxLayer l1=new ParallaxLayer(layer1,0,0);
ParallaxLayer l2=new ParallaxLayer(layer2,0.5f,0);
ParallaxLayer l3=new ParallaxLayer(layer3,1,0);
ParallaxLayer[] layers={l1,l2,l3};
background=new ParallaxBackground(layers, camera,batch);
// [...] in render
background.moveX(30*delta); // move to the right to show the effect
background.render();
to achieve parallax scrolling effect but i want infinite scrolling but unable to get it. I tried doing this in ParallaxBackground class under for loop but repeats only three time.
posXbg1L1 = layer.positionX;
posXbg2L1 = posXbg1L1 - layer.region.getRegionWidth();
if (camera.position.x <= posXbg2L1 - camera.viewportWidth / 2) {
// Gdx.app.log("TAG", camera.position.x + ":" + posXbg2L1 + camera.viewportWidth / 2);
posXbg1L1 = posXbg2L1;
}
batch.draw(layer.region, -camera.viewportWidth / 2
- posXbg1L1, -camera.viewportHeight / 2
- layer.positionY);
batch.draw(layer.region, -camera.viewportWidth / 2
- posXbg2L1, -camera.viewportHeight / 2
- layer.positionY);
}
Any psuedocode/code will be helpful.
You could try something like this:
TextureRegion[] backgrounds = [...your array of background textures...];
float[] parallax = {...your parallax coefficients...}; //For example {0.2f, 0.1f}
public void drawLayers(Batch batch, OrthographicCamera camera) {
batch.setColor(Color.WHITE);
for(int b = backgrounds.length - 1; b >= 0; b--) {
TextureRegion background = backgrounds[b];
if(background != null) {
float x = (camera.position.x - camera.viewportWidth / 2f * camera.zoom);
float y = camera.position.y - camera.viewportHeight / 2f * camera.zoom + camera.viewportHeight / 15f * camera.zoom;
float rWidth = camera.viewportWidth * 1.5f * camera.zoom;
float rHeight = (rWidth / background.getRegionWidth()) * background.getRegionHeight();
drawParallaxLayer(batch, background, parallax[b], x, y, rWidth, rHeight);
}
}
}
public static void drawParallaxLayer(Batch batch, TextureRegion region, float parallax, float x, float y, float width, float height) {
for(int j = 0; j < 3; j++) {
batch.draw(region, x + (j * width) - ((x * parallax) % width) - (width / 2f), y, width, height);
}
}
You might have to adjust some of the position/width/height values in the drawLayers function, but the real magic happens in drawParallaxLayer - which should be able to stay the same.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Right now I am working on making the classic game Asteroids. I have gotten the ship to move 360 degrees using the arrow keys. However, when I try to shoot the balls out of the ship at that angle, they only leave at 45 degree increments. I think that means there is something wrong with my math in the ball class:
public Ball(double ballAngle){
angle = ballAngle;
xRatio = Math.cos((angle + 90) * 3.14 / 180);
yRatio = Math.sin((angle + 90) * 3.14 / 180);
xChange = xRatio * speed;
yChange = yRatio * speed;
}
public void update(){
x = (int) Math.round(x + xChange);
y = (int) Math.round(y + yChange);
}
However, I can't seem to find what is going on. I have tried debugging it by printing the values an following them step by step, but still can't solve it. Here is the rest of my code incase you need to see it.
Main Game Class:
package Asteroids;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.ArrayList;
#SuppressWarnings("serial")
public class Asteroids extends JPanel implements KeyListener{
public final static int BOX_WIDTH = 600;
public final static int BOX_HEIGHT = 600;
public final static int UPDATE_RATE = 300;
public final static double shipSpeed = 1;
ArrayList<Ball> balls = new ArrayList<Ball>();
int i = 0;
int ballCount = 0;
boolean spawn = false;
Ship ship = new Ship(BOX_WIDTH / 2,BOX_HEIGHT / 2);
public Asteroids(){
//Set window size
setPreferredSize(new Dimension(BOX_WIDTH,BOX_HEIGHT));
//Start game thread
Thread gameThread = new Thread() {
public void run(){
while(true){
ship.update();
for (int j=0; j<ballCount; j++){
balls.get(j).update();
}
if(spawn){
i++;
}
if(i % 100 == 0){
balls.add(new Ball(ship.getAngle()));
ballCount ++;
}
repaint();
try {Thread.sleep(1000 / UPDATE_RATE);}
catch (InterruptedException ex) {}
}
}
};
gameThread.start();
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, BOX_WIDTH, BOX_HEIGHT);
for (int j=0; j<ballCount; j++){
balls.get(j).draw(g);
}
ship.draw(g);
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT){
ship.setSpeed(-shipSpeed);
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
ship.setSpeed(shipSpeed);
}
if(e.getKeyCode() == KeyEvent.VK_SPACE){
spawn = true;
}
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT){
ship.setSpeed(0);
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
ship.setSpeed(0);
}
if(e.getKeyCode() == KeyEvent.VK_SPACE){
spawn = false;
}
}
public void keyTyped(KeyEvent e) {}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Create Frame
JFrame frame = new JFrame("ASTEROIDS");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Asteroids asteroids = new Asteroids();
frame.setContentPane(asteroids);
frame.setSize(BOX_WIDTH,BOX_HEIGHT);
frame.pack();
frame.addKeyListener(asteroids);
frame.setVisible(true);
}
});
}
public int getBoxHeight(){
return BOX_HEIGHT;
}
public int getBoxWidth(){
return BOX_WIDTH;
}
}
Ship Class:
package Asteroids;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Ship {
Random rng = new Random();
int r = rng.nextInt(256);
int g = rng.nextInt(256);
int b = rng.nextInt(256);
Color color = new Color(r,g,b);
double speed = 0;
double angle = 0;
final static int shipLength = 20;
final static int shipAngle = 40;
static int x;
static int y;
int point1x;
int point2x;
int point3x;
int point1y;
int point2y;
int point3y;
public Ship(int xPos, int yPos){
x = xPos;
y = yPos;
point1x = x;
point2x = (int) Math.round( x - (Math.tan(shipAngle * 6.28 / 360) * shipLength));
point3x = (int) Math.round( x + (Math.tan(shipAngle * 6.28 / 360) * shipLength));
point1y = y - shipLength;
point2y = y + shipLength;
point3y = y + shipLength;
}
public void update(){
angle = angle + speed;
if(angle < 0){
angle = angle + 360;
}
else if(angle >= 360){
angle = angle - 360;
}
}
public void draw(Graphics g) {
g.setColor(color);
point1x = x - (int) Math.round( Math.sin(angle * 6.28 / 360) * shipLength);
point2x = x + (int) Math.round( Math.sin((angle + shipAngle) * 6.28 / 360) * shipLength);
point3x = x + (int) Math.round( Math.sin((angle - shipAngle) * 6.28 / 360) * shipLength);
point1y = y + (int) Math.round( Math.cos(angle * 6.28 / 360) * shipLength);
point2y = y + (int) Math.round( Math.cos((angle + 180 + shipAngle) * 6.28 / 360) * shipLength);
point3y = y + (int) Math.round( Math.cos((angle - 180 - shipAngle) * 6.28 / 360) * shipLength);
int xpoints[] = {point1x, point2x, point3x};
int ypoints[] = {point1y, point2y, point3y};
int npoints = 3;
g.fillPolygon(xpoints, ypoints, npoints);
}
public void setSpeed(double s){
speed = s;
}
public static int getX(){
return x;
}
public static int getY(){
return y;
}
public double getAngle(){
return angle;
}
}
Ball Class:
package Asteroids;
import java.awt.Color;
import java.awt.Graphics;
public class Ball {
int x = Ship.getX();
int y = Ship.getY();
double angle;
double xRatio;
double yRatio;
double xChange;
double yChange;
final static int speed = 1;
final static int diameter = 5;
public Ball(double ballAngle){
angle = ballAngle;
xRatio = Math.cos((angle + 90) * 3.14 / 180);
yRatio = Math.sin((angle + 90) * 3.14 / 180);
xChange = xRatio * speed;
yChange = yRatio * speed;
}
public void update(){
x = (int) Math.round(x + xChange);
y = (int) Math.round(y + yChange);
}
public void draw(Graphics g) {
g.setColor(Color.white);
g.fillOval(x - diameter/2, y - diameter/2, diameter, diameter);
}
}
I would suspect its a rounding error. You're storing x and y as int primitives, but then adding doubles to it, storing it back in the int. If you changed x and y to be doubles, and then round them only before you display the location, you shouldn't have this problem
I have the clock displaying correctly, but I need to write my name in the middle of it and I can't figure out how. Also how to make the hour and minute hands change every time the program runs? I assume I need to make the hour and minute equal to a random number generator?
class StillClock extends JPanel
{
private int hour;
private int minute;
private int second;
private boolean hourHandVisible = true;
private boolean minuteHandVisible = true;
private boolean secondHandVisible = true;
/** Construct a default clock with the current time*/
public StillClock()
{
setCurrentTime();
}
/** Construct a clock with specified hour, minute, and second */
public StillClock(int hour, int minute)
{
this.hour = hour;
this.minute = minute;
//this.second = second;
}
/** Return hour */
public int getHour()
{
return hour;
}
/** Set a new hour */
public void setHour(int hour)
{
this.hour = hour;
repaint();
}
/** Return minute */
public int getMinute()
{
return minute;
}
/** Set a new minute */
public void setMinute(int minute)
{
this.minute = minute;
repaint();
}
/*public int getSecond()
{
return second;
}
public void setSecond(int second)
{
this.second = second;
repaint();
}*/
/** Draw the clock */
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// Initialize clock parameters
int clockRadius = (int)(Math.min(getWidth(), getHeight()) * 0.8 * 0.5);
int xCenter = getWidth() / 2;
int yCenter = getHeight() / 2;
// Draw circle
g.setColor(Color.black);
g.drawOval(xCenter - clockRadius, yCenter - clockRadius,2 * clockRadius, 2 * clockRadius);
// Draw minute hand
if (minuteHandVisible)
{
int mLength = (int)(clockRadius * 0.65);
int xMinute = (int)(xCenter + mLength *Math.sin(minute * (2 * Math.PI / 60)));
int yMinute = (int)(yCenter - mLength *Math.cos(minute * (2 * Math.PI / 60)));
g.setColor(Color. blue);
g.drawLine(xCenter, yCenter, xMinute, yMinute);
}
// Draw hour hand
if (hourHandVisible)
{
int hLength = (int)(clockRadius * 0.5);
int xHour = (int)(xCenter + hLength *Math.sin((hour % 12 + minute / 60.0) * (2 * Math.PI / 12)));
int yHour = (int)(yCenter - hLength *Math.cos((hour % 12 + minute / 60.0) * (2 * Math.PI / 12)));
g.setColor(Color.green);
g.drawLine(xCenter, yCenter, xHour, yHour);
}
// }// Display hours on the clock
g.setColor(Color.red);
for (int i = 0; i < 12; i++)
{
int x = (int)(xCenter + 0.8 * clockRadius * Math.sin (i*(2 * Math.PI / 12)));
int y = (int)(yCenter - 0.8 * clockRadius * Math.cos (i*(2 * Math.PI / 12)));
g.drawString("" + ((i == 0) ? 12 : i), x, y);
}
}
public void setCurrentTime()
{
// Construct a calendar for the current date and time
Calendar calendar =
new GregorianCalendar();
// Set current hour, minute and second
this.hour = calendar.get(Calendar.HOUR_OF_DAY);
this.minute = calendar.get(Calendar.MINUTE);
}
public Dimension getPreferredSize()
{
return new Dimension(800, 800);
}
public boolean isHourHandVisible()
{
return hourHandVisible;
}
public boolean isMinuteHandVisible()
{
return hourHandVisible;
}
public void setHourHandVisible(boolean hourHandVisible)
{
this.hourHandVisible = hourHandVisible;
repaint();
}
public void setMinuteHandVisible(boolean minuteHandVisible)
{
this.minuteHandVisible = minuteHandVisible;
repaint();
}
}
Start by taking a look at Working with Text APIs
But the basics would be something along the lines of
String text = "You're Name Here";
FontMetrics fm = g.getFontMetrics();
int x = (getWidth() - fm.stringWidth(text)) / 2;
int y = ((getHeight()- fm.getHeight()) / 2) + fm.getAscent();
g.drawString(text, x, y);
For a comparison of the concept of "centring text vertically", take a look at this Previous Question
Try Adding this to the bottom of your paintComponent()
// get the FontMetrics for the current font
FontMetrics fm = g.getFontMetrics();
// find the center location to display
int stringWidth = fm.stringWidth("MyName");
int stringAccent = fm.getAscent();
// get the position of the leftmost character in the baseline
int xCoordinate = getWidth() / 2 - stringWidth / 2;
int yCoordinate = getHeight() / 2 + stringAccent / 2;
g.drawString("MyName", xCoordinate, yCoordinate);
I'm struggling with a problem: I want to access openstreetmap via my Java application. I wrote a JComponent which is able to show tiles downloaded from openstreetmap. The problem is that in the formula which calculates the y-position (see FIXME in the sourcecode) of the downloaded picture it is an error and I'm not able to find it. Some parts of the code are copied from http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames. The crazy thing is that the x-position is correct. The goTo() method is used to determine which place of the map should be in the center of the JComponent-View!
package ui;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JComponent;
public class OSMViewer extends JComponent {
private static final long serialVersionUID = 1L;
protected ImageHandler imagehandler = null;
protected int zoomlevel = 0;
protected double center_deg_lon = 0.0;
protected double center_deg_lat = 0.0;
final double DEGY = 85.0511;
final double DEGX = 180.0;
public OSMViewer(ImageHandler imagehandler) {
this.imagehandler = imagehandler;
// TODO
goTo(13, 30.0, 30.0);
}
public void goTo(final int zoom, final double lon, final double lat) {
zoomlevel = zoom;
center_deg_lon = lon;
center_deg_lat = lat;
repaint();
}
// deg
public int getTileNumberX(final int zoom, final double lon) {
int xtile = (int) Math.floor((lon + 180) / 360 * (1 << zoom));
return xtile;
}
// deg
public int getTileNumberY(final int zoom, final double lat) {
int ytile = (int) Math
.floor((1 - Math.log(Math.tan(Math.toRadians(lat)) + 1
/ Math.cos(Math.toRadians(lat)))
/ Math.PI)
/ 2 * (1 << zoom));
return ytile;
}
// deg
public double getLonDegPx(final int zoom) {
double deg_px = 2 * DEGX / (Math.pow(2, zoom) * 256);
return deg_px;
}
// deg
public double getLatDegPx(final int zoom) {
double deg_px = 2 * DEGY / (Math.pow(2, zoom) * 256);
return deg_px;
}
// deg
public int getPxX(final int zoom, final double lon) {
return (int) (((lon + DEGX) / (2 * DEGX)) * Math.pow(2, zoom) * 256);
}
// deg
public int getPxY(final int zoom, final double lat) {
return (int) (((DEGY - lat) / (2.0 * DEGY)) * Math.pow(2.0, zoom) * 256.0);
}
public void paintComponent(Graphics g) {
int x = getTileNumberX(zoomlevel, center_deg_lon);
int y = getTileNumberY(zoomlevel, center_deg_lat);
String str = ("" + zoomlevel + "/" + x + "/" + y);
System.out.println(str);
int xpos = (x * 256) - getPxX(zoomlevel, center_deg_lon)
+ (getWidth() / 2);
// FIXME
int ypos = (y * 256) - getPxY(zoomlevel, center_deg_lat)
+ (getHeight() / 2);
Image image = imagehandler.getImage(str);
if (image != null) {
g.drawImage(image, xpos, ypos, this);
}
g.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
}
}
Nice to hear that you were able to fix your problem :)
Please also note, that OSM runs on donated ressources and has restrictions on how people access the rendererd map tiles: http://wiki.openstreetmap.org/wiki/Tile_usage_policy Please pay attention that your app respects it, to avoid stressing the community servers.