Java - Slick - Fill Rectangle on Click - java

I am trying to fill a rectangle on the nearest 10th pixel with a 50x50 size. Whenever this code executes, it shows me the numbers in the syso so I know the locations are being calculated correctly. However, the rectangle does not appear. I have a grid drawn but the squares aren't being drawn correctly. What am I doing wrong? I'm not getting any Stack Traces from errors or something like that...
if(gc.getInput().isMousePressed(0)){
float f1 = (float) Math.ceil(gc.getInput().getMouseX() / 16 * 10);
float f2 = (float) Math.ceil(gc.getInput().getMouseY() / 12 * 10);
gc.getGraphics().fillRect(f1, f2, 50, 50);
System.out.println("Filled: " + f1 + "x" + f2);
}

This is my solution, based on your code:
package game;
import entity.Block;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
import world.Camera;
import world.World;
import java.util.ArrayList;
import java.util.List;
public class TestState extends BasicGameState {
/**
* This variable sets
* the gird size, and the block's
* size.
*/
private final int size = 50;
/**
* This list contains/stores the blocks
* who going to be rendered.
*/
private final List<Block> blocks = new ArrayList<>();
#Override
public int getID() {
return 0;
}
#Override
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException {
}
#Override
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {
/**
* DRAW THE GRID
*
* This can be confusing
* for the first look, but its logical.
*/
g.setColor(Color.white);
for (int i = 0; i < 50; i++) {
float y = i * size;
float x = 0;
g.drawLine(x, y, gc.getWidth(), y);
for (int i2 = 0; i2 < 50; i2++) {
float x2 = i2 * size;
g.drawLine(x2, y, x2, gc.getHeight());
}
}
// DRAW EACH BLOCKS (this is a for-each loop)
for (Block block : blocks) {
block.render(gc, g);
}
}
#Override
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
// ADD NEW BLOCK IF MOUSE PRESSED
if (gc.getInput().isMouseButtonDown(0)) {
// get the x and y positions
float x = (float) Math.ceil(gc.getInput().getMouseX() / size * size);
float y = (float) Math.ceil(gc.getInput().getMouseY() / size * size);
/**
* The block class has a
* special constructor because
* I built it for my game.
* You should build your own.
*
* The block is *size by *size sized :D
* I mean the *size is the variable.
* Ohh, and it's uses the x & y positions.
*/
blocks.add(new Block(new World(new Camera()), new Camera(), new Rectangle(x, y, size, size)));
}
}
}
The output:

Related

Calculate the padding to center-align a rectangle (resized by percentage)

Below is my current algorithm to align the rectangle (representing symbol) in the center of the canvas space (representing icon). It is only the algorithm I am interested in so ignore the rest of the code as it is merely for demonstration purposes as a visual aid.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class IconSymbol extends JFrame {
public IconSymbol(double iWH, double s, double w, double h) {
getContentPane().add(new Canvas((int)iWH, s, w, h));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize((int)iWH, (int)iWH);
setVisible(true);
}
public static void main(String arg[]) {
IconSymbol is = new IconSymbol(100, 0.9, 50, 50);
}
class Canvas extends JPanel {
// STIPULATED
double iconWH = 0;
double sScale = 0;
double sWidth = 0;
double sHeight = 0;
// CALCULATED
double padX = 0;
double padY = 0;
double xOffSet = 0;
double yOffSet = 0;
public Canvas(double iWH,double sS,double sW,double sH) {
this.iconWH = iWH;
this.sScale = sS;
this.sWidth = sW;
this.sHeight = sH;
}
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.setBackground(Color.WHITE);
g2D.setPaint(Color.BLUE);
Shape icon = new Rectangle.Double(0,0,(int)iconWH,(int)iconWH);
g2D.fill(icon);
g2D.setPaint(Color.BLACK);
int width = (int)iconWH / 10;
int height= (int)iconWH / 10;
for(int row=0;row<10;row++){
for(int col=0;col<10;col++){
g.drawRect(row*width,col*height,width,height);
}
}
Point off = algorithm();
g2D.setPaint(Color.RED);
Shape s = new Rectangle.Double(off.x,off.y,(int)sWidth,(int)sHeight);
AffineTransform tran = AffineTransform.getScaleInstance(sScale, sScale);
g2D.fill(tran.createTransformedShape(s));
}
public Point algorithm(){
// ALGORITHM WITH EXACT NEEDED PARAMETERS
padX = (sWidth - ((sWidth * sScale))) / 2;
padY = (sHeight - ((sHeight * sScale))) / 2;
xOffSet = padX + ((iconWH - (sWidth * sScale)) / 2);
yOffSet = padX + ((iconWH - (sHeight * sScale)) / 2);
Point point = new Point((int)xOffSet, (int)yOffSet);
return point;
}
}
}
The problem with your code is that the scale transform tran is scaling the calculated origin of the rectangle, off, as well as sWidth and sHeight. If you want to keep with your current scheme you need to apply the inverse of the scale transform to the calculated offset in your algorithm method:
public Point algorithm(){
// ALGORITHM WITH EXACT NEEDED PARAMETERS
xOffSet = ((iconWH - (sWidth * sScale)) / 2) / sScale;
yOffSet = ((iconWH - (sHeight * sScale)) / 2) / sScale;
Point point = new Point((int)xOffSet, (int)yOffSet);
return point;
}
Note that I removed padX and padY as they weren't required for calculating the offset.

Why is JavaFX canvas sometimes failing to draw and breaking my program?

This is my first question here so take it easy ;)
Ok so, I am trying to make a game in Java completely from scratch. The problem I am having at the moment is drawing on a canvas. So essentially the game takes place in a hexagonal grid, so I am trying to draw a hexagonal grid over the screen. The problem is that sometimes (Maybe half the time) the grid doesn't fully render and everything breaks. Upon clicking play game from the main menu, the user should be greeted with a game screen, which is for now just a canvas. A hexagon grid is immediately drawn. When testing with a 10 x 10 hexagonal grid, some hexagons on the right side (that are rendering last) flicker for a few seconds and then either stop flickering and everything works (I can zoom) or they disappear completely and I can no longer zoom. With a 90 x 90 grid, I can't see any flickering as it is likely off-screen, but zooming in/out never works.
Game.java
public class Game {
private static Game ourInstance = new Game();
public static Game getInstance() {
return ourInstance;
}
public final float MIN_SIZE = 64.0f;
public final float MAX_SIZE = 512.0f;
public final float SCROLL_MULTIPLIER = 0.2f;
private float size;
private Point gridPosition;
private HexGrid hexGrid;
public GraphicsContext gc;
private Timer timer = new Timer();
private Game() {
}
public void startGame(GraphicsContext gc) {
hexGrid = new HexGrid(HexHelper.GRID_ORIENTATION.POINTY, HexHelper.GRID_SIZE.OPEN_SPACE);
size = 128.0f;
gridPosition = new Point(0.0f, 0.0f);
runGame(gc);
}
public void runGame(GraphicsContext gc) {
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
updateGame(gc);
}
}, 0, 1000L / 60L);
}
public void updateGame(GraphicsContext gc) {
repaintGame(gc);
}
public void repaintGame(GraphicsContext gc) {
gc.clearRect(0, 0, 1920, 1080);
gc.setStroke(Color.BLACK);
//TODO change with zoom
gc.setLineWidth(5.0);
hexGrid.drawGrid(gc, size);
}
public void zoomCamera(double delta) {
if(size >= MIN_SIZE && size <= MAX_SIZE) {
size += delta * SCROLL_MULTIPLIER;
size = Math.max(MIN_SIZE, Math.min(MAX_SIZE, size));
}
System.out.println(size);
}
}
HexGrid.java
package hexlib;
import javafx.scene.canvas.GraphicsContext;
public class HexGrid {
private HexHelper.GRID_ORIENTATION orientation;
private Hexagon[][] grid;
public HexGrid(HexHelper.GRID_ORIENTATION o, HexHelper.GRID_SIZE s) {
orientation = o;
generateGrid(s);
}
public void generateGrid(HexHelper.GRID_SIZE s) {
int tiles;
switch (s) {
case OPEN_SPACE:
tiles = 90;
break;
case PLANETARY_ORBIT:
tiles = 10;
break;
default:
tiles = 1;
}
grid = new Hexagon[tiles][tiles];
for (int i = 0; i < tiles; i++) {
for (int j = 0; j < tiles; j++) {
grid[j][i] = new Hexagon(new OffsetCoord(j, i));
}
}
}
public void drawGrid(GraphicsContext gc, float size) {
Point[] points;
for (Hexagon[] row: grid) {
for (Hexagon h : row) {
//Gets the coordinates of vertices of the hexagon located at the given coordinate
points = HexHelper.evenRToPixelHexagonVertices(h.getOffsetCoord(), size);
double[] xPoints = new double[]{points[0].x, points[1].x, points[2].x, points[3].x, points[4].x, points[5].x};
double[] yPoints = new double[]{points[0].y, points[1].y, points[2].y, points[3].y, points[4].y, points[5].y};
gc.strokePolygon(xPoints, yPoints, 6);
}
}
}
public Hexagon[][] getGrid() {
return grid;
}
}
HexHelper.java
package hexlib;
import utils.ExtendedMath;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HexHelper {
public enum GRID_ORIENTATION {
POINTY,
FLAT;
}
public enum GRID_SIZE {
OPEN_SPACE,
PLANETARY_ORBIT,
LARGE_PLANET,
SMALL_PLANET,
ONE;
}
public static Point evenRToPixelHexagonCenter(OffsetCoord o, float size) {
float x, y;
//If row is odd, x = column + 1 (times size)
//Else x = column + 1/2 (times size)
if (o.getCoords()[1] % 2 == 0) {
x = (o.getCoords()[0] + 1.0f) * size;
}
else {
x = (o.getCoords()[0] + 0.5f) * size;
}
//0.75 is 3/4 height between each hexagon
//0.5 is 1/2 height that inherently exists between the top of the first row and their centers
y = (o.getCoords()[1] * 0.75f * size) + (0.5f * size);
return new Point(x, y);
}
public static Point[] evenRToPixelHexagonVertices(OffsetCoord o, float size) {
float x, y;
Point[] points = new Point[6];
Point centerPoint = evenRToPixelHexagonCenter(o, size);
points[0] = new Point(centerPoint.x + (0.00f * size), centerPoint.y + (0.50f * size));
points[1] = new Point(centerPoint.x + (0.50f * size), centerPoint.y + (0.25f * size));
points[2] = new Point(centerPoint.x + (0.50f * size), centerPoint.y - (0.25f * size));
points[3] = new Point(centerPoint.x + (0.00f * size), centerPoint.y - (0.50f * size));
points[4] = new Point(centerPoint.x - (0.50f * size), centerPoint.y - (0.25f * size));
points[5] = new Point(centerPoint.x - (0.50f * size), centerPoint.y + (0.25f * size));
return points;
}
}
gc is a GraphicsContext created in the JavaFX application and passed into Game.getInstance().startGame()
Any help is appreciated, and thank you in advance for your help

Need to draw projectile motion of a thrown ball

So I'm writing a code that allows a user to throw an imaginary object at an initial angle and speed to see if they can come close to hitting a ball (that is positioned based on user input).
However, I'm having trouble drawing the curve of the users inputted angle and speed of the imaginary object.
I've used a mathematical formula to calculate the total time and range of said object. That is:
π‘Ÿπ‘Žπ‘›π‘”π‘’= 𝑣02sin⁑(2πœƒπœ‹/180)𝑔
π‘‘π‘œπ‘‘π‘Žπ‘™ π‘‘π‘–π‘šπ‘’= 2𝑣0sin⁑(πœƒπœ‹/180)𝑔
I've already tried attempting to put range and total time into an arc and plotting it that way. But that didn't seem to work.
Here's the code:
import java.awt.AWTEvent;
import java.awt.*;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.util.Scanner;
import java.awt.geom.QuadCurve2D;
public class BallGame extends JFrame {
public static void main (String[]args)
{
Scanner cool= new Scanner(System.in);
double angle, speed, range, totalTime;
{
JFrame frame = new JFrame (" Throwing Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,700);
}
{
System.out.println("Please enter the location of the ball (0 < X < 1)");
StdDraw.setPenRadius(0.06);
StdDraw.setPenColor(StdDraw.BLUE);
double x, y;
y = 0;
x = cool.nextDouble();
StdDraw.point(x, y);
}
System.out.println("Please enter an angle of your choosing:");
angle = cool.nextDouble();
System.out.println("Please enter the speed at wish you which to throw the ball");
speed = cool.nextDouble();
double g;
g = 9.8;
range = Math.pow(speed, 2) * Math.sin(2 * angle * (Math.PI / 180) / g);
totalTime = (2 * speed * Math.sin(angle * Math.PI / 180)) / g;
For drawing a curve you need to calculate horizontal (x) and vertical (y) position, as a function of time, start point, start speed and angle.
In other words, calculate the horizontal distance, and vertical distance.
The equations are well known and widely available.
You use these equations to repeatedly calculate x,y and then repaint.
See the following demonstration. Not the comments :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BalisticCurve extends JFrame {
private static final double G = 9.8; //positive because Y axis is positive going down
private int animationSpeed = 5; //millis. The smaller the faster
private static int size = 900, ballDiameter = 10;
private double startX, startY, ballX, ballY;
private double xSpeed, ySpeed, lastPointX, lastPointY;
private double time, deltaTime = 0.01 ; //in seconds
private List<Point2D> curvePoints= new ArrayList<>();
private Timer timer;
BalisticCurve(){
super("Balistic Curve");
DrawBoard board = new DrawBoard();
add(board, BorderLayout.CENTER);
ballX= lastPointX = startX = 50;
ballY = lastPointY = startY = size - 100;
getUserInput();
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
timer = new Timer(animationSpeed, new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
board.moveBall();
board.repaint();
if(! inBounds()) {
timer.stop();
}
}
});
timer.start();
}
private void getUserInput() {
double angle = 45;//todo replace with user input + verification
double speed = 100;
xSpeed = speed * Math.cos(angle * (Math.PI / 180));
ySpeed = speed * Math.sin(angle * (Math.PI / 180));
}
private boolean inBounds() {
//ignore if ball exceeds height
if((ballX < 0) || (ballX > (getWidth()))
|| ( ballY > (getHeight() - ballDiameter) ) ) {
return false;
}
return true;
}
class DrawBoard extends JPanel {
public DrawBoard() {
setPreferredSize(new Dimension(size, size));
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.RED);
g2d.fillOval((int)ballX,(int)ballY,ballDiameter,ballDiameter);
if((Math.abs(lastPointX - ballX)>=1) && (Math.abs(lastPointY - ballY)>=1) ) {
curvePoints.add(new Point2D.Double(ballX, ballY));
lastPointX = ballX; lastPointY = ballY;
}
drawCurve(g2d);
}
private void drawCurve(Graphics2D g2d) {
g2d.setColor(Color.BLUE);
for(int i=0; i < (curvePoints.size()-1); i++) {
Point2D from = curvePoints.get(i);
Point2D to = curvePoints.get(i+1);
g2d.drawLine((int)from.getX(),(int)from.getY(), (int)to.getX(), (int)to.getY());
}
}
private void moveBall() {
ballX = startX + (xSpeed * time);
ballY = startY - ((ySpeed *time)-(0.5 *G * Math.pow(time, 2))) ;
time += deltaTime;
}
}
public static void main(String[] args) {
new BalisticCurve();
}
}
Don't hesitate to ask what is not clear enough.

while loop loops just once - java

Why my while loop is looping just once ? It should loops 99 times. Could Thread.sleep method break this loop or repaint ? Can you help me resolve this ? It doesn't show any errors. And i am using netbeans.
Licznik.java:
import javax.swing.JApplet;
public class Licznik extends JApplet {
#Override
public void init() {
setSize(900,900);
PanelLicznik pl=new PanelLicznik();
add(pl);
}
}
PanelLicznik.java:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.*;
import java.awt.geom.Line2D;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class PanelLicznik extends JPanel implements Runnable
{
int srodek = 450;
Image bg;
int a = 400, t = 0, v = 0, i = 0;
double x = 152, y = 756;
public PanelLicznik() {
Thread watek1 = new Thread(this);
watek1.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(900, 900);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
bg = new ImageIcon(this.getClass().getResource("s.gif")).getImage();
g2.drawImage(bg,0,0,null);
Line2D wsk = new Line2D.Double(srodek,srodek,x,y);
g2.setColor(new Color(255,255,255));
g2.setStroke(new BasicStroke(15.0f,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER));
g2.draw(wsk);
}
#Override
public void run() {
t = 3;
v = 100;
i = 0
while(i < v){
try{
Thread.sleep(100);
}
catch(Exception ek) {}
double stopien = 231.4 - ((360*v)/280);
double radSek = Math.toRadians(stopien);
x = srodek + (a * Math.cos(radSek));
y = srodek - (a * Math.sin(radSek));
repaint();
i++;
}
}
}
repaint
public void repaint() {
repaint(0, 0, 0, width, height);
}
/**
* Repaints the component. If this component is a lightweight
* component, this results in a call to <code>paint</code>
* within <code>tm</code> milliseconds.
* <p>
* <b>Note</b>: For more information on the paint mechanisms utilitized
* by AWT and Swing, including information on how to write the most
* efficient painting code, see
* Painting in AWT and Swing.
*
* #param tm maximum time in milliseconds before update
* #see #paint
* #see #update(Graphics)
* #since JDK1.0
*/
public void repaint(long tm) {
repaint(tm, 0, 0, width, height);
}
/**
* Repaints the specified rectangle of this component.
* <p>
* If this component is a lightweight component, this method
* causes a call to this component's <code>paint</code> method
* as soon as possible. Otherwise, this method causes a call to
* this component's <code>update</code> method as soon as possible.
* <p>
* <b>Note</b>: For more information on the paint mechanisms utilitized
* by AWT and Swing, including information on how to write the most
* efficient painting code, see
* Painting in AWT and Swing.
*
* #param x the <i>x</i> coordinate
* #param y the <i>y</i> coordinate
* #param width the width
* #param height the height
* #see #update(Graphics)
* #since JDK1.0
*/
public void repaint(int x, int y, int width, int height) {
repaint(0, x, y, width, height);
}
/**
* Repaints the specified rectangle of this component within
* <code>tm</code> milliseconds.
* <p>
* If this component is a lightweight component, this method causes
* a call to this component's <code>paint</code> method.
* Otherwise, this method causes a call to this component's
* <code>update</code> method.
* <p>
* <b>Note</b>: For more information on the paint mechanisms utilitized
* by AWT and Swing, including information on how to write the most
* efficient painting code, see
* Painting in AWT and Swing.
*
* #param tm maximum time in milliseconds before update
* #param x the <i>x</i> coordinate
* #param y the <i>y</i> coordinate
* #param width the width
* #param height the height
* #see #update(Graphics)
* #since JDK1.0
*/
public void repaint(long tm, int x, int y, int width, int height) {
if (this.peer instanceof LightweightPeer) {
// Needs to be translated to parent coordinates since
// a parent native container provides the actual repaint
// services. Additionally, the request is restricted to
// the bounds of the component.
if (parent != null) {
if (x < 0) {
width += x;
x = 0;
}
if (y < 0) {
height += y;
y = 0;
}
int pwidth = (width > this.width) ? this.width : width;
int pheight = (height > this.height) ? this.height : height;
if (pwidth <= 0 || pheight <= 0) {
return;
}
int px = this.x + x;
int py = this.y + y;
parent.repaint(tm, px, py, pwidth, pheight);
}
} else {
if (isVisible() && (this.peer != null) &&
(width > 0) && (height > 0)) {
PaintEvent e = new PaintEvent(this, PaintEvent.UPDATE,
new Rectangle(x, y, width, height));
SunToolkit.postEvent(SunToolkit.targetToAppContext(this), e);
}
}
}
Reset i before the while
v = 100;
i = 1; // if you want 99 times
while (i<v) { ...
Note: try to stay away from using global values like this because you have to keep track of the value of the variable all the time. Use local variables if possible.
Local variables:
int ax = 100;
int bx = 1;
while(bx < ax){
try{
Thread.sleep(100);
}
catch(Exception ek) {}
double stopien = 231.4 - ((360*v)/280);
double radSek = Math.toRadians(stopien);
x = srodek + (a * Math.cos(radSek));
y = srodek - (a * Math.sin(radSek));
repaint();
bx++;
}

How to make a sprite spiral to the center (in Java but if you know a formula, it would help too)

I'm making a game in java where enemy sprites spiral to the center and damage the main tower. The only thing I'm having problems with is the formula to make the sprite spiral. All I found on the internet it this: http://scratch.mit.edu/projects/1439249/
That is sort of what I want to do but I want to make them spiral to a point from outside the JFrame, not from a point within the JFrame.
I am in Secondary 4 and I don't have to much knowledge about such formulas yet and sorry if I have problems understanding the formulas. Thanks in advance!
One simple way of making a sprite appear to spiral is to pretend that it is attached to an arm, like the hand of a clock, that rotates around the center of the spiral. As that arm rotates, slowly move the sprite down the arm towards the center. What you end up with is a classic Archimedan Spiral
I can mock up some code for you, but that's going to take a few minutes.
Okay, here's the code.
public static double getArmX(double length, double angle) {
return Math.cos(angle) * length;
}
public static double getArmY(double length, double angle) {
return Math.sin(angle) * length;
}
These are the core of the math. They return the x and y values of an entity that is at the specified distance from the center (length) and angle from the center (angle).
Now, I don't know how you have your code set up, but lets pretend we have a double named spiralProgress that represents how far into its spiral your entity is. At spiralProgress == 0, the entity is just starting, and at spiralProgress == 1, the entity is at the center.
Here is what the code to get the x and y for the entity would look like:
double startingRadius = 64;
double rotations = 10;
double x = getArmX(startingRadius * (1-t), t * rotations * Math.PI * 2);
double y = getArmY(startingRadius * (1-t), t * rotations * Math.PI * 2);
In that snippet, startingRadius is how many units (pixels, if thats what x and y means in your program), the entity should start away from the center, and rotations is how many times the entity should loop around the center before reaching it.
The coordinates this returns are for a spiral around {0, 0}, so if you want to spiral around some other point, say {screenWidth / 2, screenHeight / 2}, you'd add screenWidth / 2 to x and screenHeight / 2 to y.
Here is a full Java program that demonstrates this math. Click the mouse anywhere in the window to reset the spiral.
package net.eonz.stackoverflow.spiral;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable, MouseListener {
private static final long serialVersionUID = 1L;
public static final String NAME = "untitled";
public static final int HEIGHT = 600;
public static final int WIDTH = 600;
public static final int SCALE = 1;
private boolean running = false;
public void start() {
running = true;
new Thread(this).start();
this.addMouseListener(this);
}
public void stop() {
running = false;
}
public void run() {
long last = System.currentTimeMillis();
while (running) {
long now = System.currentTimeMillis();
double dt = (now - last) / 1000.0;
last = now;
update(dt);
render();
}
}
double t = 0;
public void update(double dt) {
t += dt / 16;
if (t > 1)
t = 1;
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
/* SPIRAL MATH IS HERE */
double startingRadius = this.getHeight() * 0.40;
double rotations = 10;
double x = getArmX(startingRadius * (1 - t), t * rotations * Math.PI
* 2);
double y = getArmY(startingRadius * (1 - t), t * rotations * Math.PI
* 2);
g.setColor(Color.black);
g.fillRect((int) (x - 8) + this.getWidth() / 2,
(int) (y - 8) + this.getHeight() / 2, 16, 16);
/* END SPIRAL MATH */
g.dispose();
bs.show();
}
public static double getArmX(double length, double angle) {
return Math.cos(angle) * length;
}
public static double getArmY(double length, double angle) {
return Math.sin(angle) * length;
}
#Override
public void mouseClicked(MouseEvent e) {
this.t = 0;
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
public static void main(String[] args) {
Game game = new Game();
game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame frame = new JFrame(Game.NAME);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(game, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
game.start();
}
}
I am new to java programming too and as part of my course I recently had to program a spiral.
Here is the solution file from my course.
This will draw a simple spiral.
I hope this helps you. It also has comments to help you understand what is happening.
enjoy
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawSpiral2 extends JPanel
{
// draws a square shape that continually spirals outward
public void paintComponent( Graphics g )
{
super.paintComponent( g );
g.setColor( Color.GREEN );
// draw a green spiral
int x = getWidth() / 2;
// x coordinate of upperleft corner
int y = getHeight() / 2;
// y coordinate of upperleft corner
int radiusStep = 20;
// distance the radius changes
int diameter = 0; // diameter of the arc
int arc = 180; // amount and direction of arc to sweep
// draws individual lines in to form a spiral
for ( int i = 0; i < 20; i++ )
{
if ( i % 2 == 1 ) // move the x position every other repetition
x -= 2 * radiusStep;
y -= radiusStep; // move the y position
diameter += 2 * radiusStep; // increase the diameter
g.drawArc( x, y, diameter, diameter, 0, arc );
// draw the arc
arc = -arc; // reverse the direction of the arc
} // end for
} // end method paintComponent
} // end class DrawSpiral2
Here is the test file.
public class DrawSpiralTest2
{
public static void main( String args[] )
{
DrawSpiral2 panel = new DrawSpiral2();
JFrame application = new JFrame();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
application.add( panel );
application.setSize( 300, 300 );
application.setVisible( true );
} // end main
} // end class DrawSpiralTest2

Categories

Resources