I am working on creating a weighted US map and I have broken the zip codes down into 3 digit zip zones. I then use a for loop that iterates 1000 times to color each 3 digit zip zone a random color.
This works every time with out issue. My current issue is coming in if I start my for loop count above 310. Anything less than 310 and it loops through perfectly. So since raising the initial count would mean that it would run the recursive code less, then this does make any sense to me.
The code that calls the for loop:
private void GUI()
{
JFrame frame = new JFrame();
frame.setLayout(new MigLayout());
try
{
mapImg = ImageIO.read(new File("Res/Zipzone map of the US.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
g = mapImg.createGraphics();
for(int i = 311; i < 1001; i++)
{
Random rand = new Random();
String count = "";
int red = rand.nextInt(220) + 25;
int green = rand.nextInt(220) + 25;
int blue = rand.nextInt(220) + 25;
if(i < 100)
{
count = "0" + i;
}
else
{
count = i + "";
}
if(i <= 512)
{
ApplyColor(count, new Color(red, blue, green));
}
else if( i > 909)
{
ApplyColor3(count, new Color(red, blue, green));
}
else
{
ApplyColor2(count, new Color(red, blue, green));
}
}
frame.add(new JLabel("", new ImageIcon(GetScaledImage(new ImageIcon(mapImg).getImage(), 1400, 875)), JLabel.CENTER), "GROW, PUSH");
frame.setTitle("US Map");
frame.setSize(1500,900);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
Small example of the apply color function:
private void ApplyColor(String zip, Color color)
{
int x;
int y;
if(zip.equals("010"))
{
try
{
x = 3339;
y = 672;
FloodFill(x, y, new Color(mapImg.getRGB(x, y)), color);
x = 3361;
y = 681;
FloodFill(x, y, new Color(mapImg.getRGB(x, y)), color);
}
catch(AWTException e)
{
e.printStackTrace();
}
}
}
And the FloodFill function:
public void FloodFill(int x, int y, Color targetColor, Color replacementColor) throws AWTException
{
if(new Color(mapImg.getRGB(x, y)).equals(replacementColor))
{
return;
}
g.setColor(replacementColor);
g.fillRect(x, y, 1, 1);
if(new Color(mapImg.getRGB(x-1, y)).equals(targetColor))
{
FloodFill(x-1, y, targetColor, replacementColor);
}
if(new Color(mapImg.getRGB(x+1, y)).equals(targetColor))
{
FloodFill(x+1, y, targetColor, replacementColor);
}
if(new Color(mapImg.getRGB(x, y-1)).equals(targetColor))
{
FloodFill(x, y-1, targetColor, replacementColor);
}
if(new Color(mapImg.getRGB(x, y+1)).equals(targetColor))
{
FloodFill(x, y+1, targetColor, replacementColor);
}
}
I don't really know why you receive this error when you start from 310 or more, because the part of your code that deals with what you are referring to as "zip codes" is too bizarre to try and make sense of, and because in any case, making sense out of that would not benefit any other visitors of the site, only you.
What I suspect is happening is that by starting at 310 or above the arrangement of zip codes is such that your recursive flood-fill algorithm is required to do more painting than if you did not.
Which brings us to your recursive flood-fill algorithm.
That's not the right way to do flood-fill.
It might be considered right in the academia, but not in the real world.
If your algorithm is given a long stretch of pixels to paint, it will recurse for every single one of them. In your initialization code I see you setting the width of your frame to 1500, and elsewhere I see you using coordinates in excess of 3000, which means that you do in fact give your algorithm long stretches of pixels to paint. Which means that it recurses a lot. That's why you get a stack overflow exception.
To correct your problem, you need to rewrite your recursive flood-fill algorithm so that it does not recurse so much. For example, instead of recursing each time you visit a pixel to the left, have it loop to the left for as long as there are pixels to paint, and only recurse for the pixel above and the pixel below each painted pixel. The same holds for visiting pixels to the right. That's an easy way to reduce the recursion depth of your algorithm by orders of magnitude.
It also has the benefit of performing much better, because once you know all the pixels that you need to paint in a row, you can paint them all with a single drawing call, instead of performing one fillRect() per pixel. We are talking about orders of magnitude better performance here.
If that is not enough to solve your stack overflow problems, then you might want to consider replacing your algorithm with one which uses a stack data structure instead of actually invoking itself. Conversion of a recursive algorithm to a non-recursive that uses a stack data structure is something that you can look up and find plenty of solutions to.
Related
I have to make a box move zig-zag all the way to the bottom of the screen. I figured out how to have the box start at the top left corner, move to the top right corner, then it moves down (one complete box of (x,y,90,90)). I'm stuck now because I realize that the next if-statement I want to write is fighting with the first if-statement to glide the box to the left end of the screen. I've tried while and for loops to overcome the problem but I honestly don't know what to do or where to do. I need the program to do this all the way down the screen and stop at rest(810,810,90,90) and stop. Any suggestions?
Here's my main code:
WBox v1;
int a = 0;
float x=0;
float y=0;
void setup() {
size(900, 900);
frameRate(1000);
v1 = new WBox();
}
void draw(){
background(255);
fill(0);
rect(x,y,90,90);
if(x<810){
x+=1;
} else if(y < 90){
y+=1;
} else if (x<=0){
x-=1;
}
}
Here's the class:
**class WBox{
PVector wb;
void box(int tempX, int tempY) {
wb = new PVector(tempX, tempY);
wb.mult(a);//
rect(wb.x, wb.y, 90, 90);
}
}
Full disclaimer: it would be better practice to use the WBox class differently to achieve this, but as you seem to be a beginner, I'm going to stick to easy stuff. You can ask me questions if you feel like it, I'll hang around for a while.
Instead of having a hardcoded number for movement speed, let's try it with a variable:
float boxSpeedX = 1;
The we just have to figure out an algorithm to get it to go down. The best way to do this is to use pseudocode.
In other words: write the logic behind the machine code. Something like this:
Rectangle must move horizontally until it reaches a border
When it reaches a border, it must go down 90 pixels
Then it moves horizontally toward the other side
When it reaches (810, 810) it should stop and rest.
Seems easy enough. Let's go closer to the code:
if (reached a border)
box move horizontally toward the other border
else
box move downward 90 pixels
if (box reached (810, 810)
stop
Closer!
// let's start with the stop condition
if (box reached 810, 810)
do nothing
else
if (box is on an horizontal line)
x += speed
if (box reached right side)
speed = -1 // so next time it'll go left
y +=1 // this way the box isn't on an horizontal line anymore
else if (box reached left side)
speed = 1
y += 1
else
y += 1
Now let's elaborate on some of the details:
(box is on an horizontal line):
horizontal lines are multiples of 90 pixels
(box reached right side)
x == 810
(box reached left side)
x == 0
We'll use the modulo operator to know if the y number is a multiple or 90. Take some time to understand this operator, it's really, really useful. In short, it will give you the remains of an integer division (for example, if you do 13/5, instead of having a number with decimals the integer division will say "2" and the modulo will say "3" because there's 2 times 5 in 13, not more "full 5", and there's 3 units left after this operation).
I feel like we're close enough, now. The rest is just translating this in code. I did it for you, and I've left comments in the code. You can copy and paste it into a Processing IDE and it'll run. You can build on this example to get your box to do whatever you want.
WBox v1;
int a = 0;
float x=0;
float y=0;
float boxSpeedX = 1;
void setup() {
size(900, 900);
frameRate(1000);
v1 = new WBox();
}
void draw() {
background(255);
fill(0);
rect(x, y, 90, 90);
moveBox();
}
void moveBox() {
// first check for the stop condition:
if (x != 810 || y != 810) { // the box will move only while the stop condition isn't met
// if the box is on a horizontal line, let's move it
if (y % 90 == 0) { // the '%' operator's name is 'modulo', it's awesome and useful
x += boxSpeedX;
// once the box has moved, let's check if we need to steer it down:
if (x == 0) { // if the box reaches the left side
boxSpeedX = 1; //next time the box moves horizontally, it'll go right
y += 1; // let's move down
} else if (x == 810) {
boxSpeedX = -1;
y += 1;
}
} else { // if the box isn't on an horizontal line, let's move it downward until it reaches a new line
y += 1;
}
}
}
class WBox {
PVector wb;
void box(int tempX, int tempY) {
wb = new PVector(tempX, tempY);
wb.mult(a);//
rect(wb.x, wb.y, 90, 90);
}
}
Have fun!
I have been doing a small little project using Processing, and the effect I wanted to achieve was a kind of "mountains" forming and moving, using Perlin Noise with the noise() function, with 2 parameters.
I was originally using a image for the background, but for illustrational purposes, I made the background black, and it's basically the same effect.
My issue is that I want to have a "history" of the mountains because they should fade away after some time, and so I made a history of PShapes, and draw the history and update it each frame.
Updating it is no issue, but drawing the PShapes seems to take a lot of time, reducing the frame rate from 60 to 10 when the length of the history is 100 elements.
Below is the code I used :
float noise_y = 0;
float noise_increment = 0.01;
// increment x in the loop by this amount instead of 1
// makes the drawing faster, since the PShapes have less vertices
// however, mountains look sharper, not as smooth
// bigger inc = better fps
final int xInc = 1;
// maximum length of the array
// bigger = less frames :(
final int arrLen = 100;
int lastIndex = 0;
PShape[] history = new PShape[arrLen];
boolean full = false;
// use this to add shapes in the history
PShape aux;
void setup() {
size(1280, 720);
}
void draw() {
background(0);
// create PShape object
aux = createShape();
aux.beginShape();
aux.noFill();
aux.stroke(255);
aux.strokeWeight(0.5);
for (float x = 0; x < width + xInc; x = x + xInc) {
float noise = noise(x / 150, noise_y) ;
// get the actual y coordinate
float y = map(noise, 0, 1, height / 2, 0);
// create vertex of shape at x, y
aux.vertex(x, y);
}
aux.endShape();
// push the current one in the history
history[lastIndex++] = aux;
// if it reached the maximum length, start it over ( kinda works like a queue )
if (lastIndex == arrLen) {
lastIndex = 0;
full = true;
}
// draw the history
// this part takes the MOST TIME to draw, need to fix it.
// without it is running at 60 FPS, with it goes as low as 10 FPS
if (full) {
for (int i = 0; i < arrLen; i++) {
shape(history[i]);
}
} else {
for (int i = 0; i < lastIndex; i++) {
shape(history[i]);
}
}
noise_y = noise_y - noise_increment;
println(frameRate);
}
I have tried to use different ways of rendering the "mountains" : I tried writing my own class of a curve and draw lines that link the points, but I get the same performance. I tried grouping the PShapes into a PShape group object like
PShape p = new PShape(GROUP);
p.addChild(someShape);
and I got the same performance.
I was thinking of using multiple threads to render each shape individually, but after doing some research, there's only one thread that is responsible with rendering - the Animation Thread, so that won't do me any good, either.
I really want to finish this, it seems really simple but I can't figure it out.
One possible solution would be, not to draw all the generated shapes, but to draw only the new shape.
To "see" the shapes of the previous frames, the scene can't be cleared at the begin of the frame, of course.
Since the scene is never cleared, this would cause, that the entire view is covered, by shapes over time. But if the scene would be slightly faded out at the begin of a new frame, instead of clearing it, then the "older" shapes would get darker and darker by time. This gives a feeling as the "older" frames would drift away into the depth by time.
Clear the background at the initlization:
void setup() {
size(1280, 720);
background(0);
}
Create the scene with the fade effect:
void draw() {
// "fade" the entire view
blendMode(DIFFERENCE);
fill(1, 1, 1, 255);
rect(0, 0, width, height);
blendMode(ADD);
// create PShape object
aux = createShape();
aux.beginShape();
aux.stroke(255);
aux.strokeWeight(0.5);
aux.noFill();
for (float x = 0; x < width + xInc; x = x + xInc) {
float noise = noise(x / 150, noise_y) ;
// get the actual y coordinate
float y = map(noise, 0, 1, height / 2, 0);
// create vertex of shape at x, y
aux.vertex(x, y);
}
aux.endShape();
// push the current one in the history
int currentIndex = lastIndex;
history[lastIndex++] = aux;
if (lastIndex == arrLen)
lastIndex = 0;
// draw the newes shape
shape(history[currentIndex]);
noise_y = noise_y - noise_increment;
println(frameRate, full ? arrLen : lastIndex);
}
See the preview:
I'm making a game similar to agar.io where a blob goes around and eats dots. I'm making it on my phone and you control the blob with your finger to collect the dots. I noticed that when I collect a single dot some random other dots dissappearing as well. I debugged some and found out that unless you collected the dots in the order that they were added to the array, any dot with a lower array order would be destroyed. Example: if you collected the dot added to the array 7th then dots 0-6 would dissappear, bit if you collected 1 then 2 and so on then no other dots would dissappear randomly. I created another simpler example to explore this problem. Now it's a simple screen with 5 circles. You can pick up and drag and drop any circle. I noticed the same problem where you drag a circle and other circles randomly dissappear even though there is no code to make them dissappear. My code is as follows:
// Drag n' Drop //
Objects[] box;
int objCount = 5;
void setup() {
box = new Objects[objCount];
for (int i = 0; i < objCount; i++){
box[i] = new Objects(random(displayWidth),random(displayHeight),200);
}
}
void draw() {
background(170);
for (Objects boxes : box) {
boxes.display();
boxes.dragging();
}
}
class Objects {
float x, y;
float s;
Objects(float tempX, float tempY, int tempS) {
x = tempX;
y = tempY;
s = tempS;
}
void display() {
ellipse(x, y, s, s);
}
void dragging() {
if (dist(x, y, mouseX, mouseY) < 500) {
x = mouseX;
y = mouseY;
s = 300;
}
}
}
I believe my problem may lie in the loop I use to call the display function of the box object, but I cannot find out any other way to make it work. Any help us very much appreciated. Thank you for your time. PS Im using processing to run this code.
Kelton
Firstly, I'd like to thank you for I have never played with Processing before and you inspired me to download it!
There are quite a few things wrong that I'd like to point out and maybe steer you in the right direction. The main issue lies within your dragging() method you are not actually removing the objects you are just moving them to your mouse position, giving you the illusion they are being removed!
Anyway, as you said you were creating the game Agar.io, I would assume that you yourself should have your own Blob. For the sake of my Java brain I have switched what you called Objects to Blobs.
First off, the setup.
import java.util.*;
public static final int BLOB_COUNT = 10;
List<Blob> blobs = new ArrayList<Blob>();
// this is our blob, the one that displays in the middle of the screen
Blob myBlob = new Blob(mouseX, mouseY, 50);
void setup() {
size(1000, 500);
for (int i = 0; i < BLOB_COUNT; i++){
blobs.add(new Blob(random(displayWidth/2),random(displayHeight/2),50));
}
}
Notice how I am using ArrayLists rather than an array, this will make it easier for you to add and remove from the List.
Next, the draw() so this happens each frame.
void draw() {
background(170);
// refreshes the players blob wherever the cursor is!
myBlob.setX(mouseX);
myBlob.setY(mouseY);
myBlob.display();
// display the other blobs on the screen
for (Blob boxes : blobs) {
boxes.display();
boxes.dragging();
}
}
Notice, we want to update our blob to the current position of the mouse!
Lastly, the Blob class!
class Blob {
float x, y;
float size;
Blob(float tempX, float tempY, int size) {
this.x = tempX;
this.y = tempY;
this.size = size;
}
void display() {
ellipse(x, y, size, size);
}
void dragging() {
if (dist(x, y, mouseX, mouseY) < myBlob.getSize()/2) {
myBlob.setBlobSize(25);
this.x = random(displayWidth/2);
this.y = random(displayHeight/2);
}
}
void setX(float x){
this.x = x;
}
void setY(float y) {
this.y = y;
}
void setBlobSize(float size) {
this.size += size;
}
float getSize() {
return this.size;
}
}
So now, we check in the dragging() method whether the blob is close to our blob, and if it is we want to consume that blob (which increases our mass) and then we want that blob to re-spawn to another location, well that's how most Agar.io games work, but of course this is entirely up to you. There is also much more accurate ways to calculate the area of the blob and determine whether two blobs are within touching distance, but I'll leave the maths to you.
I am making a minecraft mod that implements a new system of "energy" for the player. There are various ways to acquire this energy and I want it to display the player's amount of energy onto the screen. My plan for this is to make a GUI (with OpenGL, as minecraft uses) that uses a file called "energybar.png":
to print numbers. This is the code I have for the method that will do as described.
#SubscribeEvent
public void onGUIRenderEvent(RenderGameOverlayEvent event){
if(event.isCancelable() || event.type != RenderGameOverlayEvent.ElementType.EXPERIENCE)
{
return;
}
int xPos = 10;
int yPos = 10;
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glDisable(GL11.GL_LIGHTING);
mc.renderEngine.bindTexture(energybar);
String energyString = Integer.toString(Energy.PlayerTotalEnergy);
for(int i=0; i < energyString.length(); i++) {
LogHelper.info("Energy: " + energyString);
drawTexturedModalRect(xPos, yPos, (Energy.PlayerTotalEnergy / (int)Math.pow(10, i))*16, 0, 16, 16);
xPos += 16;
}
}
Each number in the photo is spaced out so it should be in its respective 16 pixels (ie: 0 is x positions 0-16, 1 is x positions 17-32, etc). The photo is 256x256 as defined by the standards of minecraft's GUI system. This is the layout of the method to draw a picture:
void drawTexturedModalRect(int xPosition, int yPosition, int uPosition, int vPosition, int width, int height)
The problem I have with this is that the U Positions for the numbers i need to print onto the screen are not working right.
I have also tried passing:
energyString.substring(i, i)
to a method that takes the substring and converts it back to an integer and multiplies it by 16 to get the uPosition, but when I do the:
String energyString = Integer.toString(Energy.PlayerTotalEnergy);
the Integer.toString() and also String.valueOf() methods have trouble with zeros. For example if Energy.PlayerTotalEnergy was just 0, they would not return a string "0", they just return "".
If someone could help me figure out why I can't get this to work or come up with a better idea of how I can use Minecraft and OpenGL to print this number onto my screen. The reason I'm not just printing it as a number is because I want to keep the red numbers as they look.
This is more of a guess.
It seems to me that if Energy.PlayerTotalEnergy was, let's say, 327, then your uPosition will be:
i=0: u= 327*16
i=1: u= 32*16
i=2: u= 3*16
Did you mean for them to be 7*16, 2*16, and 3*16?
In that case you should mod them with 10:
drawTexturedModalRect(xPos, yPos, ( (Energy.PlayerTotalEnergy / (int)Math.pow(10, i))%10)*16, 0, 16, 16);
I have looked into using the EVEN-ODD Winding rule in order to create holes in an area. The thing is on the forum all I could come up with was a Path2D.Double() appending a hole within itself. I want to create a whole in an already existing Path2D much like the Area class has the Area.subtract(new Shape()); does. I am desperate. I know Path2D has the ability to improve the performance of my game.
Path2D.Double d = new Path2D.Double(Path2D.WIND_EVEN_ODD);// this is a much larger circle which I will be using to subtract from the tile...
d.append(current_draw_area.createTransformedArea(mouse_point), false);//Note that this is an area without a winding rule...
Path2D.Double shape= new Path2D.Double();//this is actually a empty tile which is simply a rectangle, but will eventually have something in it to subtract from...
shape.append(d, false);
Note: Output should be either an empty square because the much larger circle covers the tile completely or a tile that has the result of the intersection of the circle and existing tile shape removed leaving what was left of the tile...
Research Link
StackOverflow Thread
EDIT:
for (int i = 0; i < paint_textures.size(); i++) {
if (!current_paint.equals(paint_textures.get(i))) {
paint_regions.get(paint_textures.get(i)).subtract(new Area(current_draw_area.createTransformedArea(mouse_point)));
for (int y = adjY - 100; y < adjY + current_draw_area.getBounds().height + 100; y += 100) {
for (int x = adjX - 100; x < adjX + current_draw_area.getBounds().width + 100; x += 100) {
try {
if (paint_tiles.get(paint_textures.get(i)).get(new Point(x, y)).intersects(new Rectangle(x, y, 100, 100))) {
Area a = (Area) paint_regions.get(paint_textures.get(i)).clone();
a.intersect(new Area(new Rectangle(x, y, 100, 100)));
Path2D.Double d = new Path2D.Double(a.getPathIterator(null).getWindingRule());
d.append(a.getPathIterator(null), false);//This Causes painting to be Jumpy...
paint_tiles.get(paint_textures.get(i)).replace(new Point(x, y), d);
}
} catch (NullPointerException e) {
}
}
}
}
}