У меня есть эта картина (все эти эффекты находятся в одном.png файле). Я хочу отобразить, например, второе изображение, как я могу использовать Image и ImageView в javafx для отображения определенной части этого изображения? благодаря
Этот ответ излишне. Но с хорошим набором изображений, как у вас в вашем вопросе, может быть, излишний - это то, что требуется :-)
Фундаментальный дизайн такой же, как Улук, он просто настраивает Видовой экран ImageView, а не устанавливает клип, но концепция такая же.
Beware => Java 8
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.event.*;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
class ExploadableImageView extends ImageView {
private final Rectangle2D[] cellClips;
private int numCells;
private final Duration FRAME_TIME = Duration.seconds(.5);
public ExploadableImageView(Image explosionImage, int numCells) {
this.numCells = numCells;
double cellWidth = explosionImage.getWidth() / numCells;
double cellHeight = explosionImage.getHeight();
cellClips = new Rectangle2D[numCells];
for (int i = 0; i < numCells; i++) {
cellClips[i] = new Rectangle2D(
i * cellWidth, 0,
cellWidth, cellHeight
);
}
setImage(explosionImage);
setViewport(cellClips[0]);
}
public void explode(EventHandler<ActionEvent> onFinished) {
final IntegerProperty frameCounter = new SimpleIntegerProperty(0);
Timeline kaboom = new Timeline(
new KeyFrame(FRAME_TIME, event -> {
frameCounter.set((frameCounter.get() + 1) % numCells);
setViewport(cellClips[frameCounter.get()]);
})
);
kaboom.setCycleCount(numCells);
kaboom.setOnFinished(onFinished);
kaboom.play();
}
}
class ExplodableItem extends StackPane {
public ExplodableItem(Image objectImage, Image explosionImage, int numCells) {
ImageView objectView = new ImageView(objectImage);
ExploadableImageView explosionView = new ExploadableImageView(
explosionImage, numCells
);
setMinSize(
Math.max(
objectImage.getWidth(),
explosionView.getViewport().getWidth()
),
Math.max(
objectImage.getHeight(),
explosionView.getViewport().getHeight()
)
);
objectView.setPickOnBounds(false);
objectView.setOnMouseClicked(event -> {
getChildren().setAll(explosionView);
explosionView.explode(complete -> getChildren().setAll(objectView));
});
DropShadow drop = new DropShadow(10, Color.GOLD);
drop.setInput(new Glow());
objectView.setOnMouseEntered(event -> objectView.setEffect(drop));
objectView.setOnMouseExited(event -> objectView.setEffect(null));
getChildren().setAll(objectView);
}
}
public class CatWhack extends Application {
public static void main(String[] args) {
launch(args);
}
private static final int NUM_CELLS_PER_EXPLOSION = 6;
@Override
public void start(Stage stage) {
Image objectImage = new Image("http://icons.iconarchive.com/icons/iconka/meow/96/cat-box-icon.png"); // cat icon linkware: backlink to http://www.iconka.com required
// looks likes imgur may have blocked direct access to following png from a Java app (somehow).
// but you can still download the QMqbQ.png from that location
// and save it locally in the same directory as the CatWhack program
// then pick it up by replacing the new Image call with:
// new Image(CatWhack.class.getResourceAsStream("QMqbQ.png"));
Image explosionImage = new Image("http://i.stack.imgur.com/QMqbQ.png");
TilePane tiles = new TilePane();
tiles.setPrefColumns(4);
for (int i = 0; i <16; i++) {
tiles.getChildren().add(
new ExplodableItem(objectImage, explosionImage, NUM_CELLS_PER_EXPLOSION)
);
}
tiles.setMinSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
stage.setTitle("Cat Whack - Click a cat to whack it!");
stage.setScene(new Scene(tiles));
stage.show();
}
}
Простой пример
Вот та же концепция, что и в вышеприведенной игре, но просто с более простой системой анимированного изображения, которую можно контролировать с помощью вызовов методов, а не щелчков мыши мыши на изображении.
Анимированное изображение похоже на Sprite. Код, приведенный ниже, не предназначен для создания системы Sprite качества производства (вероятно, настоящая система Sprite для игры будет иметь больше функций и функций), она просто демонстрирует очень простое отображение анимированного изображения на основе Viewport.
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.ToggleButton;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
class Sprite extends ImageView {
private final Rectangle2D[] cellClips;
private int numCells;
private final Timeline timeline;
private final IntegerProperty frameCounter = new SimpleIntegerProperty(0);
public Sprite(Image animationImage, int numCells, Duration frameTime) {
this.numCells = numCells;
double cellWidth = animationImage.getWidth() / numCells;
double cellHeight = animationImage.getHeight();
cellClips = new Rectangle2D[numCells];
for (int i = 0; i < numCells; i++) {
cellClips[i] = new Rectangle2D(
i * cellWidth, 0,
cellWidth, cellHeight
);
}
setImage(animationImage);
setViewport(cellClips[0]);
timeline = new Timeline(
new KeyFrame(frameTime, event -> {
frameCounter.set((frameCounter.get() + 1) % numCells);
setViewport(cellClips[frameCounter.get()]);
})
);
}
public void playOnce() {
frameCounter.set(0);
timeline.setCycleCount(numCells);
timeline.stop();
timeline.playFromStart();
}
public void playContinuously() {
frameCounter.set(0);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.stop();
timeline.playFromStart();
}
public void stop() {
frameCounter.set(0);
setViewport(cellClips[frameCounter.get()]);
timeline.stop();
}
}
public class SpriteSample extends Application {
private static final int NUM_CELLS_PER_ANIMATION = 6;
private static final Duration FRAME_TIME = Duration.seconds(.5);
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
// looks likes imgur may have blocked direct access to following png from a Java app (somehow).
// but you can still download the QMqbQ.png from that location
// and save it locally in the same directory as the CatWhack program
// then pick it up by replacing the new Image call with:
// new Image(Sprite.class.getResourceAsStream("QMqbQ.png"));
Image tilesheetImage = new Image(SpriteSample.class.getResourceAsStream("QMqbQ.png"));
Sprite sprite = new Sprite(tilesheetImage, NUM_CELLS_PER_ANIMATION, FRAME_TIME);
ToggleButton animationControl = new ToggleButton("Animate");
animationControl.setOnAction(event -> {
if (animationControl.isSelected()) {
animationControl.setText("Stop");
sprite.playContinuously();
} else {
animationControl.setText("Animate");
sprite.stop();
}
});
VBox layout = new VBox(10, sprite, animationControl);
layout.setPadding(new Insets(10));
layout.setAlignment(Pos.CENTER);
stage.setScene(new Scene(layout));
stage.show();
}
}
Вы можете использовать свойство клипа Node
, а также свойство x ImageView
. Ниже приведена демонстрация части изображения на временной шкале, например, анимированная картинка gif:
@Override
public void start(Stage stage) {
Group root = new Group();
Image image = new Image(this.getClass().getResource("your.png").toExternalForm());
final int numberOfFrames = 6; // in image
double frameWidth = image.getWidth() / numberOfFrames;
Scene scene = new Scene(root, frameWidth, image.getHeight());
final ImageView view = new ImageView(image);
Rectangle mask = new Rectangle(frameWidth, image.getHeight());
view.setClip(mask);
Timeline timeline = new Timeline();
for (int i = 0; i <= numberOfFrames; i++) {
KeyFrame kf = new KeyFrame(Duration.seconds(i), new KeyValue(view.xProperty(), -frameWidth * i, Interpolator.DISCRETE));
timeline.getKeyFrames().add(kf);
}
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
root.getChildren().add(view);
stage.setScene(scene);
stage.show();
}