Java анимация и менеджер перекрасок
Просто надеясь, что люди помогут мне правильно понять, как работает RepaintManager при попытке создания анимации. По сути, я создаю программу, которая рисует и обновляет существа / изображения в JFrame. Каждый объект существа содержит всю информацию для рисования, такую как координаты x,y и BufferedImage. В настоящее время каждый раз, когда объект существа перемещается, он вызывает repaint(), который, как вы увидите ниже в моем методе paint / paintComponent (не уверен, что это лучше), будет выполнять цикл по всем существующим существам и обновлять их положение и графику на экране.,
Итак, мой запрос, это лучший способ сделать это, поскольку я обеспокоен тем, что RepaintManager перерисовывает все на экране, что не очень эффективно. Я прочитал несколько постов / статей об обрезке или переопределении методов обновления, но я просто не могу понять их - так возможно ли, чтобы каждый раз, когда вызывался перерисовка, он обновлял только те объекты / существа, которые изменились?
Некоторый код того, о чем я говорю:
public void paintComponent (Graphics g) {
super.paintComponent(g);
//setDoubleBuffered(true); //Probably not needed?
Graphics2D g2d = (Graphics2D) g;
//Draws the land area for penguins.
g2d.setColor(new Color(121,133,60));
g2d.fill3DRect(land.x, land.y, land.width, land.height, true);
//OR g2d.fill(land);
g2d.setColor(Color.BLUE);
g2d.fill(sea);
drawCreatures(g2d);
}
Вся графика в методе рисования не изменится и не должна быть перекрашена, однако метод ниже...
private void drawCreatures(Graphics2D g2d) {
try {
for (Creature c : crlist) {
g2d.drawImage(c.createImage(txs,tys), c.getPos(1).width, c.getPos(1).height, this);
//g2d.drawImage(cImg,c.getPos(1).width,c.getPos(1).height,this);
if (c instanceof Fish && c.getMating().equals(Mating.WBABY)) {
int xos=0;
for (Creature fb : c.getChildren()) {
if (fb.getMating().equals(Mating.BABY)) g2d.drawImage(fb.createImage(txs,tys),c.getPos(1).width+xos,c.getPos(1).height+50,txs/2,tys/2,this);
xos+=25;
}
}
if (c.getInfo()==true) displayInfo(g2d,c); //This changes when a creature is clicked on.
else if (c.getState()!=State.NORMAL || c.getMating().equals(Mating.LOVE)) drawState(g2d,c); //updated through a creature's move/search methods.
}
}
catch(ConcurrentModificationException cme) { System.out.println("CME ERROR!"); }
}
Важной частью является первая строка расширенного цикла for, поскольку он рисует изображения в окне JFrame. Метод createImage просто получает изображение существ и конвертирует / модифицирует, например, переворачивает его, когда они двигаются влево, прежде чем его использует краска.
Анимация в настоящее время обрабатывается каждым существом, использующим Поток, однако мне также интересно, будет ли лучше Таймер Swing, поскольку в настоящее время я получаю исключение ConcurrentModificationException, когда существо пытается добавить новое существо в crlist.
private class Creature implements Behaviours<Creature>, Runnable {
//...variables
//...constructor
//...methods for updating the creature/object
@Override
public void run() {
while (getState()!=State.DEAD) {
move(); //where the coordinates of a creature is updated.
repaint();
try { Thread.sleep(1000); }
catch(InterruptedException e) {}
}
}
Таким образом, каждые 1 секунду для каждого движения существа и перерисовки вызывается, но я бы хотел, чтобы способ не проходил по циклу через каждое существо в краске, или чтобы при вызове перекраски он обновлял только существо, которое его вызвало.
Будем благодарны за любые предложения или просто указание мне на другой пост. Благодарю.
1 ответ
Вы можете использовать этот код. Вы должны расширить свои объекты рисования на PaintObject, фон, а также. и реализовать свою краску по-своему. Я надеюсь, что этот код может дать вам идею. Вы можете собрать всю площадь, которую нужно перекрасить. затем найдите, какой объект находится там. после, перекрасим только эту область
class GameCanvas extends Canvas {
private static final int FPS = 24;
private boolean isAlive;
private Vector<PaintObject> allObjects = new Vector<Rec.PaintObject>();
private Vector<Rectangle> paintingClipsInTurn = new Vector<Rectangle>();
public GameCanvas() {
isAlive = true;
new Thread(){
@Override
public void run() {
while(isAlive){
long ti1 = System.currentTimeMillis();
repaint();
long ti2 = System.currentTimeMillis();
long frameTime = ti2-ti1;
long targetFrameTime = 1000/FPS;
if (targetFrameTime > frameTime){
try {
Thread.sleep(targetFrameTime - frameTime);
} catch (InterruptedException e){
}
}
}
}
}.start();
}
@Override
public void paint(Graphics g) {
if (paintingClipsInTurn.size() > 0) {
Rectangle s = paintingClipsInTurn.get(0);
int min_x = s.x;
int min_y = s.y;
int max_x = s.x + s.width;
int max_y = s.y + s.height;
for (Rectangle r : paintingClipsInTurn) {
if (r.x < min_x)
min_x = r.x;
if (r.y < min_y)
min_y = r.y;
if (r.x + r.width > max_x)
max_x = r.x + r.width;
if (r.y + r.height > max_y)
max_y = r.y + r.height;
}
Rectangle totalclip = new Rectangle(min_x, min_y, max_x-min_x, max_y-min_y);
for (PaintObject object : allObjects) {
Rectangle r1 = object.getClip();
if (totalclip.intersects(r1)){
object.paintObject(g);
}
}
}
paintingClipsInTurn.clear();
}
public void addDrawComponent(PaintObject object){
object.parent = this;
allObjects.add(object);
}
public void removeDrawComponent(PaintObject object){
object.parent = null;
allObjects.remove(object);
}
void requestRepaint(PaintObject object){
paintingClipsInTurn.add(object.getClip());
}
}
abstract class PaintObject {
GameCanvas parent;
private int x,y,w,h;
public void setPosition(int x,int y,int w,int h){
if (parent != null) parent.requestRepaint(this);
this.x = x;
this.y = y;
this.w = w;
this.h = h;
if (parent != null) parent.requestRepaint(this);
}
Rectangle getClip(){
Rectangle rect = new Rectangle();
rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;
return rect;
}
void paintObject(Graphics g){
g.translate(x, y);
Shape oldClip = g.getClip();
g.setClip(0, 0, w, h); // in here you have to actually find intersection of current clip and object clip. this code needs to be fixed.
paint(g);
g.setClip(oldClip);
g.translate(-x, -y);
}
public abstract void paint(Graphics g);
}