How to use a class-specific thread with multiple threads?

Asked

Viewed 2,018 times

2

I’m with a class called Ball where I have a thread that makes some balls move in phase 1 of a game. It is possible for me to implement in this same class another thread make the balls move differently in the case for phase 2 of the game, if possible leave an example of how I can have the 2 thread in the same class and how I can access each one.

Here is the code:

import java.awt.Rectangle;

public class Bola extends Thread {
private int x,y,tamanho;
private int direcao;
int opcao;

public Bola(int x,int y,int tamanho){
    this.x=x;
    this.y=y;
    this.tamanho=tamanho;
}

@Override

public void run() {
    super.run();
    while(1==1){

        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(x<150){
            direcao=1;

        }
        if(x>700){
            direcao=0;

        }
        if(direcao==1){
            x++;

        }
        if(direcao==0){
            x--;
        }
    }
//aqui gostaria de por outra thread, do mesmo jeito da primeira,porém vai //alterar o y...dai na classe da fase eu gostaria de chamar apenas essa thread //que altera o y

}




public Rectangle colisao(){
    return new Rectangle(x, y, tamanho, tamanho);
}


public int getX() {
    return x;
}

public void setX(int x) {
    this.x = x;
}

public int getY() {
    return y;
}

public void setY(int y) {
    this.y = y;
}

public int getTamanho() {
    return tamanho;
}

public void setTamanho(int tamanho) {
    this.tamanho = tamanho;
}

}
  • The question is half empty but speaking very generically it seems better to implement the behavior of each phase in a different class

  • 4

    Phase 1 of the game takes place simultaneously to phase 2? If not, there is no reason to create two threads... Use the same! What you need is: a) a class for each phase, as suggested by @epx; or b) a class parameterizable - if the behavior of the balls is similar in both phases, what changes is only a few meters (such as speed, acceleration, angle etc). If you have any specific questions, post excerpt(s) of the code you already have, and what is causing difficulty.

  • 1

    Can’t you put a little code in here so we can try to understand exactly how you structured this?

  • Would that question be a schoolwork?

  • The title of your question is a little weird, maybe because you’re mixing in the question an idea solution that you already have. Maybe if you change the title (and maybe even the text, I don’t know) more to what you want to do, the question attracts more people interested in answering.

4 answers

5

You don’t "access" a thread. You start it, and it keeps running. By the way, your program is already running on a thread -- what you do is start new threads.

It is possible to coordinate threads using several resources: synchronization, semaphores, shared objects, etc. But to know what is most appropriate in your case, it is necessary to define because you want a thread for each phase and what it will bring of benefit?

It would also be useful for you to show details of the existing class, to know how this thread is created and used.

3

As @rdllopes already mentioned in his reply, it is not a good practice to make your objects run in different threads, as it is very common that games have many objects and it is quite costly for the operating system to scale many threads.

In games it is more common to have only one or two threads, such as one to manage the user interface (the main thread, say) and the other to manage the game loop of the game.

You didn’t mention whether you’re playing a game just to learn programming in Java or to actually produce a game. If not for learning, it will most likely be easier (and more productive) if you use a Game Engine ready. Such tools greatly facilitate game development because they already include game loop, audio and input handling functions, and (in many cases) even libraries for physics and artificial intelligence simulation. In the case of Java, a very famous engine is the Jmonkeyengine.

In addition to the subject of the thread your question is also about how to have different behaviors in a game object (a ball). So I have prepared an example to suggest a form of implementation.

Before you start, it’s important that you familiarize yourself with vectors and with class Vector2D (by Jadrian Miles). Vectors are important in the code because they are used to represent the position of the balls and their speed.

import java.awt.geom.Point2D;
import java.lang.Math;

/**
 * An extension to the relatively impotent java.awt.geom.Point2D.Double,
 * Vector2D allows mathematical manipulation of 2-component vectors.
 * 
 * @author Jadrian Miles
 * @version 20031122
 */
public class Vector2D extends Point2D.Double {

    /*
     * (non-Javadoc)
     * 
     * @see java.awt.geom.Point2D.Double#Point2D.Double()
     */
    public Vector2D() {
        super();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.awt.geom.Point2D.Double#Point2D.Double()
     */
    public Vector2D(double x, double y) {
        super(x, y);
    }

    /**
     * Copy constructor
     */
    public Vector2D(Vector2D v) {
        x = v.x;
        y = v.y;
    }

    /**
     * @return the radius (length, modulus) of the vector in polar coordinates
     */
    public double getR() {
        return Math.sqrt(x * x + y * y);
    }

    /**
     * @return the angle (argument) of the vector in polar coordinates in the
     *         range [-pi/2, pi/2]
     */
    public double getTheta() {
        return Math.atan2(y, x);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.awt.geom.Point2D.Double#setLocation(double, double)
     */
    public void set(double x, double y) {
        super.setLocation(x, y);
    }

    /**
     * Sets the vector given polar arguments.
     * 
     * @param r
     *            The new radius
     * @param t
     *            The new angle, in radians
     */
    public void setPolar(double r, double t) {
        super.setLocation(r * Math.cos(t), r * Math.sin(t));
    }

    /** Sets the vector's radius, preserving its angle. */
    public void setR(double r) {
        double t = getTheta();
        setPolar(r, t);
    }

    /** Sets the vector's angle, preserving its radius. */
    public void setTheta(double t) {
        double r = getR();
        setPolar(r, t);
    }

    /** The sum of the vector and rhs */
    public Vector2D plus(Vector2D rhs) {
        return new Vector2D(x + rhs.x, y + rhs.y);
    }

    /** The difference of the vector and rhs: this - rhs */
    public Vector2D minus(Vector2D rhs) {
        return new Vector2D(x - rhs.x, y - rhs.y);
    }

    public boolean equals(Vector2D rhs) {
        return x == rhs.x && y == rhs.y;
    }

    /** Product of the vector and scalar */
    public Vector2D scalarMult(double scalar) {
        return new Vector2D(scalar * x, scalar * y);
    }

    /** Dot product of the vector and rhs */
    public double dotProduct(Vector2D rhs) {
        return x * rhs.x + y * rhs.y;
    }

    /**
     * Since Vector2D works only in the x-y plane, (u x v) points directly along
     * the z axis. This function returns the value on the z axis that (u x v)
     * reaches.
     * 
     * @return signed magnitude of (this x rhs)
     */
    public double crossProduct(Vector2D rhs) {
        return x * rhs.y - y * rhs.x;
    }

    /** Product of components of the vector: compenentProduct( <x y>) = x*y. */
    public double componentProduct() {
        return x * y;
    }

    /** Componentwise product: <this.x*rhs.x, this.y*rhs.y> */
    public Vector2D componentwiseProduct(Vector2D rhs) {
        return new Vector2D(x * rhs.x, y * rhs.y);
    }

    /**
     * An alias for getR()
     * @return the length of this
     */
    public double length() {
        return getR();
    }

    /**
     * Returns a new vector with the same direction as the vector but with
     * length 1, except in the case of zero vectors, which return a copy of
     * themselves.
     */
    public Vector2D unitVector() {
        if (getR() != 0) {
            return new Vector2D(x / getR(), y / getR());
        }
        return new Vector2D(0,0);
    }

    /** Polar version of the vector, with radius in x and angle in y */
    public Vector2D toPolar() {
        return new Vector2D(Math.sqrt(x * x + y * y), Math.atan2(y, x));
    }

    /** Rectangular version of the vector, assuming radius in x and angle in y*/
    public Vector2D toRect() {
        return new Vector2D(x * Math.cos(y), x * Math.sin(y));
    }

    /** @return Standard string representation of a vector: "<x, y>" */
    public String toString() {
        return "<" + x + ", " + y + ">";
    }
}

The most important class of example I have prepared is called simplemenge Game. I made it as an Applet, but you can build a Swing window, for example. The principle is the same: it implements the interface Runnable because she’s the one who implements the game loop thread! The code is following:

import java.awt.BorderLayout;

import javax.swing.JApplet;

/**
 * Classe principal, de implementação do jogo.
 * Exemplo para ilustração no SOPT.
 * @author Luiz C. Vieira
 */
@SuppressWarnings("serial")
public class Game extends JApplet implements Runnable {

    /** Thread de execução da applet. */
    private Thread m_oMainThread;

    /** Indicador de que o jogo está em execução. */
    private boolean m_bRunning;

    /** Taxa de quadros por segundo (framerate) ideal do jogo. */
    private static float FPS = 1000f / 60f; 

    /**
     * Método de inicialização da applet do jogo.
     */
    @Override
    public void init() {
        super.init();

        // Define tamanho da janela de jogo
        setSize(800, 600);

        // Adiciona a cena ao jogo
        setLayout(new BorderLayout());
        add(GameScene.instance);

        // Cria e inicia a thread de execução do jogo
        m_bRunning = true;
        m_oMainThread = new Thread(this);
    }

    /**
     * Método de início da applet do jogo.
     */
    @Override
    public void start() {
        super.start();
        m_oMainThread.start();
    }

    /**
     * Método de interrupção da applet do jogo.
     */
    @Override
    public void stop() {
        super.stop();
        m_bRunning = false;
    }

    /**
     * Método de execução da thread da applet do jogo.
     * Basicamente implementa o game loop, atualizando na cena
     * todos os componentes a cada quadro (cada iteração).
     */
    @Override
    public void run() {

        long lPrevious = System.nanoTime() / 1000000;
        long lLag = 0;

        // Gameloop do jogo
        while(m_bRunning) {

            // Contabilização de tempo
            long lCurrent = System.nanoTime() / 1000000;
            long lElapsed = lCurrent - lPrevious;
            lPrevious = lCurrent;
            lLag += lElapsed;

            // Processamento de entrada (teclado, mouse, etc) vai aqui!
            // TODO

            // Atualização do mundo!
            // Faz chamadas de update enquanto o número desejado de quadros
            // por segundo não tiver sido atingido
            while(lLag >= Game.FPS)
            {
                GameScene.instance.update();
                lLag -= Game.FPS;
            }

            // Renderização do jogo!
            GameScene.instance.repaint();

        }
    }
}

This class works like this:

  • On startup, it adds the Singleton object of the class GameScene (the set of the game) under a layout.
  • Then create a thread that will execute the method run of the object itself (this).
  • The method run contains the game loop itself. What it does is continuously run GameScene.instance.update(); (the simulation of the world) and GameScene.instance.repaint(); (the game screen update), seeking to control the refresh rate of the game frames (seek to read more about framerate and gameloop on the Internet if you no longer know what it is, because it is worth it).

The other class is called GameScene and it is merely a class that inherits from JComponent to be added to the applet, but which especially contains all the objects in the game. Note that I made this class a Singleton, but ideally you can have different instances of it for each level. That is, the idea is that this class represents the current scene or phase of the game. Here is the code:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JComponent;

/**
 * Classe de implementação de cenas de jogo.
 * @author Luiz C. Vieira
 */
@SuppressWarnings("serial")
public class GameScene extends JComponent {

    /** Referência estática do vetor da gravidade. */
    public static Vector2D GRAVITY = new Vector2D(0, 1);

    /** Referência estática dos limites do mundo. */
    public static Rectangle BOUNDS = new Rectangle(0, 0, 800, 600);

    /** Matriz com as bolas instanciadas na cena. */
    private ArrayList<Ball> m_lsBalls;

    /** Instância singleton da cena. */
    public static GameScene instance = new GameScene();

    /**
     * Construtor protegido.
     */
    protected GameScene() {
        // Cria 10 bolas aleatoriamente
        m_lsBalls = new ArrayList<Ball>();

        Color aColors[] = { Color.white, Color.blue, Color.red, Color.green, Color.orange, Color.cyan };
        Random oRnd = new Random();

        for(int i = 1; i <= 5; i++) {

            int iRadius = oRnd.nextInt(50) + 10;
            Color oColor = aColors[oRnd.nextInt(aColors.length)];

            Ball oBall = new Ball(iRadius, oColor);

            oBall.setPosition(new Vector2D(oRnd.nextDouble() * 800, oRnd.nextDouble() * 600));
            oBall.setVelocity(new Vector2D(oRnd.nextDouble() * 10, oRnd.nextDouble() * 10));

            // A primeira bola não perde velocidade!
            if(i == 1) {
                oBall.setBounciness(1);
                oBall.setVelocity(new Vector2D(5, 0));
            }

            // A terceira bola não tem gravidade!
            else if(i == 3) {
                oBall.setOwnGravity(new Vector2D(0, 0));
                oBall.setOwnGravityEnabled(true);
            }

            // A quinta bola tem a gravidade invertida (isto é, "cai pra cima")!
            else if(i == 5) {
                oBall.setOwnGravity(new Vector2D(0, -1));
                oBall.setOwnGravityEnabled(true);
            }

            m_lsBalls.add(oBall);
        }
    }

    /**
     * Método de atualização da cena. É chamado a cada quadro do jogo.
     */
    public void update() {
        // Atualiza todos os objetos em cena
        for(Ball oBall: m_lsBalls) {
            oBall.update();
        }       
    }

    /**
     * Método de pintura da cena.
     * @param g Intância com o objeto Graphics da applet para pintura. 
     */
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        // Pinta o fundo da cena (simplesmente todo branco nesse exemplo)
        g.setColor(Color.black);
        g.fillRect(0, 0, GameScene.BOUNDS.width, GameScene.BOUNDS.height);

        // Faz a repintura de cada um dos objetos em cena
        for(Ball oBall: m_lsBalls) {
            oBall.paint(g);
        }
    }

    /**
     * Getter de acesso aos objetos em cena.
     * @return ArrayList com os objetos na cena.
     */
    public ArrayList<Ball> getBalls() {
        return m_lsBalls;
    }
}

The main method of this class is the update, which is called there in the game loop to every frame of the game. What this method does looks pretty simple, but it’s critical: it calls the update method of each object in scene, so that they can update themselves properly. The method paintComponent is also important because it is where the rendering (drawing) of the scene is implemented. Note that it also executes the method paint of each object so that they can draw themselves on the screen.

IMPORTANT: The game scene is inherited from JComponent because that class (just like Jpanel, for example) already implements a painting control called double buffering. Without this control, repaint the screen to each frame (controlled by the game loop) makes the screen blink (effect known as flickering).

You will notice that in the builder of this class I create 5 balls with random size and colors. But more importantly (and related to your question) I set the balls 1, 3 and 5 with distinct "behaviors" that I defined, such as making one not obey the gravity of the world and the other not lose speed when colliding. You can play there however you want, and the big point is to control the specifics of each ball through attributes and class changes Ball.

By the way (and finally!), here is the class code Ball:

    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Rectangle;
    import java.util.ArrayList;

    /**
     * Classe bola para exemplificação no SOPT.
     * Ela não implementa thread! Esse controle fica por parte das classes
     * Game e GameScene que executam o método update.
     * @author Luiz C. Vieira
     */
    public class Ball {

        /** Vetor com a posição atual da bola. */
        private Vector2D m_vPosition;

        /** Vetor velocidade (direção de movimentação + velocidade do movimento) da bola. */
        private Vector2D m_vVelocity;

        /** Raio da bola pixels. */
        private int m_iRadius;

        /** Cor da bola. */
        private Color m_oColor;

        /** Indicador a respeito da bola usar a própria gravidade. */
        private boolean m_bOwnGravity;

        /** Vetor de gravidade específico para a bola. */
        private Vector2D m_vOwnGravity;

        /** Indicação de modo de depuração, para desenho do vetor velocidade. */
        private static boolean DEBUG = true;

        /**
         * Fator de ressalto da bola, indicando qual proporção da velocidade a bola deve
         * perder ao se chocar (colidir) com outro objeto no mundo. Valores válidos são
         * no intervalo [0, 1]. O valor 0 indica que a bola simplesmente não quica (isto é,
         * para completamente ao se chocar com algo). O valor 1 indica que a bola quica totalmente
         * (isto é, não perde velocidade alguma ao se chocar).
         */
        private float m_fBounciness;

        /**
         * Construtor padrão. Inicializa a bola com valores predefinidos.
         */
        public Ball() {
            m_iRadius = 25;
            m_fBounciness = 0.8f;
            m_vPosition = new Vector2D(0, 0);
            m_vVelocity = new Vector2D(0, 0);
            m_oColor = Color.red;
            m_bOwnGravity = false;
            m_vOwnGravity = new Vector2D(0, 1);
        }

        public Ball(int iRadius, Color oColor) {
            m_iRadius = iRadius;
            m_fBounciness = 0.8f;
            m_vPosition = new Vector2D(0, 0);
            m_vVelocity = new Vector2D(0, 0);
            m_oColor = oColor;
            m_bOwnGravity = false;
            m_vOwnGravity = new Vector2D(0, 1);
        }

        /**
         * Getter da posição atual da bola.
         * @return Vetor com a posição atual da bola.
         */
        public Vector2D getPosition() {
            return m_vPosition;
        }

        /**
         * Setter da posição atual da bola.
         * @param vPosition Vetor com a nova posição para a bola.
         */
        public void setPosition(Vector2D vPosition) {
            m_vPosition = vPosition;
        }

        /**
         * Getter da velocidade da bola.
         * @return Vetor com a velocidade atual da bola.
         */
        public Vector2D getVelocity() {
            return m_vVelocity;
        }

        /**
         * Setter da velocidade da bola.
         * @param vVelocity Vetor com a nova velocidade da bola.
         */
        public void setVelocity(Vector2D vVelocity) {
            m_vVelocity = vVelocity;
        }

        /**
         * Getter do raio da bola.
         * @return Raio da bola em pixels.
         */
        public int getRadius() {
            return m_iRadius;
        }

        /**
         * Setter do raio da bola.
         * @param iRadius Novo raio da bola, em pixels.
         */
        public void setRadius(int iRadius) {
            m_iRadius = iRadius;
        }

        /**
         * Getter do fator de ressalto da bola.
         * @return Float com o fator de ressalto da bola, no intervalo [0, 1].
         */
        public float getBounciness() {
            return m_fBounciness;
        }

        /**
         * Setter do fator de ressalto da bola.
         * @param fBounciness Float com o fator de ressalto da bola, no intervalo [0, 1].
         * Valores fora do intervalo são ajustados para a extremidade limitante.
         */
        public void setBounciness(float fBounciness) {
            if (fBounciness < 0.0f)
                m_fBounciness = 0.0f;
            else if(fBounciness > 1.0f)
                m_fBounciness = 1.0f;
            else
                m_fBounciness = fBounciness;
        }

        /**
         * Getter da indicação de gravidade específica da bola habilitada.
         * @return Booleano indicando se está ou não habilitada.
         */
        public boolean getOwnGravityEnabled() {
            return m_bOwnGravity;
        }

        /**
         * Setter da indicação de gravidade específica da bola habilitada.
         * @param bEnable Booleano indicando se deve ou não habilitar.
         */
        public void setOwnGravityEnabled(boolean bEnabled) {
            m_bOwnGravity = bEnabled;
        }

        /**
         * Getter da gravidade específica da bola.
         * @return Vetor com a gravidade específica da bola.
         */
        public Vector2D getOwnGravity() {
            return m_vOwnGravity;
        }

        /**
         * Setter da gravidade específica da bola.
         * @param vOwnGravity Vetor com a nova gravidade específica da bola.
         */
        public void setOwnGravity(Vector2D vOwnGravity) {
            m_vOwnGravity = vOwnGravity;
        }

        /**
         * Método de desenho da bola. É chamado pela cena sempre que for necessário
         * repintar a bola.
         * @param g Instância do objeto Graphics para pintura da bola.
         */
        public void paint(Graphics g) {
            // Simplesmente desenha no Graphics uma bola (mas poderia copiar uma
            // imagem ou um quadro de uma animação).
            Vector2D vTopLeft = new Vector2D(m_vPosition.x - m_iRadius, m_vPosition.y - m_iRadius);
            int iDiameter = 2 * m_iRadius;
            g.setColor(m_oColor);
            g.fillOval((int) vTopLeft.x, (int) vTopLeft.y, iDiameter, iDiameter);

            // Se a depuração está ligada, desenha o vetor velocidade
            if(Ball.DEBUG) {
                g.setColor(Color.yellow);
                Vector2D vVel = m_vVelocity.scalarMult(10); // Escala x10 para facilitar a visualização
                Vector2D vAux = m_vPosition.plus(vVel);
                g.drawLine((int) m_vPosition.x, (int) m_vPosition.y, (int) vAux.x, (int) vAux.y);
            }
        }

        /**
         * Método de atualização do objeto. É chamado a cada quadro do jogo.
         */
        public void update() {
            // Adiciona a gravidade à velocidade da bola
            // Ou seja: Velocidade = Velocidade + Gravidade
            if(!m_bOwnGravity)
                m_vVelocity = m_vVelocity.plus(GameScene.GRAVITY);
            else
                m_vVelocity = m_vVelocity.plus(m_vOwnGravity);

            // Atualiza a posição da bola de acordo com a velocidade (direção e valor)
            m_vPosition = m_vPosition.plus(m_vVelocity);

            // Trata colisões com o mundo e com outras bolas
            handleCollisions();
        }

        /**
         * Método de tratamento das colisões. Simplesmente inverte o vetor nos eixos x e y quando
         * a bola se choca com as bordas do mundo, e calcula o vetor inverso à direção em que as bolas
         * se chocam umas com as outras.
         * OBSERVAÇÃO: É apenas um exemplo BEM SIMPLES, não inclui cálculos da física relativos à quantidade
         * de movimento, coeficientes de restituição, energia elástica, etc.  
         */
        protected void handleCollisions() {
            boolean bCollided = false;

            // Primeiro, trata a colisão com os limites do mundo, simplesmente invertendo
            // a velocidade de acordo com a borda com que a bola colidir.
            Rectangle oBounds = GameScene.BOUNDS;
            if(m_vPosition.x - m_iRadius <= oBounds.x) {
                m_vPosition.x = oBounds.x + m_iRadius;
                m_vVelocity.x *= -1;
                bCollided = true;
            }
            else if(m_vPosition.x + m_iRadius >= oBounds.width) {
                m_vPosition.x = oBounds.width - m_iRadius;
                m_vVelocity.x *= -1;
                bCollided = true;
            }

            if(m_vPosition.y - m_iRadius <= oBounds.y) {
                m_vPosition.y = oBounds.y + m_iRadius;
                m_vVelocity.y *= -1;
                bCollided = true;
            }
            else if(m_vPosition.y + m_iRadius >= oBounds.height) {
                m_vPosition.y = oBounds.height - m_iRadius;
                m_vVelocity.y *= -1;
                bCollided = true;
            }

            // Agora, trata a colisão da bola com as demais bolas
            ArrayList<Ball> lsBalls = GameScene.instance.getBalls();
            for(Ball oOtherBall: lsBalls) {
                if(!oOtherBall.equals(this)) { // Naturalmente, ignora a si próprio

                    // Checar colisão entre círculos é beeeeemmmm fácil!
                    // Duas bolas estão em colisão se a distância entre seus pontos
                    // centrais for menor ou igual do que a soma de seus raios.
                    double dDistance = m_vPosition.distance(oOtherBall.getPosition());
                    if(dDistance <= m_iRadius + oOtherBall.getRadius()) {

                        // Obtém o vetor unitário (normalizado) que aponta para a direção em que a bola colidou com a outra.
                        // Simples aritmética de vetores: http://en.wikipedia.org/wiki/Euclidean_vector"fora"
                        // da outra bola
                        Vector2D vAway = new Vector2D(vForceDir.x, vForceDir.y);
                        vAway.setR(m_iRadius + oOtherBall.getRadius());
                        m_vPosition = oOtherBall.getPosition().plus(vAway);

                        // A "força" com que a bola será ricocheteada é igual à soma das velocidades das duas bolas
                        double dSpeed = m_vVelocity.length() + oOtherBall.getVelocity().length();
                        Vector2D vForce = new Vector2D(vForceDir.x, vForceDir.y);
                        vForce = vForce.scalarMult(dSpeed);

                        // Soma o vetor força com a velocidade da bola
                        m_vVelocity = m_vVelocity.plus(vForce);
                        bCollided = true;
                    }
                }
            }

            // Aplica o fator de ressalto à bola se ela colidiu com algo
            if(bCollided)
                m_vVelocity = m_vVelocity.scalarMult(m_fBounciness);
        }
    }

This class uses and abuses vectors, and I honestly hope that the comments help you understand (if you don’t already understand enough of the subject - if you understand, I’m sorry I’m so didactic). But the most important thing is that you will notice that she does not inherit anything! The key point are, again, the methods update and paint. In the method update, the speed of the ball is updated with gravity and the collisions are checked (to decrease a small part of the speed at each collision and to change the direction of speed as the collisions). Already in the method paint the ball is simply drawn. I made a very silly example, but you can draw an image or even an animation (drawing one frame at a time each call paint, for example).

The "physics simulation" (if it can be called like that) is innocent beeeemmmm, but serves to exemplify (and to make everything more fun!). The end result is a window with 5 balls that move and collide with each other, something as illustrated in the figure below:

inserir a descrição da imagem aqui

The yellow lines are debugging and indicate the speed vectors. Turn off doing Ball.DEBUG = false;.

And that’s it. Good luck with your game. :)

  • 1

    thank you guys, I gathered a little of each one’s answer and implemented the thread in the same class,created a logic here that worked, thank you!

1

Well, you don’t "should", but you can do an Object extend class and use it in a simulation.

Ex:

public class Bola
    extends Thread {

    private float directionX;
    private float posX = 0;
    private boolean should_run;

    Bola(float x, float posX) {
        directionX = x;
        should_run = true;
    }

    @Override
    public void run() {
        while (should_run) {
            posX = posX + directionX;
            System.out.println(this + "\tposX:" + posX);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
                should_run = false;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Bola[] bolas =
            { new Bola(1, 0), new Bola(-1, 0) };
        for (Bola bola : bolas) {
            bola.start();
        }
        Thread.sleep(1000);
        bolas[0].should_run = false;
        bolas[1].should_run = false;
        Thread.sleep(100);
    }
}

And why shouldn’t I? Imagine your simulation has a million balls (particles). Although this one-thread-per-object model is conveniently simple, in the end the impact of having a million thread spinning would be huge. It would be much better to use a Thread Pool (or use some other more advanced parallelization mechanism) and implement each particle as a task (Task).

0

If you want to independently control each Thread you must save reference to each object created from your Runnable and use the standard Thread Lifecycle methods to control it. View this PDF http://www.inf.puc-rio.br/~inf1621/Java2.pdf that describes well how it works.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.