BWR
BWR

Reputation: 47

Java Turtle Animation Issue

I am trying to make an animation where two rectangles will appear and disappear from frame when you type in: c with Turtle Graphics. But the problem I have is that I do not understand how to incorporate turtle graphics into a loop. For this, I have to use do-while loop. I am also suppose to have the rectangles that I made move horizontally across the screen. I have the general idea set out, but I do not know how to use turtle graphics with a loop. My code is not the most orderly when I tried to set it up here.

/**
* Write a description of class Animation here.
* 
* @author (author)
* @version 
*/

import java.util.Scanner;
import java.awt.*;
class Animation
{      
//set conditions for turtle to start drawing
public void prepareTurtleToDraw(Turtle myrtle, Color color, int x, int y)
{
   myrtle.hide();
   myrtle.penUp();               //pick up the pen to avoid leaving a trail when moving the turtle
   myrtle.setColor(color);       //set myrtle's color
   myrtle.moveTo(x, y);          //move to coordinates
   myrtle.penDown();             //put the pen down to start drawing
}//end of prepareTurtleToDraw method

//draw a line
public void drawLine(Turtle myrtle, int x1, int y1, int x2, int y2)//, int width)
{
    myrtle.moveTo(x1, y1);      //moves to this coordinate first
    myrtle.moveTo(x2, y2);      //then moves to this coordinate
    //myrtle.setPenWidth(width);  //this adjusts the size of the lines
}//end of drawLine method   

public static void pressC()
{
    String userInput = "";                                  //declare and initialize a String variable
    char key = ' ';                                         //declare and initialize a char variable
    Scanner in = new Scanner(System.in);                    //construct a Scanner object

    System.out.println("Please press the c key to watch the animation.");
    //do-while loop to wait for the user to enter the letter c
    do  
    {
        userInput = in.next();                                  //accept one token from the keyboard
        in.nextLine();                                          //flush the buffer
        key = userInput.charAt(0);                              //picks off the first character from the userInput String variable

    }
    while(key != 'c');                                      //do-while condition statement 

    System.out.println("Thank you. You may continue");

 }//end of main method
}
public class AnimationTester
{
public static void main(String[] args)
{
    //Picture pictureObj = new Picture("");        //create a Picture object for the maze background image, has name and etc.
    World worldObj = new World();                            //create a World object to draw in
    //worldObj.setPicture(pictureObj);                         //set the maze background image in the World object
    Turtle lertle = new Turtle(300, 150, worldObj);             //create a Turtle object to do the drawing
    Animation turt = new Animation();

    Turtle dyrtle = new Turtle(150, 150, worldObj);    

    turt.prepareTurtleToDraw(lertle, Color.BLACK, 250, 150);
    turt.drawLine(lertle, 250, 150, 400, 150);
    turt.drawLine(lertle, 400, 150, 400, 250);
    turt.drawLine(lertle, 400, 250, 250, 250);
    turt.drawLine(lertle, 250, 250, 250, 150);

    turt.prepareTurtleToDraw(dyrtle, Color.RED, 150, 150);
    turt.drawLine(dyrtle, 150, 150, 260, 75);
    turt.drawLine(dyrtle, 260, 75, 335, 150);
    turt.drawLine(dyrtle, 335, 150, 225, 225);
    turt.drawLine(dyrtle, 225, 225, 150, 150);


    System.out.println(worldObj);
}    
}    

Upvotes: 1

Views: 898

Answers (1)

JYun
JYun

Reputation: 321

Well, it seems I can't upload photos I took of my program because I don't have enough reputation. Thanks!

enter image description here Figure 1. Before pressing C

enter image description here Figure 2. After pressing C


I wrote this little program for you, it is running on Java Swing to create animations. I have three rectangles, two - red and blue - fading in and out according to how much seconds have elapsed, and the third appearing and disappearing upon pressing C.

I think what may be helpful for you when dealing with animations is a "game loop." You can find my implementation of it in MainFrame.java below. Loosely speaking, a game loop controls the update speed of animations so that the program runs consistently on both slow and fast computers. If a game loop is not implemented, a fast computer may finish an animation faster than a relatively slower computer.

This is a complete program, just compile the three .java files and run Main to bring up the game interface.

Main.java

import java.lang.reflect.InvocationTargetException;

import javax.swing.SwingUtilities;

public class Main {
    public static void main(String[] args) {
        try {
            SwingUtilities.invokeAndWait(() -> {

                MainFrame mf = MainFrame.getMainFrame();
                new Thread(mf).start();

            });
        } catch (InvocationTargetException | InterruptedException e) {
            System.out.println("Could not create GUI");
        }
    }
}


MainFrame.java

import java.awt.BorderLayout;

import javax.swing.JFrame;

class MainFrame extends JFrame implements Runnable {

    private static final long serialVersionUID = 1L;
    private DisplayPanel dp;
    private boolean isRunning;
    private double secondsPerFrame = 1.0 / 60.0;
    private static MainFrame mf;

    private MainFrame() {
        super("Title");

        dp = new DisplayPanel();
        add(dp, BorderLayout.CENTER); // Add display to the center

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    /**
     * Static factory
     *
     * @return A singleton MainFrame
     */
    static MainFrame getMainFrame() {
        return mf == null ? mf = new MainFrame() : mf;
    }

    /**
     * Game loop
     */
    @Override
    public void run() {
        isRunning = true;
        int frames = 0;
        double frameCounter = 0;

        double lastTime = System.nanoTime() / 1000000000.0;
        double unprocessedTime = 0;

        while(isRunning) {
            boolean render = false;
            double startTime = System.nanoTime() / 1000000000.0;
            double passedTime = startTime - lastTime;
            lastTime = startTime;
            unprocessedTime += passedTime;
            frameCounter += passedTime;

            while(unprocessedTime > secondsPerFrame) {
                render = true;
                unprocessedTime -= secondsPerFrame;

                // Update the state of the rectangles' brightness
                dp.update(secondsPerFrame);

                if(frameCounter >= 1.0) {
                    // Show fps count. Updates every second
                    dp.setFps(frames);
                    frames = 0;
                    frameCounter = 0;
                }
            }
            if(render) {

                // Render the rectangles
                dp.render();

                frames++;
            } else {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException ie) {}
            }
        }
    }
}


DisplayPanel.java

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;

// Create a display within the window
class DisplayPanel extends Canvas implements KeyListener {

    private static final long serialVersionUID = 2L;
    private Graphics2D g2; // Drawing tool
    private BufferStrategy strategy; // Drawing tool
    private FadingRectangle[] fadingRectangles; // Appears/disappears based on elapsed time
    private FadingRectangle userControlledRectangle; // Appears/disappears upon command by user
    private int fps; // Used to display the fps on screen

    DisplayPanel() {
        setPreferredSize(new Dimension(800, 600));
        addKeyListener(this);
        setFocusable(true);

        fadingRectangles = new FadingRectangle[2];
        fadingRectangles[0] = new FadingRectangle(150, 250, 100, 100);
        fadingRectangles[1] = new FadingRectangle(550, 250, 100, 100);

        userControlledRectangle = new FadingRectangle(350, 100, 100, 100);
    }

    /**
     * Updates the brightness of rectangles
     *
     * @param elapsedSeconds Seconds elapsed since the last call to this method
     */
    void update(double elapsedSeconds) {
        fadingRectangles[0].update(elapsedSeconds);
        fadingRectangles[1].update(elapsedSeconds);
    }

    /**
     * Draw everything
     */
    void render() {
        // Prepare drawing tools
        if (strategy == null || strategy.contentsLost()) {
            createBufferStrategy(2);
            strategy = getBufferStrategy();
            Graphics g = strategy.getDrawGraphics();
            this.g2 = (Graphics2D) g;
        }

        // Anti-aliasing
        this.g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // Clear screen by drawing background on top
        this.g2.setColor(Color.BLACK);
        this.g2.fillRect(0, 0, getWidth(), getHeight());

        // Draw the rectangles
        fadingRectangles[0].draw(new Color(255, 0, 0));
        fadingRectangles[1].draw(new Color(0, 0, 255));
        userControlledRectangle.draw(Color.WHITE);

        // Draw fps count on the upper left corner
        g2.setColor(Color.WHITE);
        g2.drawString("FPS: " + Integer.toString(fps), 10, 20);

        // Set the drawn lines visible
        if(!strategy.contentsLost())
            strategy.show();
    }

    /**
     * @param fps The fps to be drawn when render() is called
     */
    void setFps(int fps) {
        this.fps = fps;
    }

    /**
     * Used to draw rectangles in the display
     */
    private class FadingRectangle {
        private int x, y, width, height; // Location and size of the rectangle
        private double secondsPassed; // Arbitrary number that determines the brightness of blue

        private FadingRectangle(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        /**
         * Called by render()
         *
         * @param color The color of the rectangle to be drawn
         */
        private void draw(Color color) {
            // Determine color
            double fade = Math.abs(Math.sin(secondsPassed));
            int red = (int) (color.getRed() * fade);
            int green = (int) (color.getGreen() * fade);
            int blue = (int) (color.getBlue() * fade);
            g2.setColor(new Color(red, green, blue));

            // Draw the rectangle
            g2.drawRect(x, y, width, height);
        }

        private void update(double elapsedSeconds) {
            secondsPassed += elapsedSeconds;
        }
    }

    // A quick and dirty implementation. Should be fixed to make it clearer
    @Override
    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_C) {
            userControlledRectangle.update(Math.PI / 2);
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {}

    @Override
    public void keyTyped(KeyEvent e) {}
}

Upvotes: 1

Related Questions