Search code examples
javamultithreadingalgorithmcolorsfade

Color Fading Algorithm not working?


I am trying to create a fading/transitioning colors algorithm between two colors and a timer; the timer will determine how fast the colors swap between one another. The only problem is: the more fading transition objects I add in, the faster they all go. For example: If I add in one StandardFade (the class) object, it will run at the timer (alpha, in the code) I give it. However, if more objects that do 'fade' appear on the screen, the timer is no longer relevant, and they all go at the same rate, faster and faster with each object. Can anyone explain why?

//Test Game Class, Implements the StandardFades
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;

public class TestGame extends Canvas implements Runnable{

private static final long serialVersionUID = -7267473597604645224L;

private Thread thread;
private boolean running = false;
private boolean consoleFPS = true;
private boolean titleFPS = true;

private TestWindow window;

//Fade objects, two is for a really long timer to test to see if they would transition at different times
StandardFade one = new StandardFade(Color.RED,Color.BLUE,.005);
StandardFade two = new StandardFade(Color.RED,Color.GREEN,.00000000000000001);
StandardFade three = new StandardFade(Color.RED,Color.YELLOW,.000005);

private int currentFPS;
private int frames;

public int levelNum;

public TestGame(int width, int height, String title){
    this.window = new TestWindow(width,height, title, this);

    this.initFades();
    this.start();
}

private synchronized void start(){
    if(running)
        return;
    else{
        this.thread = new Thread(this);
        this.thread.start();
        this.running = true;
    }
}

private synchronized void stop(){
    if(!this.running)
        return;
    else{
        try{
            this.thread.join();
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        this.running = false;
        System.exit(0);
    }
}
/**
 * This game loop was provided by online sources, though there are many examples
 * of a game loop online.
 * 
 * @author RealTutsGML
 */
public void run() {
    requestFocus(); //Focuses the click/input on the frame/canvas.
    long lastTime = System.nanoTime(); //The current system's nanotime.
    double ns = 1000000000.0 / 60.0; //Retrieves how many nano-seconds are currently in one tick/update.
    double delta = 0; //How many unprocessed nanoseconds have gone by so far.
    long timer = System.currentTimeMillis();
    int frames = 0; //The frames per second.
    int updates = 0; //The updates per second.
    while (running) {

        boolean renderable = false; //Determines if the game should render the actual graphics.

        long now = System.nanoTime();//At this point, the current system's nanotime once again.
        delta += (now - lastTime) / ns;
        lastTime = now;
        //If the amount of unprocessed ticks is or goes above one...
        //Also determines if the game should update or not/render. Approximately sixty frames per second.
        while (delta >= 1) {
            tick();

            delta--;
            updates++;

            renderable = true;
        }

        if(renderable){
            frames++;
            render();
        }

        if (System.currentTimeMillis() - timer > 1000) {
            timer += 1000;
            System.out.println(frames);
            updates = 0;
            frames = 0;
        }
    }

    this.stop();
}

/**
 * This method should tick everything that needs to be updated via positioning, 
 * mouse input, etc.
 */
private void tick(){
    /********************PUT ALL TICKABLE METHODS IN THIS METHOD; ALL CALCULATIONS, EVERYTHING*********************/
    //this.stdFadeHandler.get(0).tick();

    //this.stdFadeHandler.tick();

    one.tick();
    two.tick();
    three.tick();
    /**********************************END OF TICK METHOD INFORMATION AND METHODS******************************/
}

private void render(){
    BufferStrategy bs = this.getBufferStrategy();

    if(bs == null){
        createBufferStrategy(3);
        return;
    }

    Graphics g = bs.getDrawGraphics();
    Graphics2D g2 = (Graphics2D) g;

    g2.setColor(Color.BLACK);       
    g2.fillRect(0, 0, window.getWidth(), window.getHeight());
    /*******************PLACE ALL DRAWING INSTRUCTIONS WITHIN THIS SECTION OF THE RENDER METHOD*************************/

    g2.setColor(one.getColor());
    g2.fillRect(20, 20, 200, 200);
    g2.setColor(two.getColor());
    g2.fillRect(20, 300, 200, 200);
    g2.setColor(three.getColor());
    g2.fillRect(20, 540, 200, 200);

    //this.stdFadeHandler


    /*******************DO NOT PLACE ANY MORE DRAWING INSTRUCTIONS WITHIN THIS SECTION OF THE RENDER METHOD***************/

    g.dispose();
    g2.dispose();

    bs.show();
}

private void initFades(){


}

public static void main(String[] args){

    TestGame stdGame = new TestGame(800,800,"Test Standard Game");
}

Below is the actual class that MAKES the frames: StandardFade

import java.awt.Color;
import java.awt.Graphics2D;

public class StandardFade {

private static float time = 0;
private static boolean firstColor = true;

private Color color1;
private Color color2;
private double alpha;

private Color fadeColor;

/**
 * Lines that implement the 
 * r,g and b values come from Princeton University; I will author
 * them in at the bottom.
 * 
 * Method takes two parameters and fades them into one another according to a 
 * timer/clock value: alpha.
 * @param c1 First color to be used. 
 * @param c2 Second color to be used. 
 * @param alpha How fast colors should shift. 0 <= n <= 1. 
 * Closer value is to zero, the longer it will take to shift.
 * ***Important note about alpha: for non-seizure inducing colors, alpha <= .0005***
 * 
 * The issue that is occurring is that, no matter what I do, no matter if I make 
 * different StandardFade objects and assign them, they will always render at the 
 * same rate, and faster and faster, depending on how many objects are fading.
 *
 * @return new Color based on r, g, and b values calculated.
 * 
 * @author (Only code utilized was lines 58-60):
 * http://introcs.cs.princeton.edu/java/31datatype/Fade.java.html
 */
public StandardFade(Color c1, Color c2, double alpha){
    this.color1 = c1;
    this.color2 = c2;

    this.alpha = alpha;
}

public void tick() {

    if(time <= 1f && firstColor){
        time += alpha;
    }

    else{
        firstColor = false;
    }
    if(time >= 0f && !firstColor)
        time -= alpha;
    else{
        firstColor = true;
    }

    //System.out.println(time);

    short r = (short) (time * color2.getRed()   + (1 - time) * color1.getRed());
    short g = (short) (time * color2.getGreen() + (1 - time) * color1.getGreen());
    short b = (short) (time * color2.getBlue()  + (1 - time) * color1.getBlue());

    if(r > 255) r = 255;
    if(g > 255) g = 255;
    if(b > 255) b = 255;

    if(r < 0) r = 0;
    if(g < 0) g = 0;
    if(b < 0) b = 0;


    this.fadeColor = new Color(r, g, b);
}

public Color getColor(){
    return this.fadeColor;
}

Solution

  • The only problem is: the more fading transition objects I add in, the faster they all go

    private static float time = 0;
    

    You are using a static variable for the time. This variable is shared by all instances of the ColorFade class. So each fading objects updates the same variable.

    Don't use a static variable (just get rid of the static keyword). Each fading object needs its own "time" variable.

    private float time = 0;
    

    I also question if the firstColor variable should be static.