001    /**
002    * @author Václav Mikolášek
003    * nicklaus@students.zcu.cz
004    */
005    
006    package animace;
007    
008    import javax.swing.*;
009    import java.awt.*;
010    import java.awt.image.*;
011    import java.util.*;
012    
013    /**
014     * Třída Driver poskytuje vlákno, které má za úkol pohybovat
015     * s jedním objektem typu Moveable. Pričemž umožňuje použití
016     * PaintControleru, který zaručuje, že s objektem není proveden
017     * dalši pohyb, dokud není stará pozice objektu vykreslena
018     */
019    public class Driver extends Thread {
020            private Moveable object;                // s timto objektem se bude pohybovat
021            private float step      = 1f;           // znamena o kolik pixelu se posouva za jedno kolo
022            private float stepCount = 0f;           // znamena o kolik pixelu se jiz pohnul;
023            private float dirX      = -1f;          // dirX a dirY urcuji, kterym smerem se objekt pohybuje
024            private float dirY      = 1f;           
025            private int locationX   = 0;            // souradnice pozice obdelniku, ve kterem se muze objekt pohybovat
026            private int locationY   = 0;                    
027            private int width       = 0;            // rozmer oblasti, ve ktere se objekt pohybuje
028            private int height      = 0;            
029            private boolean goes    = false;        // zda jede nebo stoji
030            private long time       = -1;   
031            private PaintControl pc = null;         // PaintControl pc
032                            
033            /**
034            * Vytvoří řidiče pro objekt implemenujicí rozhraní Moveable. Objekt se bude pohybovat
035            * v obdelníku určeném parametry locationX, locationY (umístěni), width a height
036            * @param object Moveable objekt, s kterým bude Driver lomcovat.
037            * @param locationX ukotvení na ose x oblasti (obdélníku), ve kterém se objekt pohybuje.
038            * @param locationY ukotvení téže oblasti na ose y.
039            * @param width šířka oblasti.
040            * @param height výška oblasti.
041            */
042            public Driver(Moveable object,int locationX,int locationY,int width,int height) { 
043                    this.object = object;
044                    this.locationX = locationX;
045                    this.locationY = locationY;
046                    this.width = width;
047                    this.height = height;
048            }
049            
050            /**
051            * Touto metodou lze uvést "Drivera" do pohybu
052            */
053            public void start() {
054                    this.goes = true;
055                    super.start();
056            }
057            
058            /**
059             * Podavá informaci o stavu řidiče.
060             */
061            public boolean goes() {
062                    return goes;
063            }
064            /**
065             * Zastaví řidiče
066             */
067            public void stopDriving() {
068                    goes = false;    
069            }
070            /**
071             * Vrací údaj o tom, jak dlouho vlákno běželo.
072             */
073            public long getTime() {
074                    return time;
075            }
076    
077            /**
078             * Nastaví směr jakým se bude objekt pohybovat, mají smysl pouze celá čísla, protože
079             * location se uchovává v celých číslech.
080             */
081            public void setDir(float dirX, float dirY) {
082                    this.dirX = dirX;
083                    this.dirY = dirY;
084            }
085    
086            /**
087             * Program běhu vlákna. Vlákno se rozeběhne a beží dokud jej nějaké jiné vlákno
088             * nezastaví voláním <tt>stopDriving()</tt> nebo až se objekt 5000x posune.
089             */ 
090            public synchronized void run() {
091                    stepCount = 0;
092                    step = 1f;
093                    long timeAtStart = System.currentTimeMillis();
094                    
095                    /// zacni pocitat fps
096                    if (pc != null) {
097                            pc.fps(true);
098                    }
099                    while (goes && stepCount < 5000) {
100                            move();
101                            stepCount++;
102                            if (pc != null) {
103                                    pc.objectMoved();
104                            }
105                            else {
106                                    try { sleep(10);}
107                                    catch (InterruptedException e) {;}
108                            }
109                    }
110                    goes = false;
111                    /// kdyz dobehl, uz nepocitej FPS
112                    if (pc != null) {
113                            pc.fps(false);
114                    }
115                    long timeAtStop = System.currentTimeMillis();
116                    this.time = timeAtStop - timeAtStart;
117            }
118            
119            /**
120             * Tato metoda implementuje jednoduchý algoritmus pohybu
121             * pohne s objektem, vždy pouze o jeden "step", implicitně nastaven na 1 pixel
122             */
123            private void move() {
124                    Point location = object.getLocation();
125                    if (location.x < locationX - (step * dirX)) {
126                            dirX = Math.abs(dirX);
127                    }
128                    if (location.x > width - (step * dirX)) {
129                            dirX = -Math.abs(dirX);
130                    }
131                    if (location.y < locationY - (step * dirY)) {
132                            dirY = Math.abs(dirY);
133                    }
134                    if (location.y > height - (step * dirY)) {
135                            dirY = -Math.abs(dirY);
136                    }
137                    
138                    object.setLocation(Math.round(location.x +  (dirX * step)), Math.round(location.y + (dirY * step)));
139            }
140            
141            /**
142             * Umožní nastavit kontrolu, která se startá o průběh vykreslování objektu
143             */
144            public void setPaintControl(PaintControl pc) {
145                    this.pc = pc;
146            }
147    }