Question

Everything is working as supposed to with the exception of the bullet not shooting straight from the cannon. The cannon moves across the screen as it is supposed to but once the bullet is shot it doesn't travel at the angle in which the gun is pointed. Any ideas how to correct this so that it shoots at the same angle the cannon is set at?

import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Exercise16_25 extends JFrame {

    private Game    board;

    public Exercise16_25(int width, int height) {
        board = new Game(width, height);
        add( board );
        board.setFocusable( true );
    }

    class Game extends JPanel {

        //instance variables
        private int     ballonsHit      = 0;
        private int     ballsShot       = 0;
        private int     xCoordinate     = 0;
        private Point   shootingFrom;
        private boolean shooting        = false;
        Timer           timer;
        private Point   balloonLocation;

        ////////////////////
        //determines how big the gun is vertically
        private int gunSize = 25;

        ////////////////////
        //ensures that a balloon is drawn without appearing cutoff (over the edge)
        private int padding = 25;

        ////////////////////
        //flag to let paintComponent() know to draw the shatter visual
        private boolean isShattered;

        ////////////////////
        //this timer will end the shatter visual
        private Timer stopShatter;

        ///////////////////
        //the current distance of the mini-balloons from the shatter point
        //slowly increases as shatter visual executes
        private int shatterDistance;

        ////////////////////
        //the bulletTilt helps guide the bullet in a diagonal path
        //both are needed as you can change the tilt of the gun
        //while a bullet is flying which require a constant tilt
        private int gunTilt;
        private int bulletTilt;

        ///////////////////////
        //Make the radius one final size, don't use 'balloonRadius*4'
        //Also lets make the balloon a little bigger
        ///////////////////////
        private int     balloonRadius   = 25;
        private int bulletRadius = 5;

        public Game(int width, int height) {

            /////////////////////////
            //You must set the size of this panel so
            //that you can give xCoordinate a value, otherwise
            //getWidth() will equal 0.
            //Since xCoordinate represents the x-coord of the gun,
            //set it to the middle of the board
            this.setSize(width, height);
            xCoordinate     = this.getWidth()/2-1;
            /////////////////////////

            ////////////////////////
            //Don't try this line before the constructor
            //because it depends on the size of the panel
            //which isn't set before setSize is called.
            balloonLocation = setRandomBalloonLocation();

            timer = new Timer( 25, new ActionListener() {

                public void actionPerformed( ActionEvent e ) {
                    repaint();
                }
            } );

            /////////////////////////
            //repaint board every 25 milliseconds
            timer.start();
            /////////////////////////


            ///////////////////////
            //initiate shatter timer. 
            stopShatter = new Timer(2000, new ShatterTerminator());
            ///////////////////////

            addKeyListener( new KeyAdapter() {

                public void keyPressed( KeyEvent e ) {
                    switch ( e.getKeyCode() ) {
                        case KeyEvent.VK_UP:
                            shootBall();
                            bulletTilt = gunTilt;
                            break;
                        case KeyEvent.VK_LEFT:
                            turnLeft();
                            break;
                        case KeyEvent.VK_RIGHT:
                            turnRight();
                            break;
                    }
                }
            } );

        }

        public Point setRandomBalloonLocation() {
            //////////////////////////
            //use java.util.Random to generate random location
            //make x between 1 and the x-coordinate of the right hand edge of the JPanel
            //padding is used so the ball doesn't appear cut off. 
            //make y between 1 and half of the y-coordinate of the lower hand edge of the JPanel
            Random rand = new Random();
            Point location = new Point( rand.nextInt(this.getX()+this.getWidth()-padding)+1, (rand.nextInt(this.getY()+this.getHeight())/2)+1);
            return location;
        }

        public void shootBall() {
            if ( !shooting ) {
                shooting = true;

                shootingFrom = new Point( xCoordinate, getHeight() - gunSize );
                //shootingFrom = new Point( getWidth() / 2 + xCoordinate - bulletRadius / 2, getHeight() - y );
            } else {
                System.out.println( "The ball is already being shot!" );
            }
        }

        public void turnLeft() {
            xCoordinate -= 1;
            gunTilt--;
        }

        public void turnRight() {
            xCoordinate += 1;
            gunTilt++;
        }

        ///////////////////////////
        //One of the biggest issues here is your use of constants (hard-coded values).
        //Use all variables, because some variables will be used in several
        //computations, e.g. balloonLocation, ballonRadius.
        ///////////////////////////

        protected void paintComponent( Graphics g ) {
            super.paintComponent( g );

            ///////////////////////
            //Draw gun
            //'xcoordinate' represents the position of the gun.
            //turnLeft() and turnRight will control it
            g.drawLine( xCoordinate, getHeight()-gunSize, getWidth() / 2, getHeight() );
            ///////////////////////
            //To increase the thickness of the gun draw two more lines beside it
            g.drawLine( xCoordinate-1, getHeight()-gunSize, getWidth() / 2-1, getHeight() );
            g.drawLine( xCoordinate+1, getHeight()-gunSize, getWidth() / 2+1, getHeight() );
            ///////////////////////


            ///////////////////////
            //Display mini-balloons if the balloon was hit, otherwise display balloon
            if(isShattered) {
                g.drawOval( balloonLocation.x+shatterDistance, balloonLocation.y, balloonRadius/2, balloonRadius/2);
                g.drawOval( balloonLocation.x-shatterDistance, balloonLocation.y, balloonRadius/2, balloonRadius/2);
                g.drawOval( balloonLocation.x, balloonLocation.y+shatterDistance, balloonRadius/2, balloonRadius/2);
                g.drawOval( balloonLocation.x, balloonLocation.y-shatterDistance, balloonRadius/2, balloonRadius/2);
                shatterDistance+=5; //move mini-balloons
            }else {
                g.drawOval( balloonLocation.x, balloonLocation.y, balloonRadius, balloonRadius);
            }
            /////////////////////


            //////////////////
            //Draw bullet
            if ( shooting ) {

                g.drawOval( shootingFrom.x, shootingFrom.y, bulletRadius, bulletRadius);

                ////////////////////////////
                //Check if the bullet hit balloon
                //bullet is between the left and right boundaries of balloon
                //and bullet is between the lower and upper boundaries of balloon
                if((shootingFrom.x >= balloonLocation.x && shootingFrom.x <= (balloonLocation.x+(balloonRadius))) 
                && (shootingFrom.y >= balloonLocation.y && shootingFrom.y <= (balloonLocation.y+(balloonRadius)))
                ) {
                    System.out.println("Ballon Hit!");
                    shatterDistance = 0;
                    isShattered = true;
                    stopShatter.start();
                    shooting = false;
                }
                ///////////////////////////

                ///////////////////////////
                //Detect edge collision
                //Hitting the left and right edge aren't even possible, since
                //bullets shoot straight up
                if(shootingFrom.y <= 0 //hits top
                || shootingFrom.x <= 0 //hits left edge
                || shootingFrom.x >= this.getX()+this.getWidth() //hits right edge
                ) 
                { 
                    System.out.println("Hit Boundary!");
                    shooting = false;
                }
                ///////////////////////////


                ////////////////////////////
                //Continue to move bullet straight up
                //To shoot diagonal, you set shootingFrom.x accordingly
                shootingFrom.x += (bulletTilt/3);
                shootingFrom.y -= 5;
                ////////////////////////////

            }
        }

        private class ShatterTerminator implements ActionListener {
            public void actionPerformed( ActionEvent e ) {
                isShattered = false;
                balloonLocation = setRandomBalloonLocation();
                stopShatter.stop();
            }
        }
    }

    public static void main( String[] args ) {

        int width = 200, height = 300;

        Exercise16_25 frame = new Exercise16_25(width, height);

        frame.setSize( 300, 200 );
        frame.setLocationRelativeTo( null );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setVisible( true );
    }
}
Was it helpful?

Solution

The line that determines the angle in which the bullet moves is this:

shootingFrom.x += (bulletTilt/3);

Dividing by 3 is likely not the correct calculation here.

You need to calculate the angle of the gun at the time the trigger is pulled, extract your "bullet horizontal delta" from that and add that to shootingFrom.x at each refresh.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top