2017-05-10 17 views
0

他の人よりも苦労して、Javaでゲームをやろうとしばらくしてきました。スプライトの機能私は自分で作ったのですが、消去してください。私はそれが表示されて以来私のアーチャースプライトを表示するために背景のピクセルを変更していることを知っているが、私は以前のものにピクセルを変更することはできません何らかの理由で。それはなぜ、どのように私はそれを修正することができますアイデアを誰も持っていますか?画像をGoogleドキュメントへのリンク : https://docs.google.com/document/d/1eU6faW1d7valq1yE_Bo09IPMbXuuZ6ZgqUu3BesaJUw/edit?usp=sharingなぜ私はスプライトを消去できないのですか

import javax.swing.*; 
import javax.imageio.*; 
import java.io.*; 
import java.awt.image.BufferedImage; 

public class Sprite { 
BufferedImage image; 
public Sprite(BufferedImage image) throws IOException{ 
this.image = image; 
} 
public BufferedImage getSprite(){ 
return this.image; 
} 
public int getX(){ 
return this.image.getMinX(); 
} 
public int getY(){ 
return this.image.getMinY(); 
} 

//to spawn a sprite on top of another image. 
public void spawn(JFrame frame, BufferedImage world,int x, int y) throws 
IOException{ 
int orig_x = x; 
for (int sprite_y = 0; sprite_y < this.image.getHeight(); sprite_y++){ 
    for (int sprite_x = 0; sprite_x < this.image.getWidth(); sprite_x++){ 
    int sprite_pixel = this.image.getRGB(sprite_x,sprite_y); 
    int sprite_alpha = (sprite_pixel>>24) & 0xff; 
    int sprite_red = (sprite_pixel>>16) & 0xff; 
    int sprite_green = (sprite_pixel>>8) & 0xff; 
    int sprite_blue = sprite_pixel  & 0xff; 
    int pixel = (sprite_alpha<<24) | (sprite_red<<16) | (sprite_green<<8) | 
    sprite_blue; 
    world.setRGB(x,y,pixel); 
    x++; 
    } 
    y++; 
    x = orig_x; 
    } 
    } 

    public void erase(JFrame frame,BufferedImage world, BufferedImage 
    orig_world) throws IOException{ 
    int sprite_x = this.image.getMinX(); 
    int sprite_y = this.image.getMinY(); 
    int orig_sprite_x = sprite_x; 
    for (int stepper_y = this.image.getMinY(); stepper_y < 
    this.image.getHeight(); stepper_y++){ 
     for (int stepper_x = this.image.getMinX(); stepper_x < 
     this.image.getWidth(); stepper_x++){ 
     int sprite_pixel = orig_world.getRGB(sprite_x,sprite_y); 
     //get pixel from orginal sprite 
     int sprite_alpha = (sprite_pixel>>24) & 0xff; 
     //get alpha value from original sprite 
     int sprite_red = (sprite_pixel>>16) & 0xff; 
     //get red value from original sprite 
     int sprite_green = (sprite_pixel>>8) & 0xff; 
     //get green value from original sprite 
     int sprite_blue = sprite_pixel  & 0xff; 
     //get blue value from original sprite 

     int pixel = (sprite_alpha<<24) | (sprite_red<<16) | 
     (sprite_green<<8) | sprite_blue; 
     //set the pixel equal to the old values 
     world.setRGB(sprite_x,sprite_y,pixel); 
     //place the pixel 
     sprite_x++; 
     } 
    sprite_x = orig_sprite_x; 
    // setting equal to original is so that at the end of each row it resets 
    to the farthest left pixel. 
    sprite_y++; 
    } 
} 

public static void main(String[] args) throws IOException{ 

    Sprite orig_world = new Sprite(ImageIO.read(new 
    File("C:/Users/sfiel42/Documents/game/castles.png"))); 
    Sprite world  = new Sprite(ImageIO.read(new 
    File("C:/Users/sfiel42/Documents/game/castles.png"))); 

    JLabel label  = new JLabel(); 
    label.setLocation(0,0); 
    label.setIcon(new ImageIcon(world.getSprite())); 
    label.setVisible(true); 

    JFrame frame  = new JFrame(); 
    frame.setVisible(true); 
    frame.setSize(783,615); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.add(label); 

    Sprite archer  = new Sprite(ImageIO.read(new 
    File("C:/Users/sfiel42/Documents/game/archer.png"))); 
    archer.spawn(frame,world.getSprite(),250,400); 
    archer.erase(frame,world.getSprite(),orig_world.getSprite()); 

    } 
} 

答えて

1

これを実現するために結合するコードの問題がいくつかあります。最初の方法は、消去メソッドが間違ったセクションを消去することです。消去中に白いピクセルだけを書き込んでみてください。起こっているのは、spawnメソッドでは座標を指定しますが、消去メソッドではそうしないということです。 getMinX()getMinY()のメソッドでは、スプライトの座標は得られませんが、イメージ自体の最小のX座標とY座標が与えられます。バッファリングされたイメージの場合、イメージは暗黙的に位置を持たないため、これは常にゼロです。ラベルのようなものがあります。

public void erase(JFrame frame, BufferedImage world, BufferedImage orig_world, int x, int y) throws IOException { 
    for (int stepper_y = 0; stepper_y < this.image.getHeight(); stepper_y++) { 
     for (int stepper_x = 0; stepper_x < this.image.getWidth(); stepper_x++) { 
      int sprite_pixel = orig_world.getRGB(x + stepper_x, y + stepper_y); 
      // get pixel from orginal sprite 
      int sprite_alpha = (sprite_pixel >> 24) & 0xff; 
      // get alpha value from original sprite 
      int sprite_red = (sprite_pixel >> 16) & 0xff; 
      // get red value from original sprite 
      int sprite_green = (sprite_pixel >> 8) & 0xff; 
      // get green value from original sprite 
      int sprite_blue = sprite_pixel & 0xff; 
      // get blue value from original sprite 

      int pixel = (sprite_alpha << 24) | (sprite_red << 16) | (sprite_green << 8) | sprite_blue; 
      // set the pixel equal to the old values 
      world.setRGB(x + stepper_x, y + stepper_y, pixel); 
      // place the pixel 
     } 
    } 
} 

いっそのxとyはSpriteの性質を調整するために、次のようになります。ここでは正しいだろうバージョンがあります。結局のところ、スプライトはポジションを持ち、この情報を維持しなければなりません。それをスプライトオブジェクトの外側に置くことは、オブジェクト指向の観点からは意味をなさない。

したがって、このようなあなたのクラスを調整します

int x, y; 
BufferedImage image; 

public Sprite(BufferedImage image, int x, int y) throws IOException { 
    this.image = image; 
    this.x = x; 
    this.y = y; 
} 

public BufferedImage getSprite() { 
    return this.image; 
} 

public int getX() { 
    return x; 
} 

public int getY() { 
    return y; 
} 

次にそのswpanで、スプライトの座標を使用してメソッドを消去します。

// to spawn a sprite on top of another image. 
public void spawn(JFrame frame, BufferedImage world) throws IOException, InterruptedException { 
    for (int sprite_y = 0; sprite_y < this.image.getHeight(); sprite_y++) { 
     for (int sprite_x = 0; sprite_x < this.image.getWidth(); sprite_x++) { 
      int sprite_pixel = this.image.getRGB(sprite_x, sprite_y); 
      int sprite_alpha = (sprite_pixel >> 24) & 0xff; 
      int sprite_red = (sprite_pixel >> 16) & 0xff; 
      int sprite_green = (sprite_pixel >> 8) & 0xff; 
      int sprite_blue = sprite_pixel & 0xff; 
      int pixel = (sprite_alpha << 24) | (sprite_red << 16) | (sprite_green << 8) | sprite_blue; 
      world.setRGB(x + sprite_x, y + sprite_y, pixel); 
     } 
    } 
} 

public void erase(JFrame frame, BufferedImage world, BufferedImage orig_world) throws IOException { 
    for (int stepper_y = 0; stepper_y < this.image.getHeight(); stepper_y++) { 
     for (int stepper_x = 0; stepper_x < this.image.getWidth(); stepper_x++) { 
      int sprite_pixel = orig_world.getRGB(x + stepper_x, y + stepper_y); 
      // get pixel from orginal sprite 
      int sprite_alpha = (sprite_pixel >> 24) & 0xff; 
      // get alpha value from original sprite 
      int sprite_red = (sprite_pixel >> 16) & 0xff; 
      // get red value from original sprite 
      int sprite_green = (sprite_pixel >> 8) & 0xff; 
      // get green value from original sprite 
      int sprite_blue = sprite_pixel & 0xff; 
      // get blue value from original sprite 

      int pixel = (sprite_alpha << 24) | (sprite_red << 16) | (sprite_green << 8) | sprite_blue; 
      // set the pixel equal to the old values 
      world.setRGB(x + stepper_x, y + stepper_y, pixel); 
      // place the pixel 
     } 
    } 
} 

forループの変数は、(スプライト(0から幅まで0からの高さ、sprite_xとstepper_xにsprite_yとstepper_y)に対するもの、およびスプライトのベース座標に対する世界画像を調整しますxとy)。


第2号に。

実際にあなたの現在のコードで実際に起こっていることは、本当に背景をレンダリングしてスプライトをレンダリングしたことではないということです。それはあなたがそれを見ているので、奇妙に聞こえるかもしれませんよね?しかし、何が起こっているかは、競合状態です。 Java Swingはレンダリングのために別々のスレッドで動作します。つまり、何かを見えるようにすると、コードが続行される前に実際にレンダリングされることは保証されません。

JLabel label  = new JLabel(); 
label.setLocation(0,0); 
label.setIcon(new ImageIcon(world.getSprite())); 
label.setVisible(true); 

JFrame frame  = new JFrame(); 
frame.setVisible(true); 
frame.setSize(783,615); 
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
frame.add(label); 

Sprite archer = new Sprite(ImageIO.read(new File("C:/Users/sfiel42/Documents/game/archer.png"))); 
archer.spawn(frame,world.getSprite(),250,400); 
archer.erase(frame,world.getSprite(),orig_world.getSprite()); 

物事が起こっていることを順番実際にこのされています:

ここはこの部分です

  1. 背景画像(世界スプライト)でラベルを作成しても、それを設定します可視。まだコンテキストを持っていないので、まだ実際には見ていません。
  2. フレームを作成し、表示するように設定し、サイズを設定してラベルを追加します。 この時点でフレームのレンダリングは、Swingバックグラウンドスレッドによって処理されます。あなたのコードは今も続きます。しかし、フレームはまだレンダリングされていません。
  3. アーチャースプライトを読んでください。
  4. アーチャースプライトが生成されました。つまり、ラベルのアイコンであるワールドイメージのいくつかのピクセルを上書きします。
  5. フレームのレンダリングが実際に完了し、背景が調整されました。

あなたはこのように、フレームコードの間で、あなたのメインスレッドで睡眠を置くと射手スプライトを取得することによってこれをテストすることができます

frame.add(label); 

Thread.sleep(5000); 

Sprite archer = new Sprite(ImageIO.read(new File("C:/Users/sfiel42/Documents/game/archer.png"))); 

今のフレームは、前にレンダリングする時間を与えていますスプライトは背景を調整できます。その結果、あなたはその変化を見終わることはありません。

これをテストする別の方法があります。再度、上記の5秒のスリープを外し、そして今の半分スプライトが書き込まれたとき、短い睡眠を追加します。

public void spawn(JFrame frame, BufferedImage world, int x, int y) throws IOException, InterruptedException { 
    int orig_x = x; 
    for (int sprite_y = 0; sprite_y < this.image.getHeight(); sprite_y++) { 
     if (sprite_y == this.image.getHeight()/2) { 
      Thread.sleep(100); 
     } 

をあなたはおそらく、他の半分が欠けて半分のスプライトが表示されます。これらはすべて、レンダリングスレッドのタイミング、コンピュータの速度などに依存するため、結果は予測できません。アーチャースプライトファイルの読み込みが遅かった場合、スプライトが最初に表示されることはありませんでした。

何かをワールドイメージに変更すると、フレームとアイコンは自動的に更新されません。バッファリングされたイメージに直接書き込むので、それを使用しているコンポーネントは何か変更されたことを知らず、画面上の表現を変更する必要があります。レンダリング後に更新を呼び出します。

Sprite archer = new Sprite(ImageIO.read(new File("C:/Users/sfiel42/Documents/game/archer.png"))); 
archer.spawn(frame, world.getSprite()); 
frame.repaint(); 
Thread.sleep(2000); 
System.out.println("Erasing"); 
archer.erase(frame, world.getSprite(), orig_world.getSprite()); 
frame.repaint(); 

その後、最後の問題は、ここで撮影したレンダリングへのアプローチです。バックグラウンドのコピーを保持し、スプライトを削除する場合は、スプライト領域をコピーの領域に明示的に置き換えることで、スプライトが消去されます。これは、複数のスプライトを取得したり、移動しようとすると難しくなります。たとえば、spriteがspawn呼び出しとerase呼び出しの間を移動する場合、完全には消去されません。

通常、2Dレンダリングでは、レイヤーがある順序でレンダリングされます.1つ以上の背景レイヤー、次にスプライトが上にあります。 SNESやMegaDriveのような古いコンソール用のエミュレータや、NeoGeoやCPS-2(例えばMAMEやKawaks)などのシステム用のアーケードエミュレータのエミュレータを少し試してみてください。多くの場合、特定のレイヤーを無効にして、オブジェクトがどのようにレンダリングされるかを確認できます

チェスボードのような静的コンテンツを主に表示しなければならない非常に単純なゲームでは、背景をレンダリングしてスプライトを一番上に表示します。しかし、何かが速く動いてフレームを絶えず更新しているのであれば、スクリーンに出力するときのレンダリングフェーズにどこにいるかによって、スプライトやちらつきが失われる可能性があります。

普通の解決策はフレームバッファーを使用することです。フレームはいくつかのバックグラウンドバッファーイメージにレンダリングされ、準備が整ったら画面に表示することができます。これと同じように:

render loop

あなたはスイング(およびAWT)でこれを行うことができますが、それは非常にパフォーマンスの高い方法ではありません。いずれにしても、グラフィカルユーザーインターフェイスを構成するためのラベルやアイコンの代わりに、基本的なコンポーネントを使用することをお勧めします。既存のスプライトライブラリを使用したくない場合は、OpenGLなどのハードウェアレンダリング用のインターフェイスを調べるのが最良の方法です。利用可能なJavaのバインディングがあります。

またゲーム開発スタック交換をチェックアウト:https://gamedev.stackexchange.com/

+0

は今そんなに理にかなっている、ありがとうございました!!! :) –

+0

@ScottFieldあなたの質問が解決された場合は、[チェックマークをクリックして受理してください](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer -作業)。これは、あなたが解決策を見つけ出し、回答者とあなた自身の両方に評判を与えていることを広範なコミュニティに示します。これを行う義務はありません。 –

関連する問題