2D-Grafik Bild abgeschnitten nach Rotation mit Affine Transform und Hintergrund Schwarz

OLED

Mitglied
Sehr geehrte Community!

Ich bin gerade dabei ein Rennspiel zu schreiben, welches an Wipeout angelehnt ist. Nur habe ich das Problem, wenn ich eines Löse kommt das Nächste. Zu meiner Frage:

Wenn ich das Bild drehe entsteht hinter dem BufferedImage ein Schwarzer Fleck und das Bild wird oben und unten abgeschnitten. Ich mühe mich schon seit einer Woche ab um den Fehler zu finden und probiere Forenbeispiele aus, aber ich komme einfach nicht auf einen grünen Zweig. Hier mein Code:

Das ist das Fenster das den Thread aufruft:
Java:
import java.awt.BorderLayout;
import java.awt.Component;
//import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

/**
 * 
 * @author Oliver
 * @version 0.5
 */

public class MainGame extends Component{

	private static final long serialVersionUID = 1L;
	private static String MAP_URL = "Pictures\\Maps\\bmw-logo.jpg";
	private static String SHIP_URL = "Pictures\\Ships\\ShipNew.jpg";
	private static String BACK_URL = "Pictures\\Backgrounds\\space.jpg";
	
	JFrame mainGameWindow;


//	int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
//	int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
	private static int screenWidth = 1024;
	private static int screenHeight = 768;
	
    private BufferStrategy strategy;
	
	MainThread thread;
	CreatePauseDialog pauseDialog;
	
	public MainGame(){
		mainGameWindow = new JFrame("Main Game");
		mainGameWindow.setSize(screenWidth, screenHeight);
		mainGameWindow.setLayout(new BorderLayout());
	
		thread = new MainThread();
		
//		thread.setScreenHeight(screenHeight);
//		thread.setScreenWidth(screenWidth);
		
		try{
			
			thread.setBackgroundIMG(ImageIO.read(new File(MAP_URL)));
			thread.setForegroundIMG(ImageIO.read(new File(SHIP_URL)));
			thread.setBackIMG(ImageIO.read(new File(BACK_URL)));
			
		}catch(IOException e){
			System.out.println(e.getMessage().toString());	
		}
		
//		mainGameWindow.setUndecorated(true);
		mainGameWindow.setVisible(true);
		mainGameWindow.setLocationRelativeTo(null);
		mainGameWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainGameWindow.setResizable(false);
		mainGameWindow.setIgnoreRepaint(true);
		mainGameWindow.createBufferStrategy(2);	
		
		strategy = mainGameWindow.getBufferStrategy();
		thread.setStrategy(strategy);
		
		thread.start();
		
		mainGameWindow.addKeyListener(new KeyAdapter() { 
			
			public void keyTyped(KeyEvent evt) {
				if(evt.getKeyChar() == KeyEvent.VK_ESCAPE){
					System.out.println("Escape pressed");
					thread.suspend();

					pauseDialog = new CreatePauseDialog();
						
					if(pauseDialog != null){
						pauseDialog.setVisibleFalse();
					}
					
					while(true){
						if(pauseDialog.isStatus()){
							thread.resume();
							break;
						}
						if(pauseDialog.isRestart()){
							thread.interrupt();
							thread=new MainThread();
							pauseDialog.setVisibleFalse();
						}
					}
				}	
			}
			public void keyPressed(KeyEvent evt) {
				int keyCode = evt.getKeyCode();
				
				if(keyCode == KeyEvent.VK_LEFT){
					System.out.println("Left");
					thread.setRotate(true);
					thread.setRotateLeft(true);
					
				}else if(keyCode == KeyEvent.VK_RIGHT){
					System.out.println("Right");
					thread.setRotate(true);
					thread.setRotateRight(true);					
				}else if(keyCode == KeyEvent.VK_UP){
					System.out.println("Up");
					thread.setMove(true);
					thread.setMoveUp(true);					
				}else if(keyCode == KeyEvent.VK_DOWN){
					System.out.println("Down");
					thread.setMove(true);
					thread.setMoveDown(true);
				}			
			}
		
			public void keyReleased(KeyEvent evt) {
				int keyCode = evt.getKeyCode();
				
				if(keyCode == KeyEvent.VK_LEFT){
					System.out.println("Left");
					thread.setRotate(false);
					thread.setRotateLeft(false);
					
				}else if(keyCode == KeyEvent.VK_RIGHT){
					System.out.println("Right");
					thread.setRotate(false);
					thread.setRotateRight(false);
					
				}else if(keyCode == KeyEvent.VK_UP){
					System.out.println("Up");
					thread.setMove(false);
					thread.setMoveUp(false);
					
				}else if(keyCode == KeyEvent.VK_DOWN){
					System.out.println("Down");
					thread.setMove(false);
					thread.setMoveDown(false);
				}
			}
		});
	}
 
	public static void main(String[] args){
		new MainGame();
	}
}
Das der Thread der die Klasse für das Rotieren öffnet:
Java:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;

/**
 * 
 * @author Oliver
 * @version 0.8
 */

public class MainThread implements Runnable{
	
	
	private boolean move, rotate, rotateLeft, rotateRight, moveUp, moveDown, running = true;
//	private int screenWidth;
//	private int screenHeight;
	private int y;
	
	private BufferStrategy strategy;
    private BufferedImage backIMG, backgroundIMG, foregroundIMG, rotatedImage;
    
    private RotateEngine rotateEngine = new RotateEngine();
    
	private Filehandler filehandler = new Filehandler();
	private String username = filehandler.readLastloggedUser();
	private int reachedPoints = filehandler.getReachedPoints();
	
	int shipX = 512; 
	int	shipY = 256;
	double mapX; 
	double mapY; 
	double degrees;
	
	public MainThread(){
	}
	
	private Thread runner = new Thread(){
		{
			setPriority(MAX_PRIORITY);
		}
		
		public void run(){
			
			try{
				while(running){	
					Graphics2D g = (Graphics2D)strategy.getDrawGraphics();
//					g.clearRect(0, 0, screenWidth, screenHeight);
					g.drawImage(backIMG, 0, 0, null);
					g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
					
					if(rotatedImage==null){
						System.out.println("rotatedImage = null");
						g.drawImage(backgroundIMG, 0, y, null);
					}
					
					if(rotateLeft && moveUp){
						System.out.println("Rotate && move");
						degrees+=4;
						y+=4;
					}else if(rotateLeft && moveDown){
						System.out.println("Rotate && move");
						degrees+=4;
						y-=4;
					}else if(rotateRight && moveUp){
						System.out.println("Rotate && move");
						degrees-=4;	
						y+=4;
						
					}else if(rotateRight && moveDown){
						System.out.println("Rotate && move");
						degrees-=4;	
						y-=4;
					}
					
					if(rotate){	
						System.out.println("Rotate!");
				
						if(rotateLeft){
							degrees+=4;
						}else if(rotateRight){
								degrees-=4;	
						}
							
						degrees %= 360;	
						System.out.println(degrees);				
						rotatedImage = rotateEngine.rotateImage(backgroundIMG, degrees, shipX, shipY);
						sleep(2);
						
						}else if(move){	
						
						System.out.println("Move!");		
						if(moveUp){
							y+=4;
						}else if(moveDown){
							y-=4;
							
						}
						System.out.println(y);
						}
						
						sleep(1);
						g.drawImage(rotatedImage,512, 256, null);
//						g.drawImage(foregroundIMG, shipX, shipY, null);
			
						g.setColor(Color.RED);
						g.setFont(new Font("TimesRoman", Font.PLAIN, 30)); 
						g.drawString("Rennfahrer: "+username, 100, 50);
						g.drawString("Punkte: "+reachedPoints, 500, 50);

						g.dispose();
						
//						rotateEngine.print();
						
						strategy.show();
								
				}
			}catch(InterruptedException e){
				System.out.println(e.getMessage().toString());
			}
		}
	};
	
	void start(){
		runner.start();	
		System.out.println("Thread gestartet");
	}
	
	//set Abteilung
	
	
	@SuppressWarnings("deprecation")
	public void suspend(){
		runner.suspend();
	}
	@SuppressWarnings("deprecation")
	public void resume(){
		runner.resume();
	}
	public void interrupt(){
		runner.interrupt();
	}

	@Override
	public void run() {
		runner.start();	
	}

	public void setMove(boolean move) {
		System.out.println("Thread Move");
		this.move = move;
	}

	public void setRotate(boolean rotate) {
		this.rotate = rotate;
	}

	public void setRotateLeft(boolean rotateLeft) {
		this.rotateLeft = rotateLeft;
	}

	public void setRotateRight(boolean rotateRight) {
		this.rotateRight = rotateRight;
	}

	public void setMoveUp(boolean moveUp) {
		this.moveUp = moveUp;
	}

	public void setMoveDown(boolean moveDown) {
		this.moveDown = moveDown;
	}

	public void setRunning(boolean running) {
		this.running = running;
	}

	public void setDegrees(int degrees) {
		this.degrees = degrees;
	}

//	public void setScreenWidth(int screenWidth) {
//		this.screenWidth = screenWidth;
//	}

//	public void setScreenHeight(int screenHeight) {
//		this.screenHeight = screenHeight;
//	}

	public void setStrategy(BufferStrategy strategy) {
		this.strategy = strategy;
	}

	public void setForegroundIMG(BufferedImage foregroundIMG) {
		this.foregroundIMG = foregroundIMG;
	}

	public void setRotatedImage(BufferedImage rotatedImage) {
		this.rotatedImage = rotatedImage;
	}

	public void setRunner(Thread runner) {
		this.runner = runner;
	}
	
	public void setBackgroundIMG(BufferedImage backgroundIMG) {
		System.out.println("Background gesetzt");
		this.backgroundIMG=backgroundIMG;
	}
	public void setBackIMG(BufferedImage backIMG){
		this.backIMG = backIMG;
	}
	
}
Und hier meine Klasse die das Bild rotieren soll:
Java:
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

/**
 * 
 * @author Oliver
 * @version 0.2
 */

public class RotateEngine{
	AffineTransform affineTransform = new AffineTransform();
	
	double translateX = affineTransform.getTranslateX();
	double translateY = affineTransform.getTranslateY();
	double x, y;
	
	public void logicVectorEngine(double shipX, double shipY, double degrees, double translateX, double translateY){
		
		System.out.println("Berechne neue X und Y");
		x=shipX + translateX*Math.cos(degrees)-translateY*Math.sin(degrees);
		y=shipY + translateX*Math.sin(degrees)+translateY*Math.cos(degrees);
		
		System.out.println("Neues X: "+x);
		System.out.println("Neues Y: "+y);
				
	}
	
	
	 public BufferedImage rotateImage(BufferedImage src, double degrees, double shipX, double shipY) {
		 	Graphics2D g = null;
		 
		 	logicVectorEngine(shipX, shipY, degrees, translateX, translateY);
		 	
	    	System.out.println("Rotate!");
	    	
//	        affineTransform = AffineTransform.getRotateInstance(
//	                Math.toRadians(degrees),
//	                src.getWidth(),
//	                src.getHeight());
	    	
	        affineTransform = g.getTransform();
	    	
	        BufferedImage rotatedImage = new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
	        g = (Graphics2D) rotatedImage.getGraphics();
	        g.setTransform(affineTransform); 	        
	        g.drawImage(src, 0, 0, null);
	        
	        translateX = affineTransform.getTranslateX();
	        translateY = affineTransform.getTranslateY();
	        
	        System.out.println("Radius: "+degrees);
	        System.out.println("Radiant: "+Math.toRadians(degrees));
	        print();
	        
	        return rotatedImage;
	  }
	 
	 public void print(){
		 System.out.println("Transated X: "+affineTransform.getTranslateX());
		 System.out.println("Transated Y: "+affineTransform.getTranslateY());
		 System.out.println(x);
		 System.out.println(y);
		 
	 }	
}
Ich hoffe man erkennt was die Klassen machen sollen, da ich noch nicht auskommentiert habe. Ich bin noch ein Anfänger, was man wohl an meiner Programmierweise erkennen kann. Lerne gerade Java Programmieren in der Schule und mache gerade ein Projekt. Ich habe desswegen alle Klassen gepostet, vielleicht habe ich irgendwo ein Fehler im Variablenübertrag.
Ich hoffe mir kann jemand helfen und mir Lösungsansätze sagen, damit ich endlich ein paar Schritte weiter komme.

Freundliche Grüße
 
Zuletzt bearbeitet:
Wie ist dein Bild denn formatiert?
Ich mein, wenn du ein Bild hast, dass 10px breit ist und 10 px hoch und dein Raumschiff genau diesen Platz einnimmt, dann kannst du nicht aus diesem Bild ein neues machen.

Wenn du das Bild um 45° drehen willst, dann muss ja die neue Höhe des Bildes 10² + 10² = sqrt(200) sein
Das ist dann ungefähr 14.

Ich weiß nicht genau, ob es daran liegt, aber wenn du jetzt dein 10*10 Bild um 45° drehst, dann kann ich mir vorstellen, dass er oben und unten (und links und rechts) ein Stück vom Bild abschneidet, nämlich ~4,14... px

Gruß eMmiE
 
Danke vielmals für deine Hilfe!

Das Problem liegt daran, dass das Buffered Image in dem das rotierte Bild abgeschspeichert wird sich nicht mitverschiebt sondern in der 0, 0 Position im Frame bleibt ausßer man verändert das Y. Ich weiß nicht wie ich es vergrößern soll. Wie kann ich deinen Vorschlag umsetzen?

LG
 
Du machst ein Bild Typ ARGB von der Größe Wurzel 200 * Wurzel 200, malst das normale Bild erstmal genau in die Mitte rein drawImage(img,0.5 * Math.sqrt(200) - 5,0.5 * math.sqrt(200) - 5) o.Ä.
und drehst das Ding dann.
Dann sollte eigentlich nichts mehr schief gehen:rtfm:

Gruß eMmiE
 
Sorry war jetzt ewig lange nicht mehr da, da ich einiges zu lernen hatte letzte Zeit...
Ich habe dass jetzt mal ausprobiert aber irgendwie mag das ganze nicht so wie ich das will, vermutlich habe ich deine Idee nicht umsetzten können :noe: :
Java:
int width = (int)(Math.sqrt(4096)* Math.sqrt(4096));
	int height = (int)(Math.sqrt(2048) * Math.sqrt(2048));
	
	private BufferStrategy strategy;
    private BufferedImage backgroundIMG, foregroundIMG;
    BufferedImage rotatedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Java:
rotatedImage = rotateImage(backgroundIMG, degrees);

Java:
g.drawImage(rotatedImage,(int)(0.5 * Math.sqrt(4096) - 5) ,(int)(0.5 * Math.sqrt(2048) - 5), null);

Ich bin gerade echt blöd, auch mein Professor konnte mir da nicht wirklich helfen ???:L
 
Zuletzt bearbeitet:
Also:

Das Bild muss die Größe Wurzel 200 (-> width ==> Satz des Pythagoras (RaumschiffbildHöhe² + RaumschiffbildBreite²)) * Wurzel 200 (-> height ==> Das Gleiche wie oben) haben.

Hiermit beziehe ich mich auf das Bild, wo du das rotierte Image abspeichern willst und: das sind Mindestwerte

So groß muss das SpeicherImage minimal sein, damit das otierte Dingsda reinpasst.

Mal ne Frage: Dreht der Heini das eigentlich um den Mittelpunkt oder um die linke obere Ecke?

Bei linke obere Ecke müssten wir uns was neues einfallen lassen

EDIT: Lass das SpeicherImage besser mal ein Typ ARGB sein und setze dann alle Alpha-Werte auf durchsichtig

P.S.: Wurzel(x) * Wurzel(x) == x :toll:

Gruß eMmiE
 
Zuletzt bearbeitet:
Grüße Dich,

nach langer langer Zeit möchte ich mich mal wieder melden ^^

Ich habe nun herausgefunden dass es etwas mit meinen Werten zu Tun hat nicht mit der Größe des BufferedImage, denn ich bekam eine Lösung von meinen Programmierprofessor und die Funktionierte zunächst bis ich den KeyListener eingebettet habe und angefangen habe alle Werte zu ersetzen. Doch nun finde ich nicht wo....

Original:
Java:
 public void paint(Graphics g) {
        int xPos = (int) ((getWidth() - src.getWidth()) / 2.0);
        int yPos = (int) ((getHeight() - src.getHeight()) / 2.0);

        g.setColor(Color.BLACK);
        g.fillRect(0, 0, getWidth(), getHeight());

        AffineTransform at = new AffineTransform();
        // translate it to the current center of the component
        at.translate(getWidth() / 2, getHeight() / 2);
        // do the actual rotation
        at.rotate(Math.toRadians(degree));
        // translate the object so that you rotate it around the center
        at.translate(-src.getWidth() / 2, -src.getHeight() / 2);
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(src, at, null);

        g.setColor(Color.RED);
        g.drawRect(xPos, yPos, src.getWidth(), src.getHeight());
    }

Mit einbettung des Listeners:
Java:
public void paint(Graphics g) {

        
        
        
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, getWidth(), getHeight());

        rotatedImage = rotateImage(src);
        
        Graphics2D g2d = (Graphics2D) g;
        
        g2d.drawImage(rotatedImage, 0 ,y, null);

        g.setColor(Color.RED);
        g.drawRect(0, y, rotatedImage.getWidth(), rotatedImage.getHeight());
        
        repaint();
    }
    
    private BufferedImage rotateImage(BufferedImage srcNew){
    	int xPos = (int) ((getWidth() - srcNew.getWidth()) / 2.0);
        int yPos = (int) ((getHeight() - srcNew.getHeight()) / 2.0);
    	System.out.println("Rotate!");
    	
    	
        AffineTransform affineTransform = new AffineTransform();
        affineTransform.translate(getWidth() / 2, getHeight() / 2);
        affineTransform.rotate(Math.toRadians(degree));
        affineTransform.translate(-srcNew.getWidth() / 2, -srcNew.getHeight() / 2);
        
        
        BufferedImage rotatedImage = new BufferedImage(srcNew.getWidth(), srcNew.getHeight(), srcNew.getType());
        Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
        g.setTransform(affineTransform);
        g.drawImage(srcNew, affineTransform, null);
        
        
        return rotatedImage;
    }
 
Hi,

ich bin mir nicht sicher, wo das Problem liegt.

Eine Möglichkeit besteht in deiner rotateImage()-Methode, wenn du zuerst dem Graphics2D die AT übergibst und dann nochmal mit der AT das Bild malst.

Am Rande:
Die Variablen xPos und yPos brauchst du bei deinem Beispiel gar nicht, wo nimmst du y her?
Kann ja sein, dass y so groß / klein ist, dass das Bild nicht mehr auf dem Bildschrim ist...

Wo genau liegt denn das Problem?
Was funktioniert nicht?

Gruß eMmiE
 
Grüße dich,

ich habe den Fehler gefunden, es lag wie du gesagt hast am doppelten malen und an derübergabe des gedrehten Bildes. Habs jetzt nur mit at gedreht und das Return weggelassen und gleich im Thread gezeichnet.

Danke für euer bemühen, ihr seit echt Top!

lg
 

Neue Themen


Zurück
Oben