I have created a custom Path2D class to draw an H-shaped "calliper" on screen, for a project I am doing. I want to drag and eventually resize the calliper on screen. I have managed to get the Path2D set up so I can draw the calliper, and the code looks like this:
Declaration and Constructor:
public class Calliper extends Path2D.Double
{
// X and Y coordinates of all six points on Calliper
double cX1, cX2, cX3, cX4, cX5, cX6;
double cY1, cY2, cY3, cY4, cY5, cY6;
// Width and Height
double cWidth;
double cHeight;
public Calliper(double x, double y, double w, double h)
{
cWidth = w;
cHeight = h;
cX1 = x;
cY1 = y;
cX2 = x;
cY2 = y + (h/2);
cX3 = x;
cY3 = y + h;
cX4 = x + w;
cY4 = y;
cX5 = cX4;
cY5 = cY4 + (h /2);
cX6 = cX4;
cY6 = cY4 + h;
build();
}
build() method (used to draw the path) and setCalliper() method, used to redefine the coordinates, or width, height:
private void build()
{
// Draw the path for the calliper
moveTo(cX1, cY1);
lineTo(cX2, cY2);
lineTo(cX3, cY3);
moveTo(cX2, cY2);
lineTo(cX5, cY5);
moveTo(cX4, cY4);
lineTo(cX6, cY6);
}
public void setCalliper(double x, double y, double w, double h)
{
// Rebuild the calliper using different x,y coordinates, or
// different width/height
cWidth = w;
cHeight = h;
cX1 = x;
cY1 = y;
cX2 = x;
cY2 = y + (h/2);
cX3 = x;
cY3 = y + h;
cX4 = x + w;
cY4 = y;
cX5 = cX4;
cY5 = cY4 + (h /2);
cX6 = cX4;
cY6 = cY4 + h;
build();
}
I have created a class to draw this calliper on the screen, which it will do, however if I try to drag the calliper around the screen, it doesn't erase the original shape as I drag, so I get a long trail of shapes left behind. I thought I had omitted super.paintComponent(g) from my paintComponent(Graphics g) method, but even with it in there the code still does not work.
My drag method looks like this:
#Override
public void mouseDragged(MouseEvent ev)
{
double mx = ev.getX();
double my = ev.getY();
if (dragging)
{
calX = mx - offsetX;
calY = my - offsetY;
cal = setCalliper(calX, calY, calW, calH);
repaint();
}
}
If I change the line cal = setCalliper(calX, calY, calW, calH); above to read cal = new Calliper(calX, calY, calW, calH); then it works, but I have been told I shouldn't do it this way.
Any ideas why it doesn't work as expected?
The setCalliper() directly calls the build method, a method which appends new points to all the previous points added to the Path2D - so each time mouseDragged is called more points are added to the Path. Try calling reset() before calling build() (or call reset in the build method before the moveTo/lineTo calls).
Related
Say I had a 2d side view type game. In this game I have sprites and other objects. The sprite jumps when you click spacebar. The jumping and other things are affected by gravity. I'd have a Gravity class that requires the parameters of an x & y coordinate of the object it's affecting. When its constructed from the Sprite class, I'd give it the x and y of the sprites location as parameters. Then, the gravity class does the necessary math and now has a modified x & y coordinate. How can I update the old x & y in the Sprite class (which is the invoking class) to the new coordinate pair calculated by Gravity (the object which needs to modify the variables in Sprite)?
Extra info:
The x & y variables can't be static. This is all on one thread currently(with the exception of the graphics thread that draws). I could make more threads if needed. I have a swing Timer in the gravity class that starts when the object is created, and is used to calculate the coordinate as an effect of time, velocity, acceleration, etc.
Gravity Class Code:
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Gravity implements ActionListener {
final double gravAccel = -32.174;
double velocity; // in FPS
double angle; // in degrees
double x; // centralized location of object in feet
double y; // centralized location in feet
double time = 0;
Timer timer;
boolean fired = true;
Point start;
public Gravity(double x, double y, double velocity, double angle, Point start) {
this.x = x;
this.y = y;
this.velocity = velocity;
this.angle = angle;
this.start = start;
initTimer();
}
void initTimer() {
timer = new Timer(10, this);
timer.start();
}
public void fire(double velocity, double angle) {
//timer.start();
x = (velocity * Math.cos(Math.toRadians(angle))) * time + start.getX();
y = 0.5 * gravAccel * Math.pow(time, 2) + (velocity * Math.sin(Math.toRadians(angle))) * time + start.getY();
System.out.println("Time:" + time + " " + x + "," + y);
}
#Override
public void actionPerformed(ActionEvent e) {
time = time + 0.01;
if (fired == true) {
fire(velocity, angle);
}
}
}
Sprite:
public class Sprite {
double x = 10; //how can I modify these from gravity
double y = 10;
Sprite() {
new Gravity(x, y, 100, 45, new Point(0,0));
}
}
Keep a reference to the Sprite in Gravity:
private Sprite;
public Gravity(double x, double y, double velocity, double angle, Point start, Sprite sprite) {
this.sprite = sprite;
...
}
and just pass this from Sprite when you create it:
Sprite() {
new Gravity(x, y, 100, 45, new Point(0,0), this);
}
You could just make x and y public:
public double x = 10;
public double y = 10;
And then access them directly from the sprite class.
Hello I have an app where there are circles floating around. At the moment the don't float around, which is the problem. I want them to slowly move around in random directions. How can I do this?
Here is my circle class:
public class data {
public int x,y, size,id;
public data(int x,int y){
this.x = x;
this.y = y;
size = new Random().nextInt(50);
id = new Random().nextInt(10);
}
public void tick(){
}
public void render(Graphics g){
g.setColor(new Color(38,127,0));
g.fillOval(x, y, size, size);
g.setColor(Color.black);
g.drawOval(x, y, size, size);
}
}
You can have a very random movement by adding a random value to x and to y every tick:
private Random random = new Random();
public void tick() {
x = x + random.nextFloat();
y = y + random.nextFloat();
}
This will result in a very fuzzy motion.
Another option is to have 2 variables: motionX and motionY. Those get added to x and y every tick, after which you add random values to motionX and motionY:
private Random random = new Random();
private float xMotion = 0f, yMotion = 0f;
private float factor = 0.5f; //just a value to reduce speed
private void tick() {
x = x + xMotion;
y = y + yMotion;
xMotion = xMotion + random.nextFloat() * factor;
yMotion = yMotion + random.nextFloat() * factor;
}
First of all, I think you messed up which one you should random, you random selected a size and the id(what is this for anyways?), not the x,y value. Also, I don't know why, but it seems that the render program must be called paint.
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 8 years ago.
Improve this question
I have a class Demo with a button and when the user clicks the button called polygon a polygon is drawn starting from the point where they hit, The code works fine in drawing but unfortunately it draws the polygon in the wrong place.
The PolygonShape Class
class PolygonShape {
int x, y;
private Polygon p;
public PolygonShape(int x, int y) {
// the x, y sent to this constructor
//are the cordinates of the point where the user clicked
this.x = x;
this.y = y;
}
public void draw(Graphics g) {
p = new Polygon();
for (int i = 0; i < 5; i++)
p.addPoint((int) (x + y * Math.cos(i * 2 * Math.PI / 5)),
(int) (x + y * Math.sin(i * 2 * Math.PI / 5)));
g.drawPolygon(p);
}
}
Assuming x and y are the center of the polygon, you're using them wrong (you need to add x to the x coordinate and y to the y coordinate) and you're missing another important variable: r for radius. Instead of multiplying by y, you should multiply by r in your formulae.
In other words:
class PolygonShape {
int x, y, r;
private Polygon p;
public PolygonShape(int x, int y, int r) {
this.x = x;
this.y = y;
this.r = r;
}
// Provide a default radius of 100 pixels if no radius is given.
public PolygonShape(int x, int y) {
this(x, y, 100);
}
public void draw(Graphics g) {
p = new Polygon();
for (int i = 0; i < 5; i++) {
double angle = i * 2 * Math.PI / 5;
p.addPoint((int) (x + r * Math.cos(angle)),
(int) (y + r * Math.sin(angle)));
}
g.drawPolygon(p);
}
}
Another option is to set the translation on the graphics before drawing:
final Graphics2D g2 = (Graphics2D)g.create();
g2.translate(x, y);
g2.drawPolygon(p);
You may need to do -x, -y, you'll have to try it.
I am working on a new graphics object (g2) so that the translate is not permanent.
Advantage is, can draw same shape in multiple places, just vary x and y.
I have a point following the path of a circle, and at a determined time, I want that point to "break" off and travel along the tangent line. How do I find this? I've been told that the derivative is
x = -sin(time)
and
y = -sin(time)
(not sure if I understand the "time" part of what I was told), but I don't see how that is enough to get my point to travel along this line. Any tips? Here is what I have currently.
/*
Rotor draws circle for random period of time, then moves
in a straight direction for a random period of time, beginning a
new circle
*/
Rotor r;
float timer = 0;
boolean freeze = false;
void setup() {
size(1000, 600);
smooth();
noFill();
frameRate(60);
background(255);
timeLimit();
r = new Rotor(100, 100, random(40, 100));
}
void draw() {
timer = timer + frameRate/1000;
if(timer > timeLimit()) {
timer = 0;
timeLimit();
if(freeze == true) {
freeze = false;
} else {
freeze = true;
}
}
if(!freeze) {
r.drawRotor();
} else {
r.holdSteady();
}
}
float timeLimit() {
float timeLimit = random(100);
return timeLimit;
}
Rotor Class:
class Rotor {
color c;
int thickness;
float xPoint;
float yPoint;
float nXPoint;
float nYPoint;
float radius;
float angle = 0;
float centerX;
float centerY;
float pointSpeed = frameRate/100;
Rotor(float cX, float cY, float rad) {
c = color(0);
thickness = 1;
stroke(c);
strokeWeight(thickness);
centerX = cX;
centerY = cY;
radius = rad;
}
void drawRotor() {
angle = angle + pointSpeed;
xPoint = centerX + cos(angle) * radius;
yPoint = centerY + sin(angle) * radius;
ellipse(xPoint, yPoint, thickness, thickness);
strokeWeight(2);
ellipse(centerX, centerY, 5, 5);
}
void holdSteady() {
xPoint = -sin(angle);//need tangent of circle
yPoint = -cos(angle);
ellipse(xPoint, yPoint, 4, 4);
//then set new center x and y
}
void drawNewRotor(float cX, float cy, float rad) {
}
}
You can use tan()
int f =100;
size(300,300);
stroke(0);
translate(width/2, height/2);
for(int i = 0; i< 360; i++){
point(cos(radians(i))*f,sin(radians(i))*f);
point(f,tan(radians(i))*f);
point(tan(radians(i))*f,f);
}
I'm having issues with the balls that I display in my JFrame window. Here's the main idea of my application:
Point object (with coordinates x and y) --> Vector object (a class I wrote that has the x and y components of a vector, as well as a few methods... gets its location and head/tail points from the Point object) --> Ball object (the position, velocity, and acceleration vectors are collected in an ArrayList, also has radius and color attributes) --> ContainerBox object (contains the balls, defines the min/max x and y for collision detection purposes).
I'm working toward having one ball centered in the window and the other orbiting the first, but right now I'm just trying to get my objects to play nicely. I'm very new to OOP principles and this is the first time I've written a program using classes in this way.
Everything works perfectly, the JFrame comes up and displays the balls... the problem is that the balls won't show up in the right places. No matter what I put in for the x and y coordinates of the balls (either explicitly or using the objects), they always show up in the upper left-hand corner of the screen. Here's a pic of what I get: Picture Here
I don't know whether it's the vectors or the collision detection or what... any ideas? Thanks a lot for reading and replying!
EDIT: Here's some of the code that I'm using (sorry to put so much, I have no idea where the problem is):
EDIT AGAIN: Added the ball class that I forgot.
package chaneyBouncingBall;
import java.util.*;
public class Point
{
float x;
float y;
public Point(float x, float y)
{
this.x = x;
this.y = y;
}
}
package chaneyBouncingBall;
import java.util.ArrayList;
public class Chaney2DVector
{
float x;
float y;
Point fromLocation;
public Chaney2DVector(float x,
float y)
{
this.x = x;
this.y = y;
}
public Chaney2DVector(Point point1,
Point point2)
{
fromLocation = new Point(point1.x, point1.y);
this.x = point2.x - point1.x;
this.y = point2.y - point1.y;
}
}
package chaneyBouncingBall;
import java.awt.*;
import java.util.*;
public class Ball
{
float x, y;
float velX, velY;
float accelX, accelY;
float radius;
private Color color;
public Ball(float x, float y, float velX,
float velY, float accelX,
float accelY, float radius,
Color color)
{
Chaney2DVector position = new Chaney2DVector(x, y);
Chaney2DVector velocity = new Chaney2DVector(velX, velY);
Chaney2DVector acceleration = new Chaney2DVector(accelX, accelY);
ArrayList posVelAcc = new ArrayList();
posVelAcc.add(position);
posVelAcc.add(velocity);
posVelAcc.add(acceleration);
this.radius = radius;
this.color = color;
}
public void draw(Graphics g)
{
g.setColor(color);
g.fillOval((int)(x - radius), (int)(y - radius),
(int)(2 * radius), (int)(2 * radius));
}
public void moveOneStepWithCollisionDetection( ContainerBox box)
{
float ballMinX = box.minX + radius;
float ballMinY = box.minY + radius;
float ballMaxX = box.maxX - radius;
float ballMaxY = box.maxY - radius;
x = x + velX;
y = y + velY;
if (x < ballMinX)
{
velX = -velX;
x = ballMinX;
}
else if (x > ballMaxX)
{
velX = -velX;
x = ballMaxX;
}
if (y < ballMinY)
{
velY = -velY;
y = ballMinY;
}
else if (y > ballMaxY)
{
velY = -velY;
y = ballMaxY;
}
}
}
package chaneyBouncingBall;
import java.awt.*;
/**
* A rectangular container box, containing the bouncing ball.
*/
public class ContainerBox {
int minX, maxX, minY, maxY; // Box's bounds (package access)
private Color colorFilled; // Box's filled color (background)
private Color colorBorder; // Box's border color
private static final Color DEFAULT_COLOR_FILLED = Color.BLACK;
private static final Color DEFAULT_COLOR_BORDER = Color.YELLOW;
/** Constructors */
public ContainerBox(int x, int y, int width, int height, Color colorFilled, Color colorBorder) {
minX = x;
minY = y;
maxX = x + width - 1;
maxY = y + height - 1;
this.colorFilled = colorFilled;
this.colorBorder = colorBorder;
}
/** Constructor with the default color */
public ContainerBox(int x, int y, int width, int height) {
this(x, y, width, height, DEFAULT_COLOR_FILLED, DEFAULT_COLOR_BORDER);
}
/** Set or reset the boundaries of the box. */
public void set(int x, int y, int width, int height) {
minX = x;
minY = y;
maxX = x + width - 1;
maxY = y + height - 1;
}
/** Draw itself using the given graphic context. */
public void draw(Graphics g) {
g.setColor(colorFilled);
g.fillRect(minX, minY, maxX - minX - 1, maxY - minY - 1);
g.setColor(colorBorder);
g.drawRect(minX, minY, maxX - minX - 1, maxY - minY - 1);
}
}
package chaneyBouncingBall;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
/**
* The control logic and main display panel for game.
*/
public class BallWorld extends JPanel {
private static final int UPDATE_RATE = 50; // Frames per second (fps)
private Ball ball; // A single bouncing Ball's instance
private Ball ball2;
private ContainerBox box; // The container rectangular box
private DrawCanvas canvas; // Custom canvas for drawing the box/ball
private int canvasWidth;
private int canvasHeight;
/**
* Constructor to create the UI components and init the game objects.
* Set the drawing canvas to fill the screen (given its width and height).
*
* #param width : screen width
* #param height : screen height
*/
public BallWorld(int width, int height) {
canvasWidth = width;
canvasHeight = height;
boolean stationary = true;
Random rand = new Random();
int angleInDegree = rand.nextInt(360);
int radius = 50;
int radius2 = 25;
// double accelAngle;
float x1 = rand.nextInt(canvasWidth - radius * 2 - 20) + radius + 10;
float y1 = rand.nextInt(canvasHeight - radius * 2 - 20) + radius + 10;
float x2 = rand.nextInt(canvasWidth - radius * 2 - 20) + radius + 10;
float y2 = rand.nextInt(canvasHeight - radius * 2 - 20) + radius + 10;
// float x = 100;
// float y = 100;
float velX1 = 0;
float velY1 = 0;
float accelX1 = 0;
float accelY1 = 0;
float velX2 = 0;
float velY2 = 0;
float accelX2 = 0;
float accelY2 = 0;
ball = new Ball(canvasWidth / 2, canvasHeight / 2, velX1, velY1, accelX1, accelY1,
radius, Color.BLUE);
ball2 = new Ball(x2, y2, velX2, velY2, accelX2, accelY2, radius / 5, Color.YELLOW);
// Init the Container Box to fill the screen
box = new ContainerBox(0, 0, canvasWidth, canvasHeight, Color.BLACK, Color.WHITE);
// Init the custom drawing panel for drawing the game
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
// Handling window resize.
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
Component c = (Component)e.getSource();
Dimension dim = c.getSize();
canvasWidth = dim.width;
canvasHeight = dim.height;
// Adjust the bounds of the container to fill the window
box.set(0, 0, canvasWidth, canvasHeight);
}
});
// Start the ball bouncing
gameStart();
}
/** Start the ball bouncing. */
public void gameStart() {
// Run the game logic in its own thread.
Thread gameThread = new Thread() {
public void run() {
while (true) {
// Execute one time-step for the game
gameUpdate();
// Refresh the display
repaint();
// Delay and give other thread a chance
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException ex) {}
}
}
};
gameThread.start(); // Invoke GaemThread.run()
}
/**
* One game time-step.
* Update the game objects, with proper collision detection and response.
*/
public void gameUpdate() {
ball.moveOneStepWithCollisionDetection(box);
ball2.moveOneStepWithCollisionDetection(box);
}
/** The custom drawing panel for the bouncing ball (inner class). */
class DrawCanvas extends JPanel {
/** Custom drawing codes */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // Paint background
// Draw the box and the ball
box.draw(g);
ball.draw(g);
ball2.draw(g);
// Display ball's information
g.setColor(Color.WHITE);
g.setFont(new Font("Courier New", Font.PLAIN, 12));
// g.drawString("Ball " + ball.toString(), 20, 30);
}
/** Called back to get the preferred size of the component. */
#Override
public Dimension getPreferredSize() {
return (new Dimension(canvasWidth, canvasHeight));
}
}
}
package chaneyBouncingBall;
import javax.swing.JFrame;
public class Main
{
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame("Matt Chaney's Gravity App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new BallWorld(550, 450));
frame.pack();
frame.setVisible(true);
}
});
}
}
In the constructor of your Ball class, you don't assign all the instance variables to their parameters, these need to be added.
public Ball(float x, float y, float velX, float velY, float accelX, float accelY, float radius, Color color) {
...
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.accelX = accelX;
this.accelY = accelY;
}