Getting my sprite to face in a certain direction b

2020-02-15 17:32发布

问题:

So I've pretty much thrown together a basic game in java by following a bunch of different tutorials - the problem is i cant manage to figure out how to get my sprite to move in different directions. Here is the code for my main

package com.game.src.main;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JFrame;

public class Game extends Canvas implements Runnable {

private static final long serialVersionUID = 1L;

public static final int WIDTH = 850;
public static final int HEIGHT = 650;
public static final int SCALE = 1;
public final String TITLE = "Racing Game!";

static ServerSocket serverSocket;
static Socket socket;
static DataOutputStream out;

private boolean running = false;
private Thread thread;

private BufferedImage image = new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);
private BufferedImage spriteSheet = null;
private BufferedImage spriteSheet2 = null;
private BufferedImage background = null;
private BufferedImage MenuBackground = null;

private Player p;

private Player2 p2;

private Menu menu;

public static enum STATE {
    MENU,
    GAME
};

public static STATE State = STATE.MENU;

public void init() {

    BufferedImageLoader loader = new BufferedImageLoader();
    try {

        spriteSheet = loader.loadImage("/Sprite_Sheet.png");

        background = loader.loadImage("/Track.png");

        MenuBackground = loader.loadImage("/MenuBG.fw.png");
    }
    catch (IOException e) {
        e.printStackTrace();
    }

    menu = new Menu();

    addKeyListener(new KeyInput(this));
    this.addMouseListener(new MouseInput());

    p = new Player(365, 500, this);

    p2 = new Player2(365, 550, this);

}

private synchronized void start() {
    if(running)
        return; 
    running = true;
    thread = new Thread(this);
    thread.start();
}

private synchronized void stop() {

    if(!running)
        return;
    running = false;
    try {
        thread.join();
    } 

    catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.exit(1);
}

public void run() {

    init();

    long lastTime = System.nanoTime();  
    final double amountOfTicks = 60.0;
    double ns = 1000000000 / amountOfTicks;
    double delta = 0;

    int updates = 0;
    int frames = 0;
    long timer = System.currentTimeMillis();

    while(running) {

        long now = System.nanoTime();
        delta += (now - lastTime) / ns;
        lastTime = now;

        if(delta >= 1) {
            tick();
            updates++;
            delta--;
        }
        render();
        frames++;
        if(System.currentTimeMillis() - timer > 1000) {
            timer += 1000;
            System.out.println(updates + " FPS, TICKS " + frames);

            updates = 0;
            frames = 0; 
        }           
    }

    stop();
}

private void tick() {
    if(State == STATE.GAME){
        p.tick();
        p2.tick();
    }

}

private void render() {

    BufferStrategy bs = this.getBufferStrategy();

    if(bs == null) {

        createBufferStrategy(3);
        return;

    }

    Graphics g = bs.getDrawGraphics();

    g.drawImage(image, 0, 0, getWidth(), getHeight(), this);

    g.drawImage(MenuBackground, 0, 0, null);

    if(State == STATE.GAME){

        //Drawing the main games background 
        g.drawImage(background, 0, 0, null);

        p.render(g);    

        p2.render(g);
    }

    else if(State == STATE.MENU){

        menu.render(g);

    }

    g.dispose();
    bs.show();

}

public void keyPressed(KeyEvent e){

    int key = e.getKeyCode();

    if(State == STATE.GAME){
        if(key == KeyEvent.VK_RIGHT){
            p.setVelX(5);       
        }
        if(key == KeyEvent.VK_D){
            p2.setVelX2(5);
        }

        else if(key == KeyEvent.VK_LEFT) {
            p.setVelX(-5);
        }
        else if(key == KeyEvent.VK_A) {
            p2.setVelX2(-5);
        }
        else if(key == KeyEvent.VK_DOWN) {
            p.setVelY(5);
        }
        else if(key == KeyEvent.VK_S) {
            p2.setVelY2(5);
        }

        else if(key == KeyEvent.VK_UP) {
            p.setVelY(-5);
        }
        else if(key == KeyEvent.VK_W) {
            p2.setVelY2(-5);
        }
    }       
}

public void keyReleased(KeyEvent e){
    int key = e.getKeyCode();

    if(key == KeyEvent.VK_RIGHT){
        p.setVelX(0);
    }
    if(key == KeyEvent.VK_D){
        p2.setVelX2(0);
    }
    else if(key == KeyEvent.VK_LEFT) {
        p.setVelX(0);
    }
    else if(key == KeyEvent.VK_A) {
        p2.setVelX2(0);
    }
    else if(key == KeyEvent.VK_DOWN) {
        p.setVelY(0);
    }
    else if(key == KeyEvent.VK_S) {
        p2.setVelY2(0);
    }
    else if(key == KeyEvent.VK_UP) {
        p.setVelY(0);
    }
    else if(key == KeyEvent.VK_W) {
        p2.setVelY2(0);
    }   
}



public static void main(String args[]) throws Exception {

    Game game = new Game();

    game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
    game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
    game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));

    JFrame frame = new JFrame(game.TITLE);
    frame.add(game);
    frame.pack();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

    game.start();

    System.out.println("Starting server....");

    serverSocket = new ServerSocket(7777);

    System.out.println("Server started");

    socket = serverSocket.accept();

    System.out.println("Connecting from: " + socket.getInetAddress());

    out = new DataOutputStream(socket.getOutputStream());

    out.writeUTF("This is a test of Java Sockets");

    System.out.println("Data has been sent");

}

public BufferedImage getSpriteSheet() {
    return spriteSheet;
}
public BufferedImage getSpriteSheet2() {
    return spriteSheet2;
}

}

This is my player class

package com.game.src.main;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class Player {

private double x;
private double y;

private double velX = 0;
private double velY = 0;

private BufferedImage player;

BufferedImageLoader loader = new BufferedImageLoader();
BufferedImage SpriteSheet = null;

public Player(double x, double y, Game game) {

    this.x = x;
    this.y = y;

    //New instance of Sprite sheet - reading from buffered image loader
    SpriteSheet ss = new SpriteSheet(game.getSpriteSheet());

    player = ss.grabImage(1, 1, 50, 50);

    try {

        SpriteSheet = loader.loadImage("/Sprite_Sheet.png");

    }

    catch(Exception e) {    
        e.printStackTrace();
    }
}

public void tick() {

    x+=velX;

    y+=velY;

    //Adding basic collision
    if(x < 0 + 50) {
        x = 0 + 50;
    }
    if(x >= 850 - 100) {
        x = 850 - 100;
    }
    if(y < 0 + 100) {
        y = 0 + 100;
    }
    if(y >= 650 - 100){
        y = 650 - 100;
    }
}

public void render(Graphics g){

    //Draw Track
    Color c1 = Color.green;
    g.setColor( c1 );
    g.fillRect( 150, 200, 550, 300 ); //grass

    Color c2 = Color.black;
    g.setColor( c2 );
    g.drawRect(50, 100, 750, 500); // outer edge
    g.drawRect(150, 200, 550, 300); // inner edge       

    Color c3 = Color.yellow;
    g.setColor( c3 );
    g.drawRect( 100, 150, 650, 400 ); // mid-lane marker

    Color c4 = Color.white;
    g.setColor( c4 );
    g.drawLine( 425, 500, 425, 600 ); // start line

    g.drawImage(player, (int)x, (int)y, null);

}

public double getX(Graphics g){
    return x;
}
public double getY(){
    return y;
}
public void setX(double x){
    this.x = x;
}
public void setY(double y){
    this.y = y;
}
public void setVelX(double velX){
    this.velX = velX;
}
public void setVelY(double velY){
    this.velY = velY;
}
}

I have two players in this game but i'm really stuck on how i can change the sprites direction by 22.5% in a desired direction so if i pressed the up key for player 1 it would rotate my car 22.5% north etc. I have a sprite sheet with 16 sprites for each player for every change in angle by 22.5% This is really confusing me and i'm not sure how i can implement this,

Thanks for taking the time to look

回答1:

This is a basic example of spinning a sprite

What this is maintain's a virtual state which the Player object inspects in order to determine how it should be changed accordingly. This separates the action from the result, meaning that it would be possible to substitute the action (arrow up key) with some other action, but still obtain the same result.

This example also uses the key bindings API, which doesn't suffer from the same focus related issues that KeyListener does, but this is a pure Swing API and won't be compatiable with Canvas, but is a nice demonstration ;)

The real magic occurs in the characters paint method...

public void paint(Graphics2D g2d) {
    Graphics2D g = (Graphics2D) g2d.create();
    AffineTransform at = new AffineTransform();
    at.translate(x, y);
    at.rotate(Math.toRadians(angle), character.getWidth() / 2, character.getHeight() / 2);
    g.transform(at);
    g.drawImage(character, 0, 0, null);
}

Basically, this creates a AffineTransformation which is then compounded to produce the result we need. That is, first it's anchor position is translated to the characters x/y position and then rotated about the characters center point. Because it's been translated, we can simply paint the character at 0x0. This much easier then try to calculate the characters rotation anchor somewhere else in virtual space - IMHO

The character is rotated by pressing either the Up or Down arrow keys. While pressed, the character will continue to rotate, this is a feature of the example for demonstration purpose.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RotateCharater {

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

    public RotateCharater() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private DefaultState state;
        private Player player;

        public TestPane() {
            player = new Player();
            state = new DefaultState();

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "upKeyPressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "upKeyReleased");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "downKeyPressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "downKeyReleased");

            ActionMap am = getActionMap();
            am.put("upKeyPressed", new UpKeyAction(state, true));
            am.put("upKeyReleased", new UpKeyAction(state, false));
            am.put("downKeyPressed", new DownKeyAction(state, true));
            am.put("downKeyReleased", new DownKeyAction(state, false));

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    player.update(state);
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            player.paint(g2d);
            g2d.dispose();
        }

        public class UpKeyAction extends AbstractAction {

            private DefaultState state;
            private boolean pressed;

            public UpKeyAction(DefaultState state, boolean pressed) {
                this.state = state;
                this.pressed = pressed;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                state.setUpKeyPressed(pressed);
            }

        }
        public class DownKeyAction extends AbstractAction {

            private DefaultState state;
            private boolean pressed;

            public DownKeyAction(DefaultState state, boolean pressed) {
                this.state = state;
                this.pressed = pressed;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                state.setDownKeyPressed(pressed);
            }

        }
    }

    public interface State {

        public boolean isUpKeyPressed();
        public boolean isDownKeyPressed();

    }

    public class DefaultState implements State {

        private boolean upKeyPressed;
        private boolean downKeyPressed;

        public boolean isDownKeyPressed() {
            return downKeyPressed;
        }

        public boolean isUpKeyPressed() {
            return upKeyPressed;
        }

        public void setDownKeyPressed(boolean downKeyPressed) {
            this.downKeyPressed = downKeyPressed;
            upKeyPressed = false;
        }

        public void setUpKeyPressed(boolean upKeyPressed) {
            this.upKeyPressed = upKeyPressed;
            downKeyPressed = false;
        }

    }

    public class Player {

        private BufferedImage character;
        private int x = 100 - 32, y = 100 - 32;
        private double angle;

        public Player() {
            try {
                character = ImageIO.read(getClass().getResource("/Character.png"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        public void paint(Graphics2D g2d) {
            Graphics2D g = (Graphics2D) g2d.create();
            AffineTransform at = new AffineTransform();
            at.translate(x, y);
            at.rotate(Math.toRadians(angle), character.getWidth() / 2, character.getHeight() / 2);
            g.transform(at);
            g.drawImage(character, 0, 0, null);
        }

        public void update(State state) {

            if (state.isUpKeyPressed()) {
                angle -= 22.5;
            } else if (state.isDownKeyPressed()) {
                angle += 22.5;
            }

        }

    }

}

Remember, this is just an example used to present the concept ;)