我如何以旋转内置的Java图形旋转的能力进行自上而下的视图?

发布于 2025-01-30 17:49:06 字数 3882 浏览 3 评论 0原文

我试图在屏幕中间的静态播放器上进行赛车游戏,并在屏幕中间的静态播放器上进行赛车,因此地图不会将播放器移动到地图上,而是围绕播放器移动。由于这是一款赛车游戏,所以我希望它也与汽车有些相似,但是我在将地图围绕播放器旋转并与翻译合作时遇到了麻烦。

我已经尝试通过从中添加或减法来跟踪中心,这是我为翻译所做的,但它不适用于旋转方法。旋转功能不会在玩家周围旋转,而是会围绕其他点旋转播放器,并且翻译将与旋转不同的位置捕捉​​到其他位置。我确定我的方法有缺陷,并且我已经阅读了有关层等的信息,但是我不确定我能对它们做什么或如何使用它们。另外,关于如何使用Java图形的任何建议将不胜感激!

这是我的主要内容:

import javax.swing.JFrame;

import java.awt.BorderLayout;

public class game 
{
    public static void main(String []args)
    {
        JFrame frame = new JFrame();
        final int FRAME_WIDTH = 1000;
        final int FRAME_HEIGHT = 600;
        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final Map b = new Map();
        frame.add(b,BorderLayout.CENTER);
        frame.setVisible(true); 
        b.startAnimation();
    }
}

这是处理所有图形的类

import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JComponent;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Map extends JComponent implements Runnable, KeyListener
{   
    private int speed = 5;
    private int xcenter = 500; // starts on player
    private int ycenter = 300;
    private double angle = 0.0;
    
    private int[] xcords = {xcenter+10, xcenter, xcenter+20};
    private int[] ycords = {ycenter-10, ycenter+20, ycenter+20};
    
    private boolean moveNorth = false;
    private boolean moveEast = false;
    private boolean moveSouth = false;
    private boolean moveWest = false;

    public Map()
    {
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }
    
    public void startAnimation()
    {
        Thread t = new Thread(this);
        t.start();
    }
    
    public void paintComponent(Graphics g)
    {
        g.fillPolygon(xcords, ycords, 3);

        // move screen
        if(moveNorth)
        {
            ycenter += speed;
            g.translate(xcenter, ycenter);
        }
        
        else if(moveEast)
        {
            angle += ((1 * Math.PI/180) % (2 * Math.PI));
            ((Graphics2D) g).rotate(angle, 0, 0);
        }
        
        else if(moveSouth)
        {
            System.out.println(xcenter + ", " + ycenter);
            ycenter -= speed;
            ((Graphics2D) g).rotate(angle, 0, 0);
            g.translate(xcenter, ycenter);
        }
        
        else if(moveWest)
        {
            angle -= Math.toRadians(1) % (2 * Math.PI);
            ((Graphics2D) g).rotate(angle, 0, 0);
        }
        for(int i = -10; i < 21; i++)
        {
            g.drawLine(i * 50, -1000, i * 50, 1000);
            g.drawLine(-1000, i * 50, 1000, i * 50);
        }
        g.drawOval(0, 0, 35, 35);

    }
    
    public void run()
    {
        while (true)
        {
            try
            {
                if(moveNorth || moveEast || moveSouth || moveWest)
                {
                    repaint();
                }
                Thread.sleep(10);
            }
            catch (InterruptedException e)
            {
            
            }
        }
    }
    
    public void keyPressed(KeyEvent e)
    {
        if(e.getExtendedKeyCode() == 68) // d
        {
            moveEast = true;
        }
        
        else if(e.getExtendedKeyCode() == 87) // w
        {
            moveNorth = true;
        }
        
        else if(e.getExtendedKeyCode() == 65) // a
        {
            moveWest = true;
        }
        
        else if(e.getExtendedKeyCode() == 83) // s
        {
            moveSouth = true;
        }
        
    }
    
    public void keyReleased(KeyEvent e)
    {
        moveNorth = false;
        moveEast = false;
        moveSouth = false;
        moveWest = false;
    }
    
    public void keyTyped(KeyEvent e)
    {
        
    }
}

I'm trying to make a racing game with the top down view on a static player in the middle of the screen, so instead of moving the player through the map, the map would move around the player. Since it's a racing game, I wanted it to also be somewhat similar to a car, but I've been having trouble with rotating the map around the player and having that work with translations.

I've tried keeping track of the center by adding or subtracting from it, which is what I did for the translations, but it doesn't work with the rotate method. The rotate function wouldn't rotate about the player and instead would rotate the player around some other point, and the translations would snap to a different location from the rotations. I'm sure my approach is flawed, and I have read about layers and such, but I'm not sure what I can do with them or how to use them. Also, any recommendations as to how to use java graphics in general would be greatly appreciated!

This is what I have in my main:

import javax.swing.JFrame;

import java.awt.BorderLayout;

public class game 
{
    public static void main(String []args)
    {
        JFrame frame = new JFrame();
        final int FRAME_WIDTH = 1000;
        final int FRAME_HEIGHT = 600;
        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final Map b = new Map();
        frame.add(b,BorderLayout.CENTER);
        frame.setVisible(true); 
        b.startAnimation();
    }
}

And this is the class that handles all the graphics

import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JComponent;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Map extends JComponent implements Runnable, KeyListener
{   
    private int speed = 5;
    private int xcenter = 500; // starts on player
    private int ycenter = 300;
    private double angle = 0.0;
    
    private int[] xcords = {xcenter+10, xcenter, xcenter+20};
    private int[] ycords = {ycenter-10, ycenter+20, ycenter+20};
    
    private boolean moveNorth = false;
    private boolean moveEast = false;
    private boolean moveSouth = false;
    private boolean moveWest = false;

    public Map()
    {
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }
    
    public void startAnimation()
    {
        Thread t = new Thread(this);
        t.start();
    }
    
    public void paintComponent(Graphics g)
    {
        g.fillPolygon(xcords, ycords, 3);

        // move screen
        if(moveNorth)
        {
            ycenter += speed;
            g.translate(xcenter, ycenter);
        }
        
        else if(moveEast)
        {
            angle += ((1 * Math.PI/180) % (2 * Math.PI));
            ((Graphics2D) g).rotate(angle, 0, 0);
        }
        
        else if(moveSouth)
        {
            System.out.println(xcenter + ", " + ycenter);
            ycenter -= speed;
            ((Graphics2D) g).rotate(angle, 0, 0);
            g.translate(xcenter, ycenter);
        }
        
        else if(moveWest)
        {
            angle -= Math.toRadians(1) % (2 * Math.PI);
            ((Graphics2D) g).rotate(angle, 0, 0);
        }
        for(int i = -10; i < 21; i++)
        {
            g.drawLine(i * 50, -1000, i * 50, 1000);
            g.drawLine(-1000, i * 50, 1000, i * 50);
        }
        g.drawOval(0, 0, 35, 35);

    }
    
    public void run()
    {
        while (true)
        {
            try
            {
                if(moveNorth || moveEast || moveSouth || moveWest)
                {
                    repaint();
                }
                Thread.sleep(10);
            }
            catch (InterruptedException e)
            {
            
            }
        }
    }
    
    public void keyPressed(KeyEvent e)
    {
        if(e.getExtendedKeyCode() == 68) // d
        {
            moveEast = true;
        }
        
        else if(e.getExtendedKeyCode() == 87) // w
        {
            moveNorth = true;
        }
        
        else if(e.getExtendedKeyCode() == 65) // a
        {
            moveWest = true;
        }
        
        else if(e.getExtendedKeyCode() == 83) // s
        {
            moveSouth = true;
        }
        
    }
    
    public void keyReleased(KeyEvent e)
    {
        moveNorth = false;
        moveEast = false;
        moveSouth = false;
        moveWest = false;
    }
    
    public void keyTyped(KeyEvent e)
    {
        
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

随心而道 2025-02-06 17:49:06

您必须记住,转换很复杂,因此,如果您将Graphics上下文旋转45度,则在旋转45度(旋转点)之后绘制的所有内容,如果旋转)同样,将其涂成45度,将其涂成90度。

如果您想在转换后绘制其他内容,则需要撤消转换,或者最好,或者在graphics上下文中拍摄快照并在您时处置(快照)完毕。

您还需要提防旋转点,graphics2d#rotate(double)将围绕原点旋转graphics(即0x0) ),这可能是不可取的。您可以通过更改原点点(IE翻译)或使用graphics2d#旋转(double,double,double)来更改此操作,从而使您可以定义旋转点。

例如...

“在此处输入图像描述”

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.image.BufferedImage;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
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;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    public class TestPane extends JPanel {

        enum Direction {
            LEFT, RIGHT;
        }

        protected enum InputAction {
            PRESSED_LEFT, PRESSED_RIGHT, RELEASED_LEFT, RELEASED_RIGHT
        }

        private BufferedImage car;
        private BufferedImage road;

        private Set<Direction> directions = new TreeSet<>();

        private double directionOfRotation = 0;

        public TestPane() throws IOException {
            car = ImageIO.read(getClass().getResource("/images/Car.png"));
            road = ImageIO.read(getClass().getResource("/images/Road.png"));

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), InputAction.PRESSED_LEFT);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), InputAction.RELEASED_LEFT);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), InputAction.PRESSED_RIGHT);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), InputAction.RELEASED_RIGHT);

            am.put(InputAction.PRESSED_LEFT, new DirectionAction(Direction.LEFT, true));
            am.put(InputAction.RELEASED_LEFT, new DirectionAction(Direction.LEFT, false));
            am.put(InputAction.PRESSED_RIGHT, new DirectionAction(Direction.RIGHT, true));
            am.put(InputAction.RELEASED_RIGHT, new DirectionAction(Direction.RIGHT, false));

            Timer timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (directions.contains(Direction.RIGHT)) {
                        directionOfRotation += 1;
                    } else if (directions.contains(Direction.LEFT)) {
                        directionOfRotation -= 1;
                    }

                    // No doughnuts for you :P
                    if (directionOfRotation > 180) {
                        directionOfRotation = 180;
                    } else if (directionOfRotation < -180) {
                        directionOfRotation = -180;
                    }

                    repaint();
                }
            });
            timer.start();
        }

        protected void setDirectionActive(Direction direction, boolean active) {
            if (active) {
                directions.add(direction);
            } else {
                directions.remove(direction);
            }
        }

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

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

        protected void drawCar(Graphics2D g2d) {
            g2d = (Graphics2D) g2d.create();
            int x = (getWidth() - car.getWidth()) / 2;
            int y = (getHeight() - car.getHeight()) / 2;
            g2d.drawImage(car, x, y, this);
            g2d.dispose();
        }

        protected void drawRoadSurface(Graphics2D g2d) {
            g2d = (Graphics2D) g2d.create();
            // This sets the point of rotation at the center of the window
            int midX = getWidth() / 2;
            int midY = getHeight() / 2;
            g2d.rotate(Math.toRadians(directionOfRotation), midX, midY);
            // We then need to offset the top/left corner so that what 
            // we want draw appears to be in the center of the window,
            // and thus will be rotated around it's center
            int x = midX - (road.getWidth() / 2);
            int y = midY - (road.getHeight() / 2);
            g2d.drawImage(road, x, y, this);
            g2d.dispose();
        }

        protected class DirectionAction extends AbstractAction {

            private Direction direction;
            private boolean active;

            public DirectionAction(Direction direction, boolean active) {
                this.direction = direction;
                this.active = active;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                setDirectionActive(direction, active);
            }

        }

    }
}

You have to keep in mind that transformations are compounding, so if you rotate the Graphics context by 45 degrees, everything painted after it will be rotated 45 degrees (around the point of rotation), if you rotate it again by 45 degrees, everything painted after it will be rotated a total of 90 degrees.

If you want to paint additional content after a transformation, then you either need to undo the transformation, or, preferably, take a snapshot of the Graphics context and dispose of it (the snapshot) when you're done.

You also need to beware of the point of rotation, Graphics2D#rotate(double) will rotate the Graphics around the point of origin (ie 0x0), which may not be desirable. You can change this by either changing the origin point (ie translate) or using Graphics2D#rotate(double, double, double), which allows you to define the point of rotation.

For example...

enter image description here

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.image.BufferedImage;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
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;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    public class TestPane extends JPanel {

        enum Direction {
            LEFT, RIGHT;
        }

        protected enum InputAction {
            PRESSED_LEFT, PRESSED_RIGHT, RELEASED_LEFT, RELEASED_RIGHT
        }

        private BufferedImage car;
        private BufferedImage road;

        private Set<Direction> directions = new TreeSet<>();

        private double directionOfRotation = 0;

        public TestPane() throws IOException {
            car = ImageIO.read(getClass().getResource("/images/Car.png"));
            road = ImageIO.read(getClass().getResource("/images/Road.png"));

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), InputAction.PRESSED_LEFT);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), InputAction.RELEASED_LEFT);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), InputAction.PRESSED_RIGHT);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), InputAction.RELEASED_RIGHT);

            am.put(InputAction.PRESSED_LEFT, new DirectionAction(Direction.LEFT, true));
            am.put(InputAction.RELEASED_LEFT, new DirectionAction(Direction.LEFT, false));
            am.put(InputAction.PRESSED_RIGHT, new DirectionAction(Direction.RIGHT, true));
            am.put(InputAction.RELEASED_RIGHT, new DirectionAction(Direction.RIGHT, false));

            Timer timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (directions.contains(Direction.RIGHT)) {
                        directionOfRotation += 1;
                    } else if (directions.contains(Direction.LEFT)) {
                        directionOfRotation -= 1;
                    }

                    // No doughnuts for you :P
                    if (directionOfRotation > 180) {
                        directionOfRotation = 180;
                    } else if (directionOfRotation < -180) {
                        directionOfRotation = -180;
                    }

                    repaint();
                }
            });
            timer.start();
        }

        protected void setDirectionActive(Direction direction, boolean active) {
            if (active) {
                directions.add(direction);
            } else {
                directions.remove(direction);
            }
        }

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

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

        protected void drawCar(Graphics2D g2d) {
            g2d = (Graphics2D) g2d.create();
            int x = (getWidth() - car.getWidth()) / 2;
            int y = (getHeight() - car.getHeight()) / 2;
            g2d.drawImage(car, x, y, this);
            g2d.dispose();
        }

        protected void drawRoadSurface(Graphics2D g2d) {
            g2d = (Graphics2D) g2d.create();
            // This sets the point of rotation at the center of the window
            int midX = getWidth() / 2;
            int midY = getHeight() / 2;
            g2d.rotate(Math.toRadians(directionOfRotation), midX, midY);
            // We then need to offset the top/left corner so that what 
            // we want draw appears to be in the center of the window,
            // and thus will be rotated around it's center
            int x = midX - (road.getWidth() / 2);
            int y = midY - (road.getHeight() / 2);
            g2d.drawImage(road, x, y, this);
            g2d.dispose();
        }

        protected class DirectionAction extends AbstractAction {

            private Direction direction;
            private boolean active;

            public DirectionAction(Direction direction, boolean active) {
                this.direction = direction;
                this.active = active;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                setDirectionActive(direction, active);
            }

        }

    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文