저는 javafx : Space Invaders와 같은 게임에서 대학 프로젝트를 진행 중입니다. 저는 ParallelTransition 으로 각 ovni의 애니메이션을 만들고 TimeLine 애니메이션을 만들고 각 ovni에 대한 ParallelTransition 에 추가하여 각각에 대한 EventHandler를 관리하려고했습니다. ovni를 X 위치로 이동하고 창의 왼쪽 경계에 올 때 Y로 이동하기 위해 그들 중 문제는 애니메이션을 재생할 때 첫 번째 행만 x 위치에서 올바르게 이동하지만 다른 하나는 행은 없습니다. 즉, 다른 행이 x 위치에서 어느 정도 거리를 이동하면 rigth 경계에서 동작을 완료하지 않고 대신 Y 위치로 이동합니다. 결과는 다음과 같습니다.
다음은 buildOvni 방법입니다.
public Shape buildOvni(){
Arc arcCuerpo=new Arc(Constantes.POS_CUERPO_OVNI_X,Constantes.POS_CUERPO_OVNI_Y,Constantes.ANCHO_CUERPO_OVNI,Constantes.ALTO_CUERPO_OVNI,0,180);
Arc arcL=new Arc(Constantes.POS_ARC_IZQ_X,Constantes.POS_ARC_IZQ_Y,Constantes.ANCHO_ARC_IZQ,Constantes.ALTO_ARC_IZQ,180,180);
Arc arcCentro=new Arc(Constantes.POS_ARC_CTR_X,Constantes.POS_ARC_CTR_Y,Constantes.ANCHO_ARC_CTR,Constantes.ALTO_ARC_CTR,180,180);
Arc arcD=new Arc(Constantes.POS_ARC_DER_X,Constantes.POS_ARC_DER_Y,Constantes.ANCHO_ARC_DER,Constantes.ALTO_ARC_DER,180,180);
Shape union1=Shape.union(arcCuerpo, arcL);
Shape union2=Shape.union(union1, arcCentro);
Shape union3=Shape.union(union2, arcD);
return union3;
}
둘째, ovnis에 대해 두 개의 행렬을 선언했습니다. 하나는 각 ovni의 모양을 포함 할 Panes에 대한 것입니다. 그리고 ovni 객체를 포함 할 다른 것.
public Juego(){
lab=new Label();
transicionEnY=new ParallelTransition();
dir=new File(Constantes.GAME_BACKGROUND);
Pane navePane=new Pane();
paneOvnis=new Pane[3][6]; //the panes for each ovni´s shape
nave=new Nave(navePane);
gameContainer=new Pane();
gameContainer.getChildren().addAll(navePane);
background=new Image(dir.toURI().toString());
pane=new BorderPane();
pane.setCenter(gameContainer);
pane.setBackground(new Background(new BackgroundImage(background,null,null,null,new BackgroundSize(Constantes.MAXIMUM_WIDHT,Constantes.MAXIMUM_HEIGTH,false,false,false,true))));
//playMusic();
agregarOvnis();
moverOvnis();
pane.setBottom(lab);
}
각 행렬을 채우는 방법 :
public void agregarOvnis(){
this.ovnis=new Ovni[paneOvnis.length][paneOvnis[0].length];
for(int i=0;i<paneOvnis.length;i++){
for(int j=0;j<paneOvnis[0].length;j++){
Pane paneOvni=new Pane();
Ovni ovni=new OvniGris(paneOvni);
ovni.setLocation(Constantes.POS_OVNI_X+Constantes.OVNI_SPACING_X*j,Constantes.POS_OVNI_Y+Constantes.OVNI_SPACING_Y*i);
this.gameContainer.getChildren().add(paneOvni);
this.paneOvnis[i][j]=paneOvni;
this.ovnis[i][j]=ovni;
}
}
}
ParallelTransition을 선언하고 각 ovni에 대한 TimeLine 애니메이션을 만드는 메서드 :
public void moverOvnis(){
ParallelTransition animaciones=new ParallelTransition();
for(int i=0;i<ovnis.length;i++){
for(int j=0;j<ovnis[i].length;j++){
Timeline animacionOvnis=new Timeline();
KeyFrame kf=new KeyFrame(Duration.millis(900),new ManejadorMovimientos(i,j));
animacionOvnis.getKeyFrames().add(kf);
animacionOvnis.setCycleCount(Timeline.INDEFINITE);
animacionOvnis.setAutoReverse(false);
animaciones.getChildren().add(animacionOvnis);
}
}
animaciones.play();
}
마지막으로 이것은 각 ovni에 대한 ovni 모션을 만드는 TimeLine EventHandler 클래스입니다.
private class ManejadorMovimientos implements EventHandler<ActionEvent>{
int i;
int j;
int orientacion=1;
public ManejadorMovimientos(int i, int j){
this.i=i;
this.j=j;
}
@Override
public void handle(ActionEvent event) {
double distanciaMaxDer=maxDistanceRight();
double distanciaMaxIzq=maxDistanceLeft();
lab.setText(""+distanciaMaxDer+","+ovnis[0][5].getXLocation());
if(orientacion==1)
if(distanciaMaxDer-30>0){
ovnis[i][j].setLocation(ovnis[i][j].getXLocation()+30,ovnis[i][j].getYLocation());
}
else{
ovnis[i][j].setLocation(ovnis[i][j].getXLocation(),ovnis[i][j].getYLocation()+20);
orientacion=-1;
}
else{
if(distanciaMaxIzq-30>30){
ovnis[i][j].setLocation(ovnis[i][j].getXLocation()-30,ovnis[i][j].getYLocation());
}
else{
ovnis[i][j].setLocation(ovnis[i][j].getXLocation(),ovnis[i][j].getYLocation()+20);
orientacion=1;
}
}
}
private double maxDistanceRight(){
int j=ovnis[0].length-1;
while(j>=0){
for(int i=0;i<ovnis.length;i++){
if(ovnis[i][j]!=null){
return 1.25*Constantes.MAXIMUM_WIDHT-ovnis[i][j].getXLocation();
}
}
j--;
}
return -1;
}
private double maxDistanceLeft(){
int j=0;
while(j<ovnis[0].length){
for(int i=0;i<ovnis.length;i++){
if(ovnis[i][j]!=null){
return ovnis[i][j].getXLocation()-30;
}
}
j++;
}
return -1;
}
}
더 많은 정보를 위해 각각 Constants, Ovni 및 Game Class를 남겨 둡니다 (스페인어로 된 단어에 대해 죄송합니다. 프로젝트 요청의 일부입니다.)
상수 클래스
public class Constantes {
//PARAMETROS GENERALES DEL JUEGO
public static final double MENU_HEIGTH= 600;
public static final double MENU_WIDTH= 500;
public static final double MAXIMUM_HEIGTH = 800;
public static final double MAXIMUM_WIDHT= 640;
public static final String MAIN_LOGO="src/backgrounds/logo.png";
public static final String MAIN_BACKGROUND="src/backgrounds/mainbackground2.jpg";
public static final String GAME_BACKGROUND="src/backgrounds/gamebackground2.jpg";
public static final String GAME_BACKGROUND_MUSIC="src/sounds/game.mp3";
public static final String MAIN_BACKGROUND_MUSIC="src/sounds/main.mp3";
//PARAMETROS DE CONSTRUCCION DE LA NAVE
public static final double POS_NAVE_X=MAXIMUM_WIDHT/2;
public static final double POS_NAVE_Y=MAXIMUM_HEIGTH-295;
public static final double ANCHO_REC_A=50;
public static final double ALTO_REC_A=18;
public static final double POS_REC_A_X=(POS_NAVE_X/4)-(ANCHO_REC_A/2);
public static final double POS_REC_A_Y=POS_NAVE_Y-400;
public static final double ANCHO_REC_B=ANCHO_REC_A*0.66667;
public static final double ALTO_REC_B=10;
public static final double POS_REC_B_X=POS_REC_A_X+ANCHO_REC_B/4;
public static final double POS_REC_B_Y=POS_NAVE_Y-405;
public static final double ANCHO_REC_C=ANCHO_REC_B*0.225;
public static final double ALTO_REC_C=10;
public static final double POS_REC_C_X=POS_REC_B_X+ANCHO_REC_B/2;
public static final double POS_REC_C_Y=POS_REC_B_Y;
public static final double ANCHO_REC_D=ANCHO_REC_C*0.45;
public static final double ALTO_REC_D=10;
public static final double POS_REC_D_X=POS_REC_C_X-1;
public static final double POS_REC_D_Y=POS_REC_C_Y-ALTO_REC_C-ALTO_REC_D+ALTO_REC_C/2;
//PARAMETROS DE CONSTRUCCION DEL OVNI
public static final double POS_OVNI_X=70;
public static final double POS_OVNI_Y=40;
public static final double POS_CUERPO_OVNI_X=0;
public static final double POS_CUERPO_OVNI_Y=0;
public static final double ANCHO_CUERPO_OVNI=23;
public static final double ALTO_CUERPO_OVNI=15;
public static final double ANCHO_ARC_IZQ=ANCHO_CUERPO_OVNI*0.22;
public static final double ALTO_ARC_IZQ=ALTO_CUERPO_OVNI*0.55;
public static final double POS_ARC_IZQ_X=POS_CUERPO_OVNI_X - ANCHO_CUERPO_OVNI * 0.80 + ANCHO_ARC_IZQ / 2;
public static final double POS_ARC_IZQ_Y=POS_CUERPO_OVNI_Y;
public static final double ANCHO_ARC_CTR=ANCHO_CUERPO_OVNI*0.35;
public static final double ALTO_ARC_CTR=ALTO_CUERPO_OVNI*0.30;
public static final double POS_ARC_CTR_X=POS_CUERPO_OVNI_X;
public static final double POS_ARC_CTR_Y=POS_CUERPO_OVNI_Y;
public static final double ANCHO_ARC_DER=ANCHO_CUERPO_OVNI*0.22;
public static final double ALTO_ARC_DER=ALTO_CUERPO_OVNI*0.55;
public static final double POS_ARC_DER_X=POS_CUERPO_OVNI_X + ANCHO_CUERPO_OVNI * 0.60 + ANCHO_ARC_DER / 2;
public static final double POS_ARC_DER_Y=POS_CUERPO_OVNI_Y;
public static final double POS_OVNI_WINDOW_X=POS_CUERPO_OVNI_X - ANCHO_CUERPO_OVNI * 0.80;
public static final double POS_OVNI_WINDOW_Y=POS_CUERPO_OVNI_Y - ANCHO_CUERPO_OVNI / 2;
public static final double OVNI_SPACING_X=70;
public static final double OVNI_SPACING_Y=30;
//PARAMETROS DE MOVIMIENTO NAVE
public static final double MOVIMIENTO_NAVE=2;
//PARAMETROS DE MOVIMIENTO OVNI
}
OVNI 클래스
public abstract class Ovni {
protected Shape ovni;
public Ovni(Pane pane){
ovni=buildOvni();
pane.getChildren().add(ovni);
}
public void setLocation(double x,double y){
ovni.setLayoutX(x);
ovni.setLayoutY(y);
}
public double getXLocation(){
return ovni.getLayoutX();
}
public double getYLocation(){
return ovni.getLayoutY();
}
public Shape getOvni() {
return ovni;
}
public void setOvni(Shape ovni) {
this.ovni = ovni;
}
public Shape buildOvni(){
Arc arcCuerpo=new Arc(Constantes.POS_CUERPO_OVNI_X,Constantes.POS_CUERPO_OVNI_Y,Constantes.ANCHO_CUERPO_OVNI,Constantes.ALTO_CUERPO_OVNI,0,180);
Arc arcL=new Arc(Constantes.POS_ARC_IZQ_X,Constantes.POS_ARC_IZQ_Y,Constantes.ANCHO_ARC_IZQ,Constantes.ALTO_ARC_IZQ,180,180);
Arc arcCentro=new Arc(Constantes.POS_ARC_CTR_X,Constantes.POS_ARC_CTR_Y,Constantes.ANCHO_ARC_CTR,Constantes.ALTO_ARC_CTR,180,180);
Arc arcD=new Arc(Constantes.POS_ARC_DER_X,Constantes.POS_ARC_DER_Y,Constantes.ANCHO_ARC_DER,Constantes.ALTO_ARC_DER,180,180);
Shape union1=Shape.union(arcCuerpo, arcL);
Shape union2=Shape.union(union1, arcCentro);
Shape union3=Shape.union(union2, arcD);
return union3;
}
}
GAME 클래스
public class Juego {
private BorderPane pane;
private Pane gameContainer;
private File dir;
private Image background;
private MediaPlayer player;
private Nave nave;
private Pane[][] paneOvnis;
private Ovni[][] ovnis;
private final ParallelTransition transicionEnY;
Label lab;
/**
*
*/
public Juego(){
lab=new Label();
transicionEnY=new ParallelTransition();
dir=new File(Constantes.GAME_BACKGROUND);
Pane navePane=new Pane();
paneOvnis=new Pane[3][6];
nave=new Nave(navePane);
gameContainer=new Pane();
gameContainer.getChildren().addAll(navePane);
background=new Image(dir.toURI().toString());
pane=new BorderPane();
pane.setCenter(gameContainer);
pane.setBackground(new Background(new BackgroundImage(background,null,null,null,new BackgroundSize(Constantes.MAXIMUM_WIDHT,Constantes.MAXIMUM_HEIGTH,false,false,false,true))));
//playMusic();
agregarOvnis();
moverOvnis();
pane.setBottom(lab);
}
/**
*
* @return
*/
public BorderPane getRoot(){
return pane;
}
/**
*
*/
public void playMusic(){
File dir=new File(Constantes.GAME_BACKGROUND_MUSIC);
Media music=new Media(dir.toURI().toString());
player=new MediaPlayer(music);
player.setOnEndOfMedia(new Runnable() {
@Override
public void run() {
player.seek(Duration.ZERO);
}
});
player.play();
}
public void agregarOvnis(){
this.ovnis=new Ovni[paneOvnis.length][paneOvnis[0].length];
for(int i=0;i<paneOvnis.length;i++){
for(int j=0;j<paneOvnis[0].length;j++){
Pane paneOvni=new Pane();
Ovni ovni=new OvniGris(paneOvni);
ovni.setLocation(Constantes.POS_OVNI_X+Constantes.OVNI_SPACING_X*j,Constantes.POS_OVNI_Y+Constantes.OVNI_SPACING_Y*i);
this.gameContainer.getChildren().add(paneOvni);
this.paneOvnis[i][j]=paneOvni;
this.ovnis[i][j]=ovni;
}
}
}
/**
*
* @param e
*/
public void moverNave(Event e){
ManejadorTeclas manager=new ManejadorTeclas();
manager.handle((KeyEvent) e);
}
public void moverOvnis(){
ParallelTransition animaciones=new ParallelTransition();
for(int i=0;i<ovnis.length;i++){
for(int j=0;j<ovnis[i].length;j++){
Timeline animacionOvnis=new Timeline();
KeyFrame kf=new KeyFrame(Duration.millis(900),new ManejadorMovimientos(i,j));
animacionOvnis.getKeyFrames().add(kf);
animacionOvnis.setCycleCount(Timeline.INDEFINITE);
animacionOvnis.setAutoReverse(false);
animaciones.getChildren().add(animacionOvnis);
}
}
animaciones.play();
}
private class ManejadorTeclas implements EventHandler<KeyEvent>{
@Override
public void handle(KeyEvent event) {
double movimiento=Constantes.MOVIMIENTO_NAVE;
if(event.getCode()==KeyCode.RIGHT && nave.getLocationX()+Constantes.MOVIMIENTO_NAVE<Constantes.MAXIMUM_WIDHT )
nave.setLocationX(nave.getLocationX()+3);
else if(event.getCode()==KeyCode.LEFT && nave.getLocationX()-Constantes.MOVIMIENTO_NAVE>0 )
nave.setLocationX(nave.getLocationX()-3);
else if(event.getCode()==KeyCode.ESCAPE){
pane.getScene().getWindow().hide();
}
}
}
private class ManejadorMovimientos implements EventHandler<ActionEvent>{
int i;
int j;
int orientacion=1;
public ManejadorMovimientos(int i, int j){
this.i=i;
this.j=j;
}
@Override
public void handle(ActionEvent event) {
double distanciaMaxDer=maxDistanceRight();
double distanciaMaxIzq=maxDistanceLeft();
lab.setText(""+distanciaMaxDer+","+ovnis[0][5].getXLocation());
if(orientacion==1)
if(distanciaMaxDer-30>0){
ovnis[i][j].setLocation(ovnis[i][j].getXLocation()+30,ovnis[i][j].getYLocation());
}
else{
ovnis[i][j].setLocation(ovnis[i][j].getXLocation(),ovnis[i][j].getYLocation()+20);
orientacion=-1;
}
else{
if(distanciaMaxIzq-30>30){
ovnis[i][j].setLocation(ovnis[i][j].getXLocation()-30,ovnis[i][j].getYLocation());
}
else{
ovnis[i][j].setLocation(ovnis[i][j].getXLocation(),ovnis[i][j].getYLocation()+20);
orientacion=1;
}
}
}
private double maxDistanceRight(){
int j=ovnis[0].length-1;
while(j>=0){
for(int i=0;i<ovnis.length;i++){
if(ovnis[i][j]!=null){
return 1.25*Constantes.MAXIMUM_WIDHT-ovnis[i][j].getXLocation();
}
}
j--;
}
return -1;
}
private double maxDistanceLeft(){
int j=0;
while(j<ovnis[0].length){
for(int i=0;i<ovnis.length;i++){
if(ovnis[i][j]!=null){
return ovnis[i][j].getXLocation()-30;
}
}
j++;
}
return -1;
}
}
}
위치를 한 줄씩 업데이트하고 매번 가장 오른쪽 위치를 다시 계산합니다. 에 Timeline
s를 추가 한 순서대로 ParallelTransition
하단 ouvis가 업데이트되기 전에 오른쪽 상단 ouvi가 업데이트됩니다. 즉, 해당 ouvis는 문제를 일으키는 최상위 라인의 ouvis보다 한 "프레임"전에 가장 오른쪽 위치에 도달하는 것으로 간주합니다.
추가 참고 사항 :
사용 a ParallelTransition
한 이후,이 경우 것은 불필요한 / 비효율적 Timeline
모두 처리 할 수있는 KeyFrame
들. 또한 KeyFrame
ouvis가 모두 동시에 업데이트되고 일부 값 도 재사용 해야하기 때문에 여러 개의조차 불필요 합니다 .
다음 예제는 더 단순한 객체를 중심으로 이동합니다.
private Rectangle[][] rects = new Rectangle[3][3];
private void moveDown() {
for (Rectangle[] column : rects) {
for (Rectangle r : column) {
if (r != null) {
r.setY(r.getY() + 5);
}
}
}
}
@Override
public void start(Stage primaryStage) {
Pane root = new Pane();
for (int j = 0; j < rects.length; j++) {
Rectangle[] column = rects[j];
for (int i = 0; i < column.length; i++) {
Rectangle rect = new Rectangle(20, 20);
rect.setX(j * 25);
rect.setY(i * 25);
root.getChildren().add(rect);
column[i] = rect;
}
}
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(500), new EventHandler<ActionEvent>() {
boolean movingRight = true;
@Override
public void handle(ActionEvent event) {
double maxX = Double.NEGATIVE_INFINITY;
double minX = Double.POSITIVE_INFINITY;
outer:
for (int i = rects.length - 1; i >= 0; i--) {
for (Rectangle r : rects[i]) {
if (r != null) {
maxX = r.getX() + r.getWidth();
break outer;
}
}
}
outer:
for (Rectangle[] col : rects) {
for (Rectangle r : col) {
if (r != null) {
minX = r.getX();
break outer;
}
}
}
if (movingRight) {
if (maxX + 5 > 150) {
moveDown();
movingRight = false;
return;
}
} else {
if (minX - 5 < 0) {
moveDown();
movingRight = true;
return;
}
}
double dx = movingRight ? 5 : -5;
for (Rectangle[] column : rects) {
for (Rectangle r : column) {
if (r != null) {
r.setX(r.getX() + dx);
}
}
}
}
}));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
Scene scene = new Scene(root, 150, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다