質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

timerクラスでkeylistenerが反応しない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,490

score 7

前提・実現したいこと

シューティングゲームを作成しています。
矢印キーの左右で、自機を左右に移動させ、矢印キーの上で、ミサイルを発射させたいです。
マウスの処理は、そのままにしておきたいです。

発生している問題・エラーメッセージ

矢印キーで自機を操作したいのですが、keylistenerを使っても反応してくれません。
敵に関する文と、Bossに関する文、ミサイルの当たり判定の文を、文字制限にかかったので、省略しています。
どなたかご教授していただけると助かります。

エラーメッセージ
なし

該当のソースコード

ソースコード
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;

public class Ex_15_1801010495 extends JFrame{
    final int windowWidth=800;//windowの幅
    final int windowHeight=500;//windowの高さ
    Container c;
    Start panelStart;
    MyJPanel mainPanel;
    Clear clear;
    GameOver gameover;
    public boolean key_up;
    public boolean key_right;
    public boolean key_left;



    public static void main(String[] args){
        new Ex_15_1801010495();

    }

    public Ex_15_1801010495(){
        Dimension dimOfScreen=Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(dimOfScreen.width/2-windowWidth/2,dimOfScreen.height/2-windowHeight/2,windowWidth,windowHeight);
        setResizable(false);//ウィンドウサイズ変更の可否
        setTitle("Software Development II"); //タイトル
        setDefaultCloseOperation(EXIT_ON_CLOSE);//バツボタンの処理

        panelStart=new Start();//panelオブジェクト作成
        panelStart.setLayout(null);

        c=getContentPane();
        c.add(panelStart);
        setVisible(true);
    }

    public class MyJPanel extends JPanel implements ActionListener,MouseListener,MouseMotionListener,KeyListener{
        //全体の設定
        Dimension dimOfPanel;//dimensionクラス
        Timer timer;//timerクラス
        ImageIcon iconMe,iconEnemy,iconHeart,iconBoss;//icon
        Image imgMe,imgEnemy,imgmyHeart,imgBoss;//img
        Font fmb = new Font("Serif" , Font.BOLD , 20);
        Random rnd=new Random();//乱数発生 

        //自分のライフ
        int myLife=3;//自機ライフ数
        int myHeartWidth,myHeartHeight;//ライフの幅と高さ
        int[] myHeartX=new int[myLife];//ライフのX座標配列
        int[] myHeartY=new int[myLife];//ライフのY座標配列
        boolean[] isHeartActive=new boolean[myLife];//ライフの有無

        //自機
        int myHeight,myWidth;//自機の幅と高さ
        int myX,myY,tempMyX;//自機のX座標,Y座標
        int gap=100;//絶対値比較の際に使用、
        int myMissileX,myMissileY,myMissileX2,myMissileY2;//ミサイルのX座標,Y座標、ミサイル2のX座標,Y座標
        int myMissileWidth=3,myMissileHeight=5;//ミサイルの横幅と縦幅
        boolean isMyMissileActive;//ミサイルの発射状態

        //敵機
        int numOfEnemy=12;//敵の数
        int numOfAlive=numOfEnemy;//敵の残数
        int enemyWidth,enemyHeight;//敵の幅と高さ
        int enemyMissileWidth=3,enemyMissileHeight=5;
        int[] enemyX=new int[numOfEnemy];//敵のX座標配列
        int[] enemyY=new int[numOfEnemy];//敵のY座標配列
        int[] enemyMove=new int[numOfEnemy];//敵の動く方向
        int[] enemyMissileX=new int[numOfEnemy];//敵ミサイルのX座標配列
        int[] enemyMissileY=new int[numOfEnemy];//敵ミサイルのY座標配列
        int[] enemyMissileSpeed= new int[numOfEnemy];//敵ミサイルのスピード配列
        int[] enemyLife=new int[numOfEnemy];//敵のライフ配列
        boolean[] isEnemyAlive=new boolean[numOfEnemy];//敵の生存状態
        boolean[] isEnemyMissileActive=new boolean[numOfEnemy];//敵のミサイル発射状態

        //boss
        int bossLife=10;//bossライフ
        int bossHeight,bossWidth;//bossの幅と高さ
        int bossX,bossY,bossMoveX,bossMoveY;//bossのx,y座標、動く方向x,y
        int bossMissileX,bossMissileY,bossMissileX2,bossMissileY2,bossMissileX3,bossMissileY3,bossMissileX4,bossMissileY4,bossMissileX5,bossMissileY5;//bossミサイルのx,y座標
        int bossMissileWidth=8,bossMissileHeight=5,bossMissileSpeed;//bossミサイルの横幅、bossミサイルの縦幅、bossミサイルのスピード
        boolean isBossAlive=true;//bossの生存状態
        boolean isBossActive=false;//bossの出現状態
        boolean isBossMissileActive;//bossミサイル発射状態

        public MyJPanel(){
            //全体の設定 

            setBackground(Color.black);//背景色 

            addMouseListener(this);
            addMouseMotionListener(this);
            addKeyListener(this);

            timer=new Timer(50,this);//timer設定
            timer.start();//timerスタート

            //自機img
            imgMe=getImg("jiki.jpg");
            myWidth=imgMe.getWidth(this);
            myHeight=imgMe.getHeight(this);

            //敵機img
            imgEnemy=getImg("teki.jpg");
            enemyWidth=imgEnemy.getWidth(this);
            enemyHeight=imgEnemy.getHeight(this);

            //ライフimg
            imgmyHeart=getImg("heart.jpg");
            myHeartWidth=imgmyHeart.getWidth(this);
            myHeartHeight=imgmyHeart.getHeight(this);

            //bossimg
            imgBoss=getImg("boss.jpg");
            bossWidth=imgBoss.getWidth(this);
            bossHeight=imgBoss.getHeight(this);

            initMyHeart();//ライフの初期化
            initMyPlane();//自機の初期化
            initEnemyPlane();//敵の初期化
            initBossPlane();//bossの初期化

        }

        //パネル上の描画
        public void paintComponent(Graphics g){
            dimOfPanel=getSize();
            super.paintComponent(g);

            //各要素の描画
            drawMyHeart(g);
            drawMyPlane(g);
            drawMyMissile(g);
            drawEnemyPlane(g);
            drawEnemyMissile(g);

            if(numOfAlive==0){
                drawBossPlane(g);//boss描画
                drawBossMissile(g);//bossミサイル
                g.setFont(fmb);//font指定
                g.setColor(Color.red);//文字色指定
                g.drawString("BossLife "+String.valueOf(bossLife),650,20);//ボスライフ表示
                isBossActive=true;//bossの出現状態
            }

        }

        public void actionPerformed(ActionEvent e){
            action();
            repaint(); 
            //自機ライフが0
            if(myLife==0){
                timer.stop();
                setVisible(false);
                           gameover = new GameOver();
                           gameover.setLayout(null);
                              c.removeAll();
                        c.add(gameover);
                        setVisible(true);
            }

            //bossライフが0なら
            if(bossLife==0){
                isBossAlive=false;//生存状態false
                timer.stop();
                setVisible(false);
                           clear = new Clear();
                           clear.setLayout(null);
                        c.removeAll();
                        c.add(clear);
                        setVisible(true);
            }
        }

        public void action(){
                if(key_up){
                    if(!isMyMissileActive){
                    myMissileX=tempMyX+myWidth/2;
                    myMissileY=myY;
                    isMyMissileActive=true;
                }
                }
                if(key_right){
                    tempMyX+=5;
                }
                if(key_left){
                    tempMyX-=5;
                }
            }
        //マウスボタンをクリック
        public void mouseClicked(MouseEvent e){
        }

                //マウスボタンを押す
        public void mousePressed(MouseEvent e){
            if(!isMyMissileActive){
                myMissileX=tempMyX+myWidth/2;
                myMissileY=myY;
                isMyMissileActive=true;
            }
        }

        //マウスボタン離す
        public void mouseReleased(MouseEvent e){
        }

        //マウスが領域外に出る
        public void mouseExited(MouseEvent e){
        }

        //マウスが領域内に入る
        public void mouseEntered(MouseEvent e){
        }

        //マウスを動かす
        public void mouseMoved(MouseEvent e){
            myX=e.getX();
        }

        //ドラッグする
        public void mouseDragged(MouseEvent e){
            myX=e.getX();
        }

        //キーボードをタイプする
        public void keyTyped(KeyEvent e){
           }

           //キーが押された時
        @Override
            public void keyPressed(KeyEvent e) {
                switch(e.getKeyCode( )){   
                     case KeyEvent.VK_UP:
                     key_up=true;
                break;
                    case KeyEvent.VK_RIGHT:
                    key_right=true;
                    break;
                    case KeyEvent.VK_LEFT:
                    key_left=true;
                    break;
                }
            }

            //キーが離れた時
            @Override
            public void keyReleased(KeyEvent e){
                  switch(e.getKeyCode( )){   
                     case KeyEvent.VK_UP :   key_up=false;  break;
                case KeyEvent.VK_RIGHT: key_right=false;  break;
                        case KeyEvent.VK_LEFT : key_left=false;  break;
                }
           }



        //画像ファイルをImageクラスへ変換
        public Image getImg(String filename){
            ImageIcon icon=new ImageIcon(filename);
            Image img=icon.getImage();

            return img;
        }



        //自機の初期化
        public void initMyPlane(){
            myX=windowWidth/2;
            myY=windowHeight-100;
            tempMyX=windowWidth/2;
            isMyMissileActive=false;
        }







        //自機の描画
        public void drawMyPlane(Graphics g){
            if(Math.abs(tempMyX-myX)<gap){
                if(myX<0){
                    myX=0;
                }else if(myX+myWidth>dimOfPanel.width){
                    myX=dimOfPanel.width-myWidth;
                }
                tempMyX=myX;
                g.drawImage(imgMe,tempMyX,myY,this);
            }else{
                g.drawImage(imgMe,tempMyX,myY,this);
            }
            g.drawImage(imgMe,tempMyX,myY,this);
        }

        //自機ミサイルの描画
        public void drawMyMissile(Graphics g){
            myMissileX2=myMissileX;//ミサイル2のx座標
            myMissileY2=myMissileY+5;//ミサイル2のy座標
            //ミサイルの発射状態がtrue未発射なら
            if(isMyMissileActive){
                myMissileY-=20;//ミサイル1の速さ設定
                g.setColor(Color.white);//ミサイルの色指定
                g.fillRect(myMissileX,myMissileY,myMissileWidth,myMissileHeight);//ミサイル1描画

                                //ミサイル1のY座標が400を下回ったら
                                if(myMissileY<400){
                                        myMissileY-=20;//ミサイル2の速さ設定
                                        g.fillRect(myMissileX2,myMissileY2,myMissileWidth,myMissileHeight);//ミサイル2描画
                                }


            }
        }





    public class Start extends JPanel implements ActionListener{
        JButton start=new JButton("スタート"); 
        public Start(){
            start.setBounds(300,150,200,100);
            start.addActionListener(this);

            add(start);
        }

        public void actionPerformed(ActionEvent e){
            if(e.getSource()==start){
                setVisible(false);
                           mainPanel = new MyJPanel();
                           mainPanel.setFocusable(true);
                           mainPanel.requestFocus();
                        c.removeAll();
                        c.add(mainPanel);
                        setVisible(true);
            }
        }
    }
}

試したこと

ここに問題に対して試したことを記載してください。 **画面を遷移させるときに、mainPanel.setFocusable(true); mainPanel.requestFocus();を使いましたが、入力しても反応してくれません。
自作関数を使用して、自機のx座標を変更したり、Listener内で、自機のx座標を変更したりしましたが、反応がありませんでした。
**

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • ngsvx

    2019/08/01 00:00

    mainPanel.requestFocus();をc.add(mainPanel);の後にするとどうでしょうか。
    また、mainPanel.requestFocus();をmainPanel.requestFocusInWindow();にしてみてください。

    キャンセル

回答 1

checkベストアンサー

0

requestFocus では無く requestFocusInWindow を使うようにとされています.

public void requestFocus()
  このComponentが入力フォーカスを取得することを要求します。このメソッドの詳細については、Component.requestFocus()を参照してください。
このメソッドの動作はプラットフォームに依存しているため、このメソッドを使用することは推奨されません。代わりにrequestFocusInWindow()を使用することをお勧めします。フォーカスの詳細については、「The Java Tutorial」の「How to Use the Focus Subsystem」を参照してください。

チュートリアルの How to Use the Focus Subsystem には以下の文があります. (google 翻訳しました)

ウィンドウが最初にアクティブになったときに特定のコンポーネントが確実にフォーカスを取得するようにしたい場合は、コンポーネントが認識された後、フレームが表示される前に、そのコンポーネントrequestFocusInWindowメソッドを呼び出すことができます。 次のサンプルコードは、この操作がどのように行われることができるのか示します。

    //...Where initialization occurs...
    JFrame frame = new JFrame("Test");
    JPanel panel = new JPanel(new BorderLayout());

    //...Create a variety of components here...

    //Create the component that will have the initial focus.
    JButton button = new JButton("I am first");
    panel.add(button);
    frame.getContentPane().add(panel);  //Add it to the panel

    frame.pack();  //Realize the components.
    //This button will have the initial focus.
    button.requestFocusInWindow(); 
    frame.setVisible(true); //Display the window

蛇足ですが.
自機, 敵機, ボス, それぞれのミサイル等の各種変数が直接パネルクラス内にあるために, キー入力等の部分が埋もれてしまっています.
それぞれに適切なクラスを作成してパネルから呼び出すようにすれば, パネル内がスッキリしてくると思います.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る