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
Related
I'm creating a game that has randomly drawn Asteroids (to give the Asteroids a jagged look). After research I've only found that you can fill primitive shapes. Does anyone know a method I could use to fill these shapes?
package view.game_object;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Asteroid extends BaseGameObject {
public static final int BASE_SIZE = 10;
private final int fragmentCount;
private final int[][] points;
private final int level;
public Asteroid(int level, Random r) {
this.level = level;
this.setBound(level * Asteroid.BASE_SIZE);
int sizeRange = (int) (this.getBound() / 2);
this.fragmentCount = this.level * 6;
// generate random points to draw
this.setPosition(0, 0);
this.points = new int[fragmentCount][2];
ArrayList<Float> angleList = new ArrayList<>();
for (int i = 0; i < fragmentCount; i++) {
angleList.add(r.nextFloat() * (float) (Math.PI * 2));
}
Collections.sort(angleList);
for (int i = 0; i < this.points.length; i++) {
// base point
float x = r.nextInt(sizeRange) + this.getBound() - sizeRange / 3;
// rotate
float[] point = BaseGameObject.rotate(x, 0, this.getPosx(), this.getPosy(),
angleList.get(i));
this.points[i][0] = (int) point[0];
this.points[i][1] = (int) point[1];
}
}
public int getLevel() {
return level;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.gray);
for (int i = 0; i < this.points.length; i++) {
int nextPoint = i + 1;
if (nextPoint >= this.points.length) {
nextPoint = 0;
}
g.drawLine(Math.round(this.getPosx()) + this.points[i][0],
Math.round(this.getPosy()) + this.points[i][1],
Math.round(this.getPosx()) + this.points[nextPoint][0],
Math.round(this.getPosy()) + this.points[nextPoint][1]
);
}
}
}
you can use the Graphics methods to draw a polygon. but you must 'transform' your points into a proper format getXs(), i didn't point that out, i'm pretty sure you can do this as good as i can =)
#Override
public void draw(Graphics g) {
g.setColor(Color.gray); //fillColor
int[] xPoints = getXs(this.points);
int[] yPoints = getYs(this.points);
int nPoints = xPoints.length;
g.fillPolygon(xPoints, yPoints, nPoints);
}
I just started working with LibGDX and can't figure out how to hide an image when it collides with an object. In my game some dots come from the top of the screen and meet the dot at the bottom. When they meet the dots should hide that isn't happening.
This is the main Game Class
public class GameScreen implements Screen,InputProcessor {
final AmazingDot game;
//setting the height and width variables
private int height;
private int width;
private static int touchCounter;
//setting the two dots variables
private Texture playerDotImage;
private Texture gameDotImage;
private Texture gameDotImage1;
private Rectangle playerDotRectangle;
private Map<Rectangle,Texture> gameDotMap;
//storing the time of last dot in nano seconds
private long lastDotTime;
public GameScreen(final AmazingDot gam){
this.game = gam;
Gdx.input.setInputProcessor(this);
//getting the height and width of the user's screen
height = Gdx.graphics.getHeight();
width = Gdx.graphics.getWidth();
touchCounter =0;
//loading the images in the variables
playerDotImage = new Texture(Gdx.files.internal("images/dot2.png"));
gameDotImage = new Texture(Gdx.files.internal("images/dot1.png"));
gameDotImage1 = new Texture(Gdx.files.internal("images/dot2.png"));
//placing the player dot in the middle of the screen
playerDotRectangle = new Rectangle();
playerDotRectangle.x = width/ 2 - 64 / 2;
playerDotRectangle.y = 20;
playerDotRectangle.width = 64;
playerDotRectangle.height = 64;
gameDotMap = new ConcurrentHashMap<Rectangle, Texture>();
populateDots();
}
private void populateDots(){
Rectangle dots = new Rectangle();
dots.x = randomLocation();
dots.y = height;
dots.width = 64;
dots.height = 64;
Random rand = new Random();
int n = rand.nextInt(2) + 1;
if(n==1){
gameDotMap.put(dots,gameDotImage1);
}
else{
gameDotMap.put(dots,gameDotImage);
}
lastDotTime = TimeUtils.nanoTime();
}
private int randomLocation(){
int[] locations = new int[3];
locations[0]=0;
locations[1]=width/2-64/2;
locations[2]=width-64;
Random generator = new Random();
int randomIndex = generator.nextInt(locations.length);
return locations[randomIndex];
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.begin();
game.batch.draw(playerDotImage,playerDotRectangle.x,playerDotRectangle.y,playerDotRectangle.width,playerDotRectangle.height);
for(Map.Entry<Rectangle,Texture> dots : gameDotMap.entrySet()){
game.batch.draw(dots.getValue(),dots.getKey().x,dots.getKey().y);
}
game.batch.end();
// check if we need to create a new dot
if(TimeUtils.nanoTime() - lastDotTime > 1000000000) populateDots();
for(Rectangle dot : gameDotMap.keySet()){
int gameSpeed = 400;
int xSpeed = calXSpeed(gameSpeed);
dot.y = dot.y - gameSpeed * Gdx.graphics.getDeltaTime();
if(dot.x <width/2-64/2){
dot.x = dot.x + xSpeed*Gdx.graphics.getDeltaTime();
}
else if(dot.x>width/2-64/2){
dot.x = dot.x - xSpeed*Gdx.graphics.getDeltaTime();
}
if(dot.y + 64 < 0) gameDotMap.remove(dot);
if(dot.overlaps(playerDotRectangle)) {
//this is where I am trying to remove the map object on collision
gameDotMap.remove(dot);
}
}
}
private int calXSpeed(int gameSpeed){
int seconds = height/gameSpeed;
int distance = width/2-64/2;
int speed = distance/seconds;
return speed;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
touchCounter++;
if(touchCounter % 2==0){
playerDotImage = new Texture(Gdx.files.internal("images/dot2.png"));
}
else{
playerDotImage = new Texture(Gdx.files.internal("images/dot1.png"));
}
return true;
}
#Override
public void dispose() {
playerDotImage.dispose();
gameDotImage.dispose();
gameDotImage1.dispose();
}
}
EDIT
As you can see in the above image when the moving dot reaches the stationary dot, it should disappear. But here in my code the dot just moves past the stationary dot. I am using rectangles(LibGdx) to detect whether the dots overlap each other or not.
Define you Map as an ArrayMap like so:
private ArrayMap<Rectangle, Texture> gameDotMap;
Then you can rewrite you render method like this:
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.begin();
game.batch.draw(playerDotImage, playerDotRectangle.x, playerDotRectangle.y, playerDotRectangle.width, playerDotRectangle.height);
for (int i = 0; i < gameDotMap.size; i++) {
game.batch.draw(gameDotMap.getValueAt(i), gameDotMap.getKeyAt(i).x, gameDotMap.getKeyAt(i).y);
}
game.batch.end();
// check if we need to create a new dot
if (TimeUtils.nanoTime() - lastDotTime > 1000000000) {
populateDots();
}
for (Iterator<ObjectMap.Entry<Rectangle, Texture>> iter = gameDotMap.iterator(); iter.hasNext();) {
ObjectMap.Entry<Rectangle, Texture> entry = iter.next();
Rectangle dot = entry.key;
int gameSpeed = 400;
int xSpeed = calXSpeed(gameSpeed);
dot.y = dot.y - gameSpeed * Gdx.graphics.getDeltaTime();
if (dot.x < width / 2 - 64 / 2) {
dot.x = dot.x + xSpeed * Gdx.graphics.getDeltaTime();
} else if (dot.x > width / 2 - 64 / 2) {
dot.x = dot.x - xSpeed * Gdx.graphics.getDeltaTime();
}
if (dot.y + 64 < 0) {
iter.remove();
}
if (dot.overlaps(playerDotRectangle)) {
//this is where I am trying to remove the map object on collision
iter.remove();
}
}
}
LibGDX has specific types for collections, they are recommended over the JDK's collections.
I am trying to make a bar chart. Everything goes fine; the code compiles and runs successfully. But the frame (window) is not packed perfectly. There is some space at the end of the bar chart. I just want this space removed.
public class BarChart extends JPanel{
int[] percentage;
Color color;
double barOffset;
public BarChart(int[] percentage, Color color) {
this.color = color;
this.percentage = percentage;
}
public BarChart(int[] percentage) {
this.color = Color.black;
this.percentage = percentage;
}
public BarChart() {
this.color = Color.black;
}
int w = 1,h = 1;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
w = getWidth();
h = getHeight();
g.setColor(color);
barOffset = w*0.05;
int barWidth = (int)(w*0.1);
for(int i = 0; i<percentage.length; i++) {
g.fillRect((int)(barOffset),(int)(h*0.95-2*percentage[i]), barWidth, 2*percentage[i]);
if(i < percentage.length-1)
barOffset = (i+2)*w*0.05 + (i+1)*(barWidth);
}
}
}
This was not a packing error, but rather you were drawing off the edge of the component. To check for packing errors, set a background color for the container that is distinct from the component color.
For the set int[] p = new int[]{100, 5, 6, 9, 1, 0, 5, 100};, your bars are being drawn as follows:
component dimensions: width=104 height=10
bar[0]: xLeft=5 yTop=-190 barWidth=10 barHeight=200
bar[1]: xLeft=20 yTop=0 barWidth=10 barHeight=10
bar[2]: xLeft=35 yTop=-2 barWidth=10 barHeight=12
bar[3]: xLeft=50 yTop=-8 barWidth=10 barHeight=18
bar[4]: xLeft=66 yTop=7 barWidth=10 barHeight=2
bar[5]: xLeft=81 yTop=9 barWidth=10 barHeight=0
bar[6]: xLeft=96 yTop=0 barWidth=10 barHeight=10
bar[7]: xLeft=111 yTop=-190 barWidth=10 barHeight=200
I think this produces what you're looking for. Drawing components can be tricky, and the way I mitigate the complexity is to keep track of my screen locations semantically.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BarChart extends JPanel
{
public static void main(String[] args)
{
int[] p = new int[]{100, 5, 6, 9, 1, 0, 5, 100};
JFrame f = new JFrame();
f.setBackground(Color.BLUE);
BarChart chart = new BarChart(p);
chart.setBackground(Color.RED);
f.add(chart);
f.pack();
f.show();
}
private int[] percentage;
private Color color;
private boolean padEnds = true;
public BarChart(int[] percentage, Color color)
{
this.percentage = percentage;
this.color = color;
return;
}
public BarChart(int[] percentage)
{
this(percentage, Color.BLACK);
return;
}
public BarChart()
{
this(new int[0]);
return;
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(this.color);
int width = super.getWidth();
int height = super.getHeight();
int topPadding = Math.round(height * 0.05f);
int barCount = this.percentage.length;
int barOffset = Math.round(width * 0.025f); // 2.5% (in pixels) reserved space on both sides of each bar == 5% between bars
int totalOffsetWidth = (barOffset * 2) * barCount;
if (!this.padEnds)
{
totalOffsetWidth -= (barOffset * 2);
}
int availableWidth = width - totalOffsetWidth;
int availableHeight = height - topPadding;
int barWidth = (int) Math.floor((float) availableWidth / (float) barCount);
int xLeft = 0;
for (int i = 0; i < barCount; i++)
{
int percent = this.percentage[i];
if (this.padEnds || (i != 0))
{
xLeft += barOffset; // Add offset here to pad left side of each bar.
}
int barHeight = Math.round(((float) availableHeight) * ((float) percent / 100f));
int yTop = topPadding + (availableHeight - barHeight);
g.fillRect(xLeft, yTop, barWidth, barHeight);
xLeft += barWidth; // advance the next drawing position
if (this.padEnds || (i != (barCount - 1)))
{
xLeft += barOffset; // Add offset here to pad right side of each bar.
}
}
return;
}
}
I'm working on a program that takes a ship object and it moves it. The trouble I am having is that if it goes past a side, then it is supposed to wrap back around on the other side.
Any help would be great :)
Here is my ship Class: The move method is what I need help with. The code I have doesnt work :/
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import junit.framework.TestCase;
public class Ship {
private BufferedImage _image;
private static final int WIDTH = 50;
private Point location;
private Vector speed = new Vector();
private double facing;
/**
* Generate ship at the given starting location and currently stopped
*
* #param starting
* location to copy for this ship
*/
public Ship(Point starting) {
try {
// Use the RunConfigurations >> Arguments > Working Directory tab so
// that this works. Don't just place the nave.png file in the bin
// directory!
_image = ImageIO.read(new File("nave.png"));
} catch (IOException e) {
System.err.println("Cannot find ship _image: " + e.getMessage());
}
location = starting.clone();
facing = Math.PI;
}
public void accelerate(double force) {
// TODO change the speed (velocity, really) by force in the direction
// the ship is facing.
// add a vector of appropriate magnitude by the facing direction
Vector acc = new Vector(facing);
acc = acc.scale(force);
speed = speed.add(acc);
}
public void rotate(double angle) {
// TODO change the direction the ship is facing. Can accept any angle
// as a parameter but should store it as in [0,2*pi)
while (angle <= 0.0f) {
angle += (Math.PI * 2);
}
while (angle >= Math.PI) {
angle -= (Math.PI * 2);
}
facing += angle;
}
public void move(Dimension bounds) {
// TODO Move the ship its speed. The ship should wrap around
// within its box. (Hint: move the ship by the size of the
// bounding area to wrap it around; you may need to do this
// more than once if the ship is moving fast enough.)
location = speed.move(location);
while (location.getX() > bounds.width) {
Vector v = new Vector(location.getX() - WIDTH);
location = v.move(location);
}
while (location.getX() < -WIDTH) {
Vector v = new Vector(location.getX() + WIDTH);
location = v.move(location);
}
while (location.getY() > bounds.height) {
Vector v = new Vector(location.getY() - WIDTH);
location = v.move(location);
}
while (location.getY() < -WIDTH) {
Vector v = new Vector(location.y() + WIDTH);
location = v.move(location);
}
}
public void draw(Graphics g2d) {
double locationX = _image.getWidth() / 2;
double locationY = _image.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(facing,
locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx,
AffineTransformOp.TYPE_BILINEAR);
// Drawing the rotated image at the required drawing locations
// Code for rotating adapted from StackOverflow.
g2d.drawImage(op.filter(_image, null), location.getX(),
location.getY(), null);
}
And here is my vector class: All this code works :)
public class Vector {
private final double _dx, _dy;
public Vector() {
_dy = 0.0;
_dx = 0.0;
}
public Vector(double x, double y) {
_dx = x;
_dy = y;
}
public Vector(Point a, Point b) {
_dx = b.x() - a.x();
_dy = b.y() - a.y();
}
public Vector(double angle) {
_dx = Math.cos(angle);
_dy = Math.sin(angle);
}
public double dx() {
return _dx;
}
public double dy() {
return _dy;
}
public Point move(Point b) {
double x = b.x();
double y = b.y();
x += _dx;
y += _dy;
return new Point(x, y);
}
public Vector add(Vector a) {
double x = (a._dx + _dx);
double y = (a._dy + _dy);
return new Vector(x, y);
}
public Vector scale(double s) {
double x = _dx * s;
double y = _dy * s;
return new Vector(x, y);
}
public double magnitude() {
double x = Math.pow(_dx, 2);
double y = Math.pow(_dy, 2);
return Math.sqrt(x + y);
}
public Vector normalize() {
double x = _dx / magnitude();
double y = _dy / magnitude();
return new Vector(x, y);
}
public Vector rotate(double rads) {
double theta = angle();
theta += rads;
return new Vector(theta);
}
public double angle() {
double alpha = Math.acos(dx() / magnitude());
if (dy() < 0)
alpha = Math.PI - alpha;
return alpha;
}
#Override
public String toString() {
String vector = "[" + _dx + "," + _dy + "]";
return vector;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Vector) {
Vector vector = (Vector) obj;
if ((Math.abs(_dx - vector._dx) <= (1 / 10000000000f))
&& (Math.abs(_dy - vector._dy) <= (1 / 10000000000f)))
return true;
else
return false;
} else
return false;
}
#Override
public int hashCode() {
return (int) Math.round((angle() * 180) / Math.PI);
}
}
Expanding upon the suggestion to use modulo, you can use it as follows to wrap around easily without loops:
// Assuming move is called for each time frame
// We can update the location of ship using modulo when it exceeds the bounds
public void move(Dimension bounds) {
// TODO Move the ship its speed. The ship should wrap around
// within its box. (Hint: move the ship by the size of the
// bounding area to wrap it around; you may need to do this
// more than once if the ship is moving fast enough.)
location = speed.move(location);
if (location.getX() > bounds.width) {
location.setLocation(location.getX() % bounds.width), location.getY());
}
else if (location.getX() < 0) {
location.setLocation(bounds.width - location.getX(), location.getY());
}
if (location.getY() > bounds.height) {
location.setLocation(location.getX(), location.getY() % bounds.height);
}
else if (location.getY() < 0) {
location.setLocation(location.getX(), bounds.height - location.getY());
}
}
You've provided a lot of code so I may have missed why you need to do this, but rather than create a new delta Vector to move the location, you can alternatively just determine the new wrapped position that the ship should be at set it per setLocation method.
I hope this helps.
I'm learning about queues in school and an having an issue with one of our labs i believe the issue is here the problem is that it will not erase the circles after reaching 50
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getX(),temp.getY());
}
temp = new Coord(getX(),getY());
q.add(temp);
c.drawCircle(g);
c.hitEdge();
}
}
catch(InterruptedException e){}
}
if you need the whole thing to run or test here is all of it with comments saying what everything is and what I'm trying to do
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
/**
* Creates an instance of the GfxApp class, which uses the Circle class, Coord class, and
* a queue to create a screen saver.
* #param args not used
*/
public class ScreenSaver
{
public static void main(String args[])
{
GfxApp gfx = new GfxApp();
}
}
/**
* Creates a Screen Saver by placing Circle coordinates in a queue
*/
class GfxApp extends JFrame
{
private int circleCount, circleSize;
public static final int TIME_DELAY = 10; // controls the speed
public static final int TOTAL_NUM_CIRCLES = 1000; // controls how long it goes
/**
* Creates a GfxApp with 50 circles with diameter 30
*/
public GfxApp()
{
circleCount = 50;
circleSize = 30;
setSize(800,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
/**
* Draws a stream of circleCount circles of size circleSize. Uses a queue to erase circles
* at the end of the stream. The total number of circles that will be drawn is 2000.
* #param g the Graphics object
*/
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getY(),temp.getX());
}
temp = new Coord(getX(),getY());
q.add(temp);
c.drawCircle(g);
c.hitEdge();
}
}
catch(InterruptedException e){}
}
}
/**
* A class to represent Circle objects. Circles can be drawn and erased.
*/
class Circle
{
private int tlX; // top-left X coordinate
private int tlY; // top-left Y coordinate
private int incX; // increment movement of X coordinate
private int incY; // increment movement of Y coordinate
private boolean addX; // flag to determine add/subtract of increment for X
private boolean addY; // flag to determine add/subtract of increment for Y
private int size; // diameter of the circle
private int timeDelay; // time delay until next circle is drawn
/**
* Creates a Circle with a specified Graphics, size, x increment, y increment and time delay
*/
public Circle(Graphics g, int s, int x, int y, int td)
{
incX = x;
incY = y;
size = s;
addX = true;
addY = false;
tlX = 400;
tlY = 300;
timeDelay = td;
}
/**
* returns the top left X of this circle
* #return tlX
*/
public int getTLX() { return tlX;}
/**
* returns the top left Y of this circle
* #return tlY
*/
public int getTLY() { return tlY;}
/**
* delays the program for a specified number of miliseconds
* #param n number of miliseconds
*/
public void delay(int n) throws InterruptedException
{
Thread.sleep(n);
}
/**
* draws a blue circle and sets the tlX and tlY for the next drawing
* #param g Graphics object
*/
public void drawCircle(Graphics g) throws InterruptedException
{
g.setColor(Color.blue);
g.drawOval(tlX,tlY,size,size);
delay(timeDelay);
if (addX)
tlX+=incX;
else
tlX-=incX;
if (addY)
tlY+=incY;
else
tlY-=incY;
}
/**
* Randomly sets a new direction for the circle by randomly setting
* the x increment and y increment
*/
public void newData()
{
incX = (int) Math.round(Math.random() * 7 + 5);
incY = (int) Math.round(Math.random() * 7 + 5);
}
/**
* Determines if any of the four edges have been hit, and if so, reverses the
* appropriate flags (addX and addY) and calls newData
*/
public void hitEdge()
{
boolean a = false;
if (tlX < incX)
{
addX = true;
a = true;
}
if (tlX > 800 - (30 + incX))
{
addX = false;
a = true;
}
if (tlY < incY + 30)
{
addY = true;
a = true;
}
if (tlY > 600 - (30 + incY))
{
addY = false;
a = true;
}
if (a)
newData();
}
// add an eraseCircle method
public void eraseCircle(Graphics g, int x, int y)
{
g.setColor(Color.black);
g.drawOval(x,y,size,size);
}
}
// Create a Coord class, so that coordinates of drawn circles can be placed in the queue.
// As coordinates are removed from the queue, circles are erased with eraseCircle.
class Coord
{
private int x;
private int y;
public Coord(int a, int b)
{
x=a;
y=b;
}
public int getX(){return x;}
public int getY(){return y;}
public int setX(int a){x=a; return x;}
public int setY(int b){y=b; return y;}
}
your coordinates are backwards:
-public void eraseCircle(Graphics g, int x, int y)
-c.eraseCircle(g,temp.getY(),temp.getX());
switch around x and y and it should work.
Edit:
Ok so the problem is the x and y in your coords are always 0 so I modified your drawCircle method to return the proper coordinates, and your paint method to store them, so this is what you get:
Paint:
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getX(),temp.getY());
}
temp = new Coord(getX(),getY());
//q.add(temp);
q.add(c.drawCircle(g));
c.hitEdge();
}
}
catch(InterruptedException e){}
}
drawCircle:
/**
* draws a blue circle and sets the tlX and tlY for the next drawing
* #param g Graphics object
* #return
*/
public Coord drawCircle(Graphics g) throws InterruptedException
{
g.setColor(Color.blue);
g.drawOval(tlX,tlY,size,size);
delay(timeDelay);
if (addX)
tlX+=incX;
else
tlX-=incX;
if (addY)
tlY+=incY;
else
tlY-=incY;
return new Coord(tlX, tlY);
}
To determine this I set a breakpoint in the paint method and viewed what temp's values were through eclipses debugger.