6
\$\begingroup\$

This is just some code I wrote for a hobby really, I'm trying to get better so please tell me all the bad/weird stuff I've done. Thanks for helping! I've left a little boring code out but most of it is here. This is what the game looks like (low fps is because of the gif looks way smoother on my PC). Images used (except target but that does nothing rn)

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

public class Main extends Application{

    public static void main(String[] args) {
    // write your code here
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        initGame ig = new initGame();
        ig.initUI(stage);

        RocketShip rocketShip = new RocketShip();
        rocketShip.initImageShip();
        rocketShip.setOverallForceNull();

        GraphicsContext gc = ig.gc;
        //fd.render(gc);
        LongValue lastNanoTime = new LongValue(System.nanoTime());
        List<Unitvector> forces = new ArrayList<>();

        MovingObject Alien = new MovingObject();
        Alien.initImage("/home/ed/Pictures/Misc_Photos/Games/target.png");
        Alien.setRandPosition();
        //would be target to hit as yet does nothing

        class timer extends AnimationTimer{
            @Override
            public void handle(long l) {
                double elapsedTime = (l - lastNanoTime.value) / 1000000000.0;
                lastNanoTime.value = l;
                //calcs time since last update DO NOT USE l IN ANIMATIONS!!!
                Unitvector vcNew = new Unitvector();
                //this is the force that acts on the rocketship

                gc.clearRect(0,0,640,480);
                //System.out.println(rot.getVal());
                rotation rot1 = new rotation();
                //interpretBooleans(forces, rocketShip);
                //what keys have been pressed
                if(interpretBooleansNoList(rocketShip)){
                    vcNew = makeNewUnitVector();
                }else{vcNew.initNullVector();}

                rocketShip.drawShip(gc, rot1.getVal());
                //TODO make this an overloadable method
                Alien.drawNonRotated(gc, Alien);


                rocketShip.drawMissile(gc);
                //MO.drawRocks(rocks, gc, rot1.getVal()); //this doesn't work null pointer exception
                //something isn't set right use the SUPER call more

                //rocketShip.updatePos(elapsedTime, forces);

                rocketShip.noListCalculatePos(elapsedTime, vcNew);
                //System.out.println(Alien.checkCollision(rocketShip, Alien));

                rocketShip.updateMissile(elapsedTime);
                //MO.updateRocks(rocks, elapsedTime);

                try {
                    TimeUnit.MICROSECONDS.sleep(10000);
                    /*
                    slows the animation down- not a very good method though
                    */
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }
        timer tim = new timer();
        tim.start();
        handleEvent(ig.getScene(), rocketShip);

        stage.show();
    }
    //to handle multiple key presses
    private BooleanProperty aPressed = new SimpleBooleanProperty();
    private BooleanProperty dPressed = new SimpleBooleanProperty();
    private BooleanProperty wPressed = new SimpleBooleanProperty();

    private void handleEvent(Scene scene, RocketShip rs){
        rotation rot = new rotation();
        //RocketShip shipRef = new RocketShip();
        scene.addEventHandler(KeyEvent.KEY_PRESSED, (key)->{
            if(key.getCode() == KeyCode.A){
                //System.out.println("fg" + rot.val);
                aPressed.set(true);
                //rot.decrement();
                //vec.setAccelation(0);
            }
            else if(key.getCode().equals(KeyCode.D)){
                //rot.increment();
                dPressed.set(true);
                //vec.setAccelation(0);
            }
            if(key.getCode().equals(KeyCode.W)){
                //move picture in correct direction of trave
                //or calculate acceleration each time this is used create
                //new unit vector that can act in the direction of travel
                wPressed.set(true);

                //they are not on the same vector
                //System.out.println("fgndfkl");

            }
            if(key.getCode().equals(KeyCode.SPACE)){
                //fire a 'missile'
                rs.fireMissile(rot.getVal());
            }
        });
        scene.addEventHandler(KeyEvent.KEY_RELEASED, (key)->{

            if(key.getCode().equals(KeyCode.A)){
                aPressed.set(false);
            }
            if(key.getCode().equals(KeyCode.D)){
                dPressed.set(false);
            }
            if(key.getCode().equals(KeyCode.W)){
                rs.setIgnition(false);
                wPressed.set(false);
            }
        });
    }
    private void interpretBooleans(List<Unitvector> lst, RocketShip rs){
        rotation rot = new rotation();

        if(aPressed.get()){
            rot.decrement();
        }
        else if(dPressed.get()){
            rot.increment();
        }
        if(wPressed.get()){

            Unitvector vecNew = new Unitvector();
            //create and add a new unitVector to the list

            vecNew.incrementAcceleration(1.5);
            vecNew.calcVelocity(rot.getVal());
            lst.add(vecNew);
            rs.setIgnition(true);
        }
    }
    private boolean interpretBooleansNoList(RocketShip rs){
        rotation rot = new rotation();

        if(aPressed.get()){
            rot.decrement();
        }
        else if(dPressed.get()){
            rot.increment();
        }
        if(wPressed.get()){
            rs.setIgnition(true);
            return true;
            //this is signal that we need a new unitvector force
        }
        return false;
    }
    private Unitvector makeNewUnitVector(){
        //this should not be in main
        rotation rot = new rotation();

        Unitvector vecNew = new Unitvector();
        //create new unitvector (avoids list memory heavy list)

        vecNew.incrementAcceleration(1.5);
        vecNew.calcVelocity(rot.getVal());
        return vecNew;
    }

    private class LongValue{
        long value;
        LongValue(long i){
            value=i;
        }
    }
}
class rotation{
    //this is a bit of a waste
    static double val;
    double getVal(){
        return val;
    }
    void decrement(){
        if(val - 2 < 0){
            val = 360;
        }
        val -= 2;

    }
    void increment(){
        if( val + 2 > 360){
            val = 0;
        }
        val+=2;
    }
}

class initGame {
    Stage mainStage;
    Canvas canvas;
    GraphicsContext gc;
    Group root;
    RocketShip ship = new RocketShip();
    Scene scene;

    initGame() {
        this.mainStage = null;
        this.canvas = null;
        this.gc = null;
        this.root = null;
        this.scene = null;
    }

    void initUI(Stage mainStage) {
        //GameBoard board = new GameBoard();
        //Setting the properties of the rectangle


        this.canvas = new Canvas(boardInfo.width, boardInfo.height);
        //Creating a Group object
        this.root = new Group();
        root.getChildren().add(canvas);


        //canvas image which can draw on with graphic context
        this.gc = canvas.getGraphicsContext2D();

        //Creating a scene object
        this.scene = new Scene(root);

        //Setting title to the Stage
        mainStage.setTitle("Asteroids");

        //Adding scene to the stage
        mainStage.setScene(scene);
    }
    Scene getScene(){
        return scene;
    }
}
class boardInfo {
    static int width = 640;
    static int height = 480;
}

Then the rocket ship class, with others

import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.transform.Rotate;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

class RocketShip extends MovingObject{
    private boolean ignition;
    //this changes which image to disply- if w pressed changes to a rocket with flames
    //altered in event handlers in Main
    private Image afterBurner;
    //the only extra methods this needs are to fire the rockets and have the binary
    //burner or not

    private List<missile> firedMissiles;
    //multiple missiles can be fired from the ship

    RocketShip(){
        firedMissiles = new ArrayList<>();
    }

    void initImageShip(){
        File fle = new File("/home/ed/Pictures/Misc_Photos/Games/rocket.png");
        setImage(new Image(fle.toURI().toString()));

        File fle2 = new File("/home/ed/Pictures/Misc_Photos/Games/rocketAfterBurner.png");
        afterBurner = new Image(fle2.toURI().toString());
        setPosition(100, 100);
    }

    void setOverallForceNull(){
        overallForce = new Unitvector();
        overallForce.initNullVector();
    }

    void drawShip(GraphicsContext gc, double rot){

        if(ignition == false)
            drawRotatedImage(gc, img, rot, posX, posY);
        else{
            drawRotatedImage(gc, afterBurner, rot, posX, posY);
        }
    }
    void drawMissile(GraphicsContext gc){
        for(missile mis : firedMissiles){
            //System.out.println(mis.getPosX() + " " + mis.getPosY());
            drawRotatedImage(gc, mis.getImg(), mis.getRotation(), mis.posX,
                    mis.posY);
            //need to rotate this about the same point that the other is rotated around
        }
    }
    void noListCalculatePos(double time, Unitvector force){
        //here we remember the overall force and only multiply it to each new force
        //when a new one is added (user presses a direction key)
        calcOverallForce(force);
        //System.out.println(overallForce.getForceX());

        overallForce.drag();
        posX += overallForce.getForceX() * time;
        posY += overallForce.getForceY() * time;
    }
    void calcOverallForce(Unitvector force){
        //each time direction and acceleration changes add the new vector to the
        //overall force (right word?)
        overallForce.setForceX(force.getForceX() + overallForce.getForceX());
        overallForce.setForceY(force.getForceY() + overallForce.getForceY());
        //System.out.println(force.getForceX() + " " + overallForce.getForceX());
    }

    void updateMissile(double time){
        List<missile> toRemove = new ArrayList<>();
        for(missile ms : firedMissiles){
            //System.out.println(ms.getPosX() + " " + ms.getPosY());
            ms.move(ms.overallForce.getForceX() * time, ms.overallForce.getForceY() * time);
            if(ms.checkOutOfBounds()){
                toRemove.add(ms);
            }
        }
        firedMissiles.removeAll(toRemove);
    }

    public void setIgnition(boolean ignition) {
        this.ignition = ignition;
    }

    void fireMissile(double angle){
        //System.out.println("this has happened");
        missile mis = new missile(this, angle);
        mis.setImg();
        mis.overallForce.setAccelation(250);
        mis.findHead(this);
        mis.overallForce.calcVelocity(angle);
        firedMissiles.add(mis);
    }

}
class Unitvector{
    //will be a unit vector and used to show all the forces acting
    //on the rocket ship
    private double forceX;
    private double forceY;
    private double accelation;

    void calcVelocity(double theta){
        //finds the direction associated with the speed of the object
        //to make a vector
        forceX = accelation * Math.cos(Math.toRadians(theta));
        forceY = accelation * Math.sin(Math.toRadians(theta));
        //unit vector in the direction of the angle
    }
    void drag(){
        forceY *= 0.997;
        forceX *= 0.997;
    }
    public void incrementAcceleration(double i){
        this.accelation += i;
    }

    public double getForceY() {
        return forceY;
    }

    public double getForceX() {
        return forceX;
    }

    public void setAccelation(double accelation) {
        this.accelation = accelation;
    }

    void initNullVector(){
        forceX = 0;
        forceY= 0;
        accelation = 0;
    }

    void setForceX(double nforceX) {
        this.forceX = nforceX;
    }

    void setForceY(double nforceY) {
        this.forceY = nforceY;
    }
}
class missile extends MovingObject{
    //when space is pressed fires a missile according the the angle the rocket ship is
    //currently at
    private double rotation;
    private static double radius;
    double headX;
    double headY;

    missile(RocketShip rocketShip, double rot){
        posX = rocketShip.getPosX() + rocketShip.getWidth();
        posY = rocketShip.getPosY() + rocketShip.getHeight() / 1.5;
        //System.out.println("head is: " + posX + ", " + posY);
        rotation = rot;

        overallForce = new Unitvector();
        overallForce.initNullVector();

        radius = new TrigStuff().findRadius(rocketShip.getPosX() + rocketShip.getWidth() /1.5,
                rocketShip.getPosY() + rocketShip.getHeight() /1.5,
                rocketShip.getPosX(), rocketShip.getPosY());
        //this roughly calculates where the image should be drawn from based on the radius of the ship
        //image

    }
    void setImg(){
        File fle = new File("/home/ed/Pictures/Misc_Photos/Games/missile.png");
        img = new Image(fle.toURI().toString());
    }

    public boolean checkOutOfBounds(){
        return posX < -20 || posX > boardInfo.width + 10
                || posY < -10 || posY > boardInfo.height + 10;
    }

    void move(double valX, double valY){
        //moves the missile according to time * acceleration
        posX += valX;
        posY += valY;
    }
    protected void findHead(MovingObject rS){
        //uses points on a circle around the center of the point of rotation to vaguely
        //start the missile from the nose of the rocket

        //System.out.println(rS.getimHeight() + " " + rS.getimWidth());
        TrigStuff help = new TrigStuff();
        posX = help.findCircleX(rS.getPosX() + 27,
                rotation, radius);
        posY = help.findCircleY(rS.getPosY() + 6,
                rotation, radius);
        //this is hardcoded wank but its the only thing thats vaguely worked
        System.out.println(posX + " " + posY);
    }
    protected void findMissileHead(MovingObject rS){
        //this is probably really wasteful (and doesn't work lol)

        //uses points on a circle around the center of the point of rotation.
        //System.out.println(rS.getimHeight() + " " + rS.getimWidth());
        TrigStuff help = new TrigStuff();
        double missileRadius = help.findRadius(rS.getPosX() + rS.img.getWidth() /1.5,
                rS.getPosY() + rS.img.getHeight() / 1.5, rS.getPosX(), rS.getPosY());

        headX = help.findCircleX(rS.getPosX() + rS.img.getWidth() /1.5,
                rotation, missileRadius);
        headY = help.findCircleY(rS.getPosY() + rS.img.getHeight() / 1.5,
                rotation, missileRadius);
        //this is hardcoded wank but its the only thing thats vaguely worked
        System.out.println(headX + " " + headY);

        //this will be used to find where the head of the missile is to check for collisions
        //with the target
    }
    double getRotation() {
        return rotation;
    }
}

And the parent class for the moving objects. Image is rotated every time it is drawn- this seems pretty wasteful to me.

import java.io.File;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.RadioMenuItem;
import javafx.scene.image.Image;
import javafx.scene.transform.Rotate;

class MovingObject {
    //this will be a parent class for rocket ship with positional information
    Image img;
    double posX;
    double posY;
    double width;
    double height;
    Unitvector overallForce;

    void rotate(GraphicsContext gc, double angle, double px, double py) {
        Rotate r = new Rotate(angle, px, py);
        gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy());
    }
    /**
     * Draws an image on a graphics context.
     *This rotates the entire graphical context- is this efficient
     * The image is drawn at (tlpx, tlpy) rotated by angle pivoted around the point:
     *   (tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2)
     *
     * @param gc the graphics context the image is to be drawn on.
     * @param angle the angle of rotation.
     * @param tlpx the top left x co-ordinate where the image will be plotted (in canvas co-ordinates).
     * @param tlpy the top left y co-ordinate where the image will be plotted (in canvas co-ordinates).
     */
    void drawRotatedImage(GraphicsContext gc, Image image, double angle, double tlpx, double tlpy) {
        gc.save(); // saves the current state on stack, including the current transform
        //System.out.println(tlpx + image.getWidth() / 1.5 + " s" + (tlpy + image.getHeight() / 1.5));
        rotate(gc, angle, tlpx + image.getWidth() / 1.5, tlpy + image.getHeight() / 1.5);
        gc.drawImage(image, tlpx, tlpy);
        gc.restore(); // back to original state (before rotation)
    }
    void initImage(String fileName){
        File fle = new File(fileName);
        setImage(new Image(fle.toURI().toString()));
    }
    void setImage(Image i) {
        this.img = i;
        width = i.getWidth();
        height = i.getHeight();
    }

    void drawNonRotated(GraphicsContext gc, MovingObject MO){
        gc.drawImage(MO.img, MO.posX, MO.posY);
    }
    protected void setPosition(int x, int y){
        posX = x;
        posY = y;
    }
    protected void setRandPosition(){
        Random rand = new Random();
        posX = rand.nextInt(440);
        posY = rand.nextInt(600);
        System.out.println(posY + " " + posX);
    }

    void setPosX(double coord){
        posX = coord;
    }
    void setPosY(double coord){
        posY = coord;
    }


    Image getImg() {
        return img;
    }
    double getWidth(){
        return width;
    }
    double getHeight(){
        return height;
    }

    boolean checkCollision(MovingObject collider, MovingObject colidee){
        //horrible English

        //issue here is that the fired missile will be rotated doesn't
        //work at all right now- hard to track position of front of missile                                                                    
        if(collider.getPosX() <= colidee.getPosX() + colidee.getWidth() &&
                collider.getPosX() >= colidee.getPosX() &&
                collider.getPosY() <= colidee.getPosY() + colidee.getHeight() &&
                collider.getPosY() >= colidee.getPosY()){
            return true;
        }
        return false;
    }

    double getPosX() {
        return posX;
    }

    double getPosY() {
        return posY;
    }
}

And some maths

import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.transform.Rotate;

public class TrigStuff {
    //this calculates the trajectory of where the ship needs to go
    private void rotate(GraphicsContext gc, double angle, double px, double py) {
        Rotate r = new Rotate(angle, px, py);
        gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy());
    }
    /**
     * Draws an image on a graphics context.
     *
     * The image is drawn at (tlpx, tlpy) rotated by angle pivoted around the point:
     *   (tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2)
     *
     * @param gc the graphics context the image is to be drawn on.
     * @param angle the angle of rotation.
     * @param tlpx the top left x co-ordinate where the image will be plotted (in canvas co-ordinates).
     * @param tlpy the top left y co-ordinate where the image will be plotted (in canvas co-ordinates).
     */
    private void drawRotatedImage(GraphicsContext gc, Image image, double angle, double tlpx, double tlpy) {
        gc.save(); // saves the current state on stack, including the current transform
        rotate(gc, angle, tlpx + image.getWidth() / 1.5, tlpy + image.getHeight() / 1.5);
        gc.drawImage(image, tlpx, tlpy);
        gc.restore(); // back to original state (before rotation)
    //todo get rid of this method and wherever it is called 
    }
    double findRotatedX(double PointofRotX, double PointofRotY, double angle,
                        double PointTOMoveX, double PointToMoveY){
        //the point of rotation is actually confusingly posX + image width /1.5

        //X=BX+(AX−BX)cosϕ−(AY−BY)sinϕ B is point of rotation
        return PointofRotX + (PointTOMoveX - PointofRotX) * Math.cos(Math.toRadians(angle))
                - (PointToMoveY - PointofRotY) * Math.sin(Math.toRadians(angle));
    }
    double findRotatedY(double PointofRotX, double PointofRotY, double angle,
                        double PointTOMoveX, double PointToMoveY){
        //Y=BY+(AX−BX)sinϕ+(AY−BY)cosϕ B is point of rotation
        return PointofRotY + (PointofRotX - PointofRotX) * Math.sin(Math.toRadians(angle))
                - (PointToMoveY - PointofRotY) * Math.cos(Math.toRadians(angle));
    }
    double findCircleX(double PointofRotX, double angle,
                       double radius){
        //its actually a circle with centre PoR and radius need to flip for screen coords
        return (radius * Math.cos(Math.toRadians(angle))) + PointofRotX;
    }
    double findCircleY(double PointofRotY, double angle,
                       double radius) {
        //its actually a circle with centre PoR and radius need to flip for screen coords
        //this doesn't work and probably never will
        return radius * Math.sin(Math.toRadians(angle)) + PointofRotY;
    }
    double findRadius(double xc, double yc, double xe, double ye){
        //where xc/yc is the center points, and xe ye are edge
        //(x-a)**2 + (y-b)**2 = r**
        double raduisSq = Math.pow((xe-xc), 2) + Math.pow((ye-yc), 2);
        return Math.sqrt(raduisSq);
    }
}
\$\endgroup\$
3
  • 3
    \$\begingroup\$ If the "boring code" is not too much you could include it here so that we can compile and run your game locally. \$\endgroup\$ – Roland Illig Oct 29 '17 at 11:21
  • \$\begingroup\$ apologies, just included everything (there's some unused methods in there but just ignore them) \$\endgroup\$ – jimmy_jazz Oct 29 '17 at 11:31
  • \$\begingroup\$ No apologies needed, since you are still new here. :) \$\endgroup\$ – Roland Illig Oct 29 '17 at 11:32
3
\$\begingroup\$
  1. All constants should be declared in a final variable.

    final String IMAGE_DIRECTORY = "/home/ed/Pictures/Misc_Photos/Games/";
    final String TARGET_IMAGE_FILENAME = "target.png";
    File file = new File(IMAGE_DIRECTORY + TARGET_IMAGE_FILENAME);
    
  2. Methods and classes should have a documentary comment for readability.

  3. Avoid using one letter variable, it will lead to confusion especially when your program grew larger.

    Rotate r = new Rotate();
    

Should be:

Rotate rotate = new Rotate();
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.