page prйcйdantetable des matiиrespage suivante

Анимация в аплети

Има разнообразни подходи за анимация в Java. Общото между тях е, че създават движение върху екрана чрез изчертаване на последователни фрейми с относително висока скорост (10-20 в секунда).

Използване на Threads

Необходимо е създаването на нова Java thread, която да включва анимационен цикъл.

Основен шаблон:

import java.applet.*
public class Example extends Applet implements Runnable {
int frame;
int delay;
Thread animator;

/**
* Initialize the applet and compute the delay between frames.
*/
public void init() { String str = getParameter("fps"); int fps = (str != null) ? Integer.parseInt(str) : 10; if(fps<=0) fps=1;
// compute the delay in ms delay = 1000 / fps; } /**
* This method is called when the applet becomes visible on
* the screen. Create a thread and start it.
*/
public void start() { animator = new Thread(this); animator.start(); } /**
* This method is called by the thread that was created in
* the start method. It does the main animation.
*/
public void run() { // Remember the starting time long tm = System.currentTimeMillis(); while (Thread.currentThread() == animator) { // Display the next frame of animation. repaint(); // Delay depends on time loose to run thread try { //compute new time to paint tm += delay;
//wait the time to paint
Thread.sleep(Math.max(0, tm - System.currentTimeMillis())); } catch (InterruptedException e) { break; } // Advance the frame frame++; } } /**
* This method is called when the applet is no longer
* visible or there is an event which will stop animation.
*
Set the animator variable to null so that the
* thread will exit before displaying the next frame.
*/
public void stop() { animator = null; }
    public void paint (Graphics g){
//paint frame
}
}

Аплетът трябва да се извика с:

<applet code=Example.class width=200 height=200>
<param name=fps value=20>
</applet>

Пример:

 

 

import java.awt.*;
import java.applet.*;
public class Example extends Applet implements Runnable {
int frame=0;
int delay;
Thread animator;

public void init() {
String str = getParameter("fps");
int fps = (str != null) ? Integer.parseInt(str) : 10;
if(fps<=0) fps=1;
// compute the delay in ms delay = 1000 / fps;         setFont(new Font("TimesRoman", Font.BOLD, 20)); } public void start() { animator = new Thread(this); animator.start(); } public void run() { // Remember the starting time long tm = System.currentTimeMillis(); while (Thread.currentThread() == animator) { // Display the next frame of animation. repaint(); try { tm += delay;
//wait the time to paint
Thread.sleep(Math.max(0, tm - System.currentTimeMillis())); } catch (InterruptedException e) { break; } // Advance the frame if(++frame == 200)frame=0; } } public void stop() { animator = null; }
    public void paint (Graphics g){
g.drawString("@", frame, 30);
} }
  фрейм в секунда

 

20 фрейма в секунда

No Java Support

 

Друг пример

import java.awt.*;
import java.applet.*;
public class AnimEx2 extends Applet implements Runnable {
int frame;
int delay;
Thread animator;

public void init() {
String str = getParameter("fps");
int fps = (str != null) ? Integer.parseInt(str) : 10;
if(fps<=0) fps=1;
// compute the delay in ms
delay = 1000 / fps;
setFont(new Font("TimesRoman", Font.BOLD, 20));

}


public void start() {
animator = new Thread(this);
animator.start();
}


public void run() {
// Remember the starting time
long tm = System.currentTimeMillis();

while (Thread.currentThread() == animator) {
// Display the next frame of animation.
repaint();

// Delay depends on time loose to run thread
try {
//compute new time to paint
tm += delay;
//wait the time to paint
Thread.sleep(Math.max(0, tm - System.currentTimeMillis()));
} catch (InterruptedException e) { break; }

// Advance the frame
++frame;
}
}

public void stop() {
animator = null;
}

public void paint(Graphics g) {
Dimension d = getSize(); //d.height d.width
int h = d.height / 2;
for (int x = 0 ; x < d.width ; x++) {
int y1 = (int)((1.0 + Math.sin((x - frame) * 0.05)) * h);
int y2 = (int)((1.0 + Math.sin((x + frame) * 0.07)) * h);
g.drawLine(x, y1, x, y2);
}
}
}
   

1 фрейм в секунда

 

No Java Support

 

15 фрейма в секунда

No Java Support

 

Намаляване на нестабилността (flashing)


Нестабилността на картината на анимацията  се дължи на две причини:
   - Изчисляването и рисуването на всеки фрейм отнема много време.
   - Целия фон се изчиства преди извикването на метода
paint().  Докато върви изчисляването на фрейма се вижда изчистения фон.

В Ms Windows това потрепване личи по-силно отколкото в X Windows ( X Windows графиката е буферирана, което прави потрепването по-късо.

Има два начина за намаляване на потрепването:
    - Предефиниране  на
update() метода.
    - Използване на двойно буфериране (
backbuffer).

 

Предефиниране  на update() метода

Когато AWT получи заявка repaint() той извиква update() метода на аплета, който изчиства фона и извиква paint() метода. 

В следващия пример update() метода е предефиниран, като не изчиства целия фон а изчиства всяка линия индивидуално преди чертането на новата.

 

    public void paint(Graphics g) {
update(g);
}


public void update(Graphics g) {
Color bgr = getBackground();
Color fgr = getForeground();
Dimension d = getSize();
int h = d.height / 2;
for (int x = 0 ; x < d.width ; x++) {
int y1 = (int)((1.0 + Math.sin((x - frame) * 0.05)) * h);
int y2 = (int)((1.0 + Math.sin((x + frame) * 0.07)) * h);

if (y1 > y2) {
int t = y1;
y1 = y2;
y2 = t;
}
g.setColor(bgr);
g.drawLine(x, 0, x, y1);
g.drawLine(x, y2, x, d.height);
g.setColor(fgr);
g.drawLine(x, y1, x, y2);
}
}
  15 фрейма в секунда

 

No Java Support

 

Двойно буфериране

Това е много често използвана техника за намаляване смущенията между анимационните фрейми. Основният принцип е създаването на изображение вън от екрана ( offscreen image) върху което се чертае и след това се извежда наведнъж на екрана чрез drawImage(). Това е много по-ефективно отколкото директното чертане на екрана. Основният недостатък е необходима много допълнителна памет при голямо поле.

import java.awt.*;
import java.applet.*;


public class AnimEx5 extends Applet implements Runnable {
int frame;
int delay;
Thread animator;

Dimension offDimension;
Image offImage;
Graphics offGraphics;


public void init() {
String str = getParameter("fps");
int fps = (str != null) ? Integer.parseInt(str) : 10;
delay = (fps > 0) ? (1000 / fps) : 100;
}

/**
Create a thread and start it.
*/
public void start() {
animator = new Thread(this);
animator.start();
}

/**
* the main animation.
*/
public void run() {
// Remember the starting time
long tm = System.currentTimeMillis();
while (Thread.currentThread() == animator) {
// Display the next frame of animation.
repaint();

// Delay depending on how far we are behind.
try {
tm += delay;
Thread.sleep(Math.max(0, tm - System.currentTimeMillis()));
} catch (InterruptedException e) {break; }

// Advance the frame
frame++;
}
}

/**
* called when the applet is no longer visible.
*/
public void stop() {
animator = null;
offImage = null;
offGraphics = null;
}

/**
* Update a frame of animation.
*/
public void update(Graphics g) {
Color fgr=getForeground();
Dimension d = getSize();

// Create the offscreen graphics context
if ((offGraphics == null)
|| (d.width != offDimension.width)
|| (d.height != offDimension.height))
{ offDimension = d;
offImage = createImage(d.width, d.height);
offGraphics = offImage.getGraphics();
}

// Erase the previous image
offGraphics.setColor(getBackground());
offGraphics.fillRect(0, 0, d.width, d.height);
offGraphics.setColor(fgr);

// Paint the frame into the image
paintFrame(offGraphics);

// Paint the image onto the screen
g.drawImage(offImage, 0, 0, this);
}


public void paint(Graphics g) {
update(g);
}

/**
* Paint a frame of animation.
*/
public void paintFrame(Graphics g) {
Dimension d = getSize();
int h = d.height / 2;
for (int x = 0 ; x < d.width ; x++) {
int y1 = (int)((1.0 + Math.sin((x - frame) * 0.05)) * h);
int y2 = (int)((1.0 + Math.sin((x + frame) * 0.07)) * h);
g.drawLine(x, y1, x, y2);
}
}
}
  15 фрейма в секунда

 

No Java Support

 

 

page prйcйdantetable des matiиrespage suivante