Java Swing - Entrada de clave con JPanel agregado a JOptionpane

Cuando ejecuto el código, la clase Example1 agregada a JOptionPane (en Frame) debería obtener keyInput y luego cambiar el valor y de la instancia del reproductor (en example1), pero no funciona. Además, ¿cómo podría rotar la nave sobre su eje y luego moverme en la dirección en que está orientada? Actualmente se mueve en la dirección hacia la que gira, pero gira en lo que parecen las coordenadas 0,0.

Cuadro

import javax.swing.*;
import java.awt.*;

/**
* Created by griffin on 12/7/2015.
*/
public class Frame extends JFrame {
    public Frame() {
        initUI();
}

private void initUI() {
    JTabbedPane jtp = new JTabbedPane();
    Example1 e1 = new Example1();
    Example2 e2 = new Example2();
    getContentPane().add(jtp);
    jtp.add(e1);
    jtp.add(e2);
    jtp.addTab("Example 1", e1);
    jtp.addTab("Example 2", e2);
    setResizable(false);
    pack();
    setTitle("NLTP");
    setLocationRelativeTo(null);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            JFrame frame =  new Frame();
            frame.setVisible(true);
        }
    });
}
}

Ejemplo 1

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.AffineTransform;

/**
* Created by griffin on 12/7/2015.
*/
public class Example1 extends JPanel implements Runnable {

private final int B_WIDTH = 640;
private final int B_HEIGHT = 480;
private int DELAY = 25;
private Thread thread;

Ship player = new Ship(320, 240);

public Example1() {
    initScreen();
}

private void initScreen() {
    JButton explanation = new JButton("Explanation");
    explanation.setBounds(0, 0, 150, 30);
    this.setLayout(null);
    add(explanation);

    addKeyListener(new keyInput());
    setFocusable(true);

    setBackground(Color.BLACK);
    setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
    setDoubleBuffered(true);
}

@Override
public void addNotify() {
    super.addNotify();

    thread = new Thread(this);
    thread.start();
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    draw(g);
}

public void draw(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    AffineTransform old = g2d.getTransform();
    g2d.rotate(Math.toRadians(player.angle));
    g2d.drawImage(player.ship, player.x, player.y, null);
    g2d.setTransform(old);


    Toolkit.getDefaultToolkit().sync();
}


public void cycle() {
    player.y += player.vY;
}


@Override
public void run() {
    long beforeTime, timeDiff, sleep;

    beforeTime = System.currentTimeMillis();

    while (true) {


        cycle();
        repaint();

        timeDiff = System.currentTimeMillis() - beforeTime;
        sleep = DELAY - timeDiff;

        if (sleep < 0) {
            sleep = 2;
        }

        try {
            Thread.sleep(sleep);
        } catch (InterruptedException e) {
            System.out.println("Interrupted: " + e.getMessage());
        }

        beforeTime = System.currentTimeMillis();
    }
}

public class keyInput extends KeyAdapter {
    @Override
    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();

        if(key == KeyEvent.VK_W) {
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();

        if (key == KeyEvent.VK_W) {
            player.vY -= 1;
        }

        if(key == KeyEvent.VK_A) {
            player.angle++;
        }

        if(key == KeyEvent.VK_D) {
            player.angle--;
        }
    }
}
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta