Souparno Paul
Souparno Paul

Reputation: 27

Moving objects on screen

I am trying to move two spheres simultaneously on screen. However, they are not moving independent of each other. Instead one is dependent on the other's movement. Please help me out. This is the code :-

Draw

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    class Draw extends JPanel implements ActionListener
    {
        Timer timer[] = new Timer[2];
        int velX = 2, velY = 2;
        Sphere sphere[] = new Sphere[2];
        public Draw()
        {
            for(int i=0;i<2;i++)
            {
                sphere[i] = new Sphere();
                timer[i] = new Timer(5,this);
            }
        }
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            for(int i=0;i<2;i++)
                drawing(g,sphere[i].color,sphere[i].radius);
        } 
        public void drawing(Graphics g,Color color, int radius)
        {
             for(int i=0;i<2;i++){
                g.setColor(color);
                g.fillOval(sphere[i].x,sphere[i].y,radius*2,radius*2);
                timer[i].start();
            }
        }
        public void actionPerformed(ActionEvent evt)
        {
            for(int i=0;i<2;i++){
            if(sphere[i].x<0 || sphere[i].x>970)
            {
                velX = -velX;
            }
            if(sphere[i].y<0 || sphere[i].y>650)
            {
                velY = -velY;
            }
            sphere[i].x += velX;
            sphere[i].y += velY;
            repaint();
        }
        }
        public static void main(String args[])
        {
            JFrame jf = new JFrame("Renderer");
            jf.getContentPane().add(new Draw(),BorderLayout.CENTER);
            jf.setBounds(0,0,1024,720);
            jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            jf.setVisible(true);
        }
    }

Sphere

    import java.awt.Color;
    class Sphere
    {
        public int x;
        public int y;
        public int radius;
        Color color;
        public Sphere()
        {
            this.x = (int)(Math.random()*800);
            this.y = (int)(Math.random()*600);
            this.radius = (int)(Math.random()*50);
            this.color = new Color((int)(Math.random()*255),
    (int)(Math.random()*255),(int)(Math.random()*255));
        }
        public Sphere(int x,int y,int radius, Color color)
        {
            this.x = x;
            this.y = y;
            this.radius = radius;
            this.color = color;
        }
    }

Upvotes: 0

Views: 81

Answers (3)

MadProgrammer
MadProgrammer

Reputation: 347214

Your x/y delta is the same for both objects, you need to contain these values within the Sphere object, for example

class Sphere {

    int velX;
    int velY;

    public int x;
    public int y;
    public int radius;
    Color color;

    public Sphere(int xDelta, int yDelta) {
        velX = xDelta;
        velY = yDelta;
        this.x = (int) (Math.random() * 800);
        this.y = (int) (Math.random() * 600);
        this.radius = (int) (Math.random() * 50);
        this.color = new Color((int) (Math.random() * 255),
                                                     (int) (Math.random() * 255), (int) (Math.random() * 255));
    }

    void move(Dimension size) {
        x += velX;
        y += velY;

        if (x < 0) {
            x = 0;
            velX *= -1;
        } else if (x + (radius * 2) > size.width) {
            x = size.width - (radius * 2);
            velX *= -1;
        }
        if (y < 0) {
            y = 0;
            velY *= -1;
        } else if (y + (radius * 2) > size.height) {
            y = size.height - (radius * 2);
            velY *= -1;
        }
    }

    public Sphere(int x, int y, int radius, Color color) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
    }

}

Then, in your actionPerformed method, you simply call update...

@Override
public void actionPerformed(ActionEvent evt) {
    for (int i = 0; i < 2; i++) {
        sphere[i].move(getSize());
    }
    repaint();
}

Additionally, you don't need two Timers, you only need one, which can be used to update both sphere's each time it's ticked...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

class Draw extends JPanel implements ActionListener {

    Timer timer;
    Sphere sphere[] = new Sphere[2];

    public Draw() {
        Random rnd = new Random();
        for (int i = 0; i < 2; i++) {
            sphere[i] = new Sphere(rnd.nextInt(4) + 1, rnd.nextInt(4) + 1);
        }
        timer = new Timer(16, this);
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < 2; i++) {
            drawing(g, sphere[i].color, sphere[i].radius);
        }
    }

    public void drawing(Graphics g, Color color, int radius) {
        for (int i = 0; i < 2; i++) {
            g.setColor(color);
            g.fillOval(sphere[i].x, sphere[i].y, radius * 2, radius * 2);
        }
    }

    @Override
    public void actionPerformed(ActionEvent evt) {
        for (int i = 0; i < 2; i++) {
            sphere[i].move(getSize());
        }
        repaint();
    }

    public static void main(String args[]) {
        JFrame jf = new JFrame("Renderer");
        jf.getContentPane().add(new Draw(), BorderLayout.CENTER);
        jf.setBounds(0, 0, 1024, 720);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);
    }

    class Sphere {

        int velX;
        int velY;

        public int x;
        public int y;
        public int radius;
        Color color;

        public Sphere(int xDelta, int yDelta) {
            velX = xDelta;
            velY = yDelta;
            this.x = (int) (Math.random() * 800);
            this.y = (int) (Math.random() * 600);
            this.radius = (int) (Math.random() * 50);
            this.color = new Color((int) (Math.random() * 255),
                                                         (int) (Math.random() * 255), (int) (Math.random() * 255));
        }

        void move(Dimension size) {
            x += velX;
            y += velY;

            if (x < 0) {
                x = 0;
                velX *= -1;
            } else if (x + (radius * 2) > size.width) {
                x = size.width - (radius * 2);
                velX *= -1;
            }
            if (y < 0) {
                y = 0;
                velY *= -1;
            } else if (y + (radius * 2) > size.height) {
                y = size.height - (radius * 2);
                velY *= -1;
            }
        }

        public Sphere(int x, int y, int radius, Color color) {
            this.x = x;
            this.y = y;
            this.radius = radius;
            this.color = color;
        }

    }
}

Also, you shouldn't be starting the timers in the "paint" pass, they should be started before hand

Upvotes: 3

anacron
anacron

Reputation: 6721

Move the velX and velY into the Sphere class. So each Sphere will maintain its own velocity. Then the spheres will move independent of each other.

There is no need of two Timers. I've cleaned it up. I also cleaned up the paintComponent method. No need of loops in two places.

Here's what I tried and it seems to work for me:


public class Draw extends JPanel implements ActionListener {
    Sphere sphere[] = new Sphere[2];

    public Draw() {
        for (int i = 0; i < 2; i++) {
            sphere[i] = new Sphere();
        }
        Timer timer = new Timer(5, this);
        timer.start();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        drawing(g);
    }

    public void drawing(Graphics g) {
        for (int i = 0; i < 2; i++) {
            g.setColor(sphere[i].color);
            g.fillOval(sphere[i].x, sphere[i].y, sphere[i].radius * 2, sphere[i].radius * 2);
        }
    }

    public void actionPerformed(ActionEvent evt) {
        for (int i = 0; i < 2; i++) {
            if (sphere[i].x < 0 || sphere[i].x > 970) {
                sphere[i].velX = -sphere[i].velX;
            }
            if (sphere[i].y < 0 || sphere[i].y > 650) {
                sphere[i].velY = -sphere[i].velY;
            }
            sphere[i].x += sphere[i].velX;
            sphere[i].y += sphere[i].velY;
            repaint();
        }
    }

    public static void main(String args[]) {
        JFrame jf = new JFrame("Renderer");
        jf.getContentPane().add(new Draw(), BorderLayout.CENTER);
        jf.setBounds(0, 0, 1024, 720);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);
    }
}

class Sphere {
    public int x;
    public int y;
    public int radius;
    Color color;
    int velX;
    int velY;

    public Sphere() {
        this.x = (int) (Math.random() * 800);
        this.y = (int) (Math.random() * 600);
        this.radius = (int) (Math.random() * 50);
        this.color = new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
        velX = new Random().nextInt()%5 + 2;
        velY = new Random().nextInt()%5 + 2;
    }

    public Sphere(int x, int y, int radius, Color color) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
    }
}

Hope this helps!

Upvotes: 2

Nil Llisterri
Nil Llisterri

Reputation: 867

Both Spheres share the same speed, so their movements will be similar.

int velX = 2, velY = 2;

If in the Sphere creation you set a random speed for each of them the movement will be different.

Upvotes: 2

Related Questions