为啥我的平台不绘制当使用带有数组列表的 for 循环(访问多个平台)时

Posted

技术标签:

【中文标题】为啥我的平台不绘制当使用带有数组列表的 for 循环(访问多个平台)时【英文标题】:Why doesn't my Platform draw When using for loops (to access multiple platforms) with array lists为什么我的平台不绘制当使用带有数组列表的 for 循环(访问多个平台)时 【发布时间】:2022-01-14 00:42:12 【问题描述】:

这些都是我的课程,我正在尝试制作一个带有数组列表的平台游戏来保存我的平台,这样我就可以随时随地添加更多平台。出于某种原因,它没有绘制平台。

有人可以帮我解决这个问题或给我一个替代方案吗?

注意:我在重新创建代码时尚未使用或忘记删除的一些变量和方法。 打包游戏;

import Game.Frame;

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


    package Game;

import javax.swing.*;
import java.awt.*;

public class Frame extends JFrame 
    GamePanel panel;
    public Frame() 
        panel = new GamePanel();
        this.add(panel);
        this.setTitle("Platformer Game");
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    

package Game;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Timer;

public class GamePanel extends JPanel implements ActionListener
        Player player1;
        Map map1;
        final int SCREEN_WIDTH = 1000;
        final int SCREEN_HEIGHT = 600;
        final int PLAYER_WIDTH = 50;
        final int PLAYER_HEIGHT = 60;
        final Dimension SCREEN_SIZE = new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT);
        boolean falling = false;
        boolean playing = true;
        Image backgroundImage;
        Thread gameThread;
        Image image;
        Graphics graphics;
        Timer gameTimer;
        ArrayList<Map> platform = new ArrayList<>();

        public GamePanel() 
            java.net.URL imgIcon = Main.class.getResource(
                    "/Resources/spaceImage.jpg");
            backgroundImage = new ImageIcon(imgIcon).getImage();
            newPlayer();
            newMap();

            this.setFocusable(true);
            this.setPreferredSize(SCREEN_SIZE);
            this.setOpaque(true);
            this.addKeyListener(new KeyListener(

            ) 
                @Override
                public void keyTyped(KeyEvent e) 

                @Override
                public void keyPressed(KeyEvent e) 
                    KeyPressed(e);
                

                @Override
                public void keyReleased(KeyEvent e) 
                    KeyReleased(e);
                
            );
            gameTimer = new Timer();
            gameTimer.schedule(new TimerTask()

                @Override
                public void run() 
                    player1.move();
                    repaint();
                
            , 0 , 17);
        

        public void paint(Graphics g) 
            image = createImage(getWidth(),getHeight());
            graphics = image.getGraphics();
            draw(graphics);
            g.drawImage(image, 0,0, null);

        
        public void draw(Graphics g) 
            Graphics2D g2D = (Graphics2D) g;
            g2D.drawImage(backgroundImage, 0,0, null);
            player1.paint(g);
            for(Map map1: platform) 
                map1.paint(g2D);
            
        
        public void KeyPressed(KeyEvent e) 
            if(e.getKeyChar()=='a') 
                player1.keyLeft = true;
            
            if(e.getKeyChar()=='d') player1.keyRight = true;
            if(e.getKeyChar()=='s') player1.keyDown = true;
            if(e.getKeyChar()=='w') player1.keyUp = true;
        


        public void KeyReleased(KeyEvent e) 
            if(e.getKeyChar()=='a') player1.keyLeft = false;
            if(e.getKeyChar()=='d') player1.keyRight = false;
            if(e.getKeyChar()=='s') player1.keyDown = false;
            if(e.getKeyChar()=='w') player1.keyUp = false;
        

        public void newPlayer() 
            player1 = new Player((SCREEN_WIDTH/2)-(PLAYER_WIDTH/2), (SCREEN_HEIGHT/2)-(PLAYER_WIDTH/2), PLAYER_WIDTH, PLAYER_HEIGHT, this);
        

        public void newMap() 
            for(int i=50;i<650;i+=50)
                platform.add(new Map(i,600,50,50));
            
        


        public void gameOver() 

        


    @Override
    public void actionPerformed(ActionEvent e) 

    



package Game;

import Game.GamePanel;

import java.awt.*;
import java.awt.event.KeyEvent;

public class Player extends Rectangle
    double velocityY = 0;
    double velocityX = 0;
    final int PLAYER_WIDTH = 50;
    final int PLAYER_HEIGHT = 50;
    static int speed = 2;
    GamePanel panel;
    boolean keyRight = false;
    boolean keyLeft = false;
    boolean keyUp = false;
    boolean keyDown = false;
    Rectangle hitbox;

    public Player(int x, int y, int PLAYERWIDTH, int PLAYERHEIGHT, GamePanel panel) 
        super(x,y,PLAYERWIDTH,PLAYERHEIGHT);
        this.panel = panel;

        hitbox = new Rectangle();
    



    public void paint(Graphics g) 
        Graphics2D g2D = (Graphics2D) g;
        g2D.setColor(Color.red);
        g2D.fillRect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT);
    

    public void move() 
        if(keyLeft && keyRight || !keyLeft && !keyRight) 
            velocityX *= 0.8;
        
        if(keyLeft && !keyRight) 
            velocityX--;
        
        if(keyRight && !keyLeft) 
            velocityX++;
        
        if(velocityX > 0 && velocityX < 0.75) velocityX = 0;
        if(velocityX < 0 && velocityX > -0.75) velocityX = 0;

        if(velocityX > 7) velocityX = 7;
        if(velocityX < -7) velocityX = -7;

        if(keyUp) 
            velocityY = -6;
        
        velocityY += 0.3;


        y += velocityY;
        x += velocityX;

        hitbox.x = x;
        hitbox.y = y;
    




package Game;

import java.awt.*;

public class Map 
    int PLATFORM_WIDTH = 600;
    int PLATFORM_HEIGHT = 150;
    int x;
    int y;
    Rectangle hitbox;
    public Map(int x, int y, int PLATFORM_WIDTH, int PLATFORM_HEIGHT) 
        this.x = x;
        this.y = y;
        this.PLATFORM_WIDTH = PLATFORM_WIDTH;
        this.PLATFORM_HEIGHT = PLATFORM_HEIGHT;

        hitbox = new Rectangle(x,y,PLATFORM_WIDTH, PLATFORM_HEIGHT);
    

    public void paint(Graphics g) 
        Graphics2D g2D = (Graphics2D) g;
        g2D.setColor(Color.gray);
        g2D.fillRect(x,y,PLATFORM_WIDTH,PLATFORM_HEIGHT);
    


【问题讨论】:

运行程序时究竟发生了什么? 我注意到您绘制了所有平台,然后在顶部绘制了背景。 SCREEN_HEIGHT 设置为 600 并且您将平台初始位置 y 设置为 600 并且它永远不会移动... 【参考方案1】:

因此,您将屏幕高度设置为600final int SCREEN_HEIGHT = 600;,然后将您的平台y 位置也设置为600platform.add(new Map(i,600,50,50));

由于它们从不移动,这会将它们绘制到屏幕外,因此,一个快速的解决方案是将y 位置更改为可见范围内的某个位置,也许是550,这样你就会看到它们(开始)。

观察

有很多有趣的想法正在发生,我不确定你是否完全理解 API 的工作原理。

先看看:

Performing Custom Painting Painting in AWT and Swing

这将使您更好地了解绘制系统在 Swing 中的工作原理以及您应该如何使用它。

话虽如此,Swing 默认是双缓冲的,所以你不需要自己的后备缓冲区,只需覆盖 paintComponent 并绘制到 Graphics 上下文

@Override
protected void paintComponent(Graphics g) 
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();
    draw(g2d);
    g2d.dispose();

这将有助于消除一个可能的问题领域。

Swing 也不是线程安全的,因此您应该避免从事件分派线程的上下文之外向 UI(或 UI 所依赖的状态)更新日期。

您应该使用javax.swing.Timer,而不是使用java.util.Timer,这将在EDT 的上下文中生成它的回调。

更多详情请参阅Concurrency in Swing 和How to Use Swing Timers

gameTimer = new Timer(5, new ActionListener() 
    @Override
    public void actionPerformed(ActionEvent e) 
        player1.move();
        repaint();
    
);
gameTimer.start();

KeyListener 众所周知会引起问题,并且有更好的系统可以解决这些问题,请参阅How to Use Key Bindings 了解更多详细信息。

我也不确定Player 发生了什么

public class Player extends Rectangle 

    double velocityY = 0;
    double velocityX = 0;
    final int PLAYER_WIDTH = 50;
    final int PLAYER_HEIGHT = 50;
    static int speed = 2;
    GamePanel panel;
    boolean keyRight = false;
    boolean keyLeft = false;
    boolean keyUp = false;
    boolean keyDown = false;
    Rectangle hitbox;

    public Player(int x, int y, int PLAYERWIDTH, int PLAYERHEIGHT, GamePanel panel) 
        super(x, y, PLAYERWIDTH, PLAYERHEIGHT);
        this.panel = panel;

        hitbox = new Rectangle();
    

    public void paint(Graphics g) 
        Graphics2D g2D = (Graphics2D) g;
        g2D.setColor(Color.red);
        g2D.fillRect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT);
    

您从Rectangle 扩展它,但随后您在其中创建另一个Rectangle,我完全不知道所有实例字段在做什么(您基本上忽略了传入的内容,有利于您的属性)

您可以做类似的事情并使用Player 作为hotbox 本身

public class Player extends Rectangle 

    enum Direction 
        UP, DOWN, LEFT, RIGHT
    

    private double velocityY = 0;
    private double velocityX = 0;
    private int speed = 2;

    public Player(int x, int y, int width, int height) 
        super(x, y, width, height);
    

    public void paint(Graphics2D g2D) 
        g2D.setColor(Color.RED);
        g2D.fill(this);
    

可运行示例...

键绑定很有趣,可以让您摸清头脑,因此我修改了您的代码以支持它们(以及上述更改),以便为您提供更好的想法。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;

public class Test 

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

    public Test() 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                JFrame frame = new JFrame();
                frame.add(new GamePanel());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            
        );
    

    public class GamePanel extends JPanel implements ActionListener 

        protected static final int SCREEN_WIDTH = 1000;
        protected static final int SCREEN_HEIGHT = 600;
        protected static final int PLAYER_WIDTH = 50;
        protected static final int PLAYER_HEIGHT = 60;
        protected static final Dimension SCREEN_SIZE = new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
        boolean falling = false;
        boolean playing = true;

        Player player1;
        Map map1;

        Image backgroundImage;
        Timer gameTimer;
        ArrayList<Map> platform = new ArrayList<>();

        public GamePanel() 
            BufferedImage img = new BufferedImage(SCREEN_WIDTH, SCREEN_HEIGHT, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = img.createGraphics();
            g2d.setColor(Color.BLUE);
            g2d.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
            g2d.dispose();
            backgroundImage = new ImageIcon(img).getImage();

            newPlayer();
            newMap();

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

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Pressed.left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Pressed.right");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Pressed.up");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Pressed.down");

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Released.left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Released.right");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Released.up");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Released.down");

            am.put("Pressed.left", new MoveAction(player1, Player.Direction.LEFT, true));
            am.put("Pressed.right", new MoveAction(player1, Player.Direction.RIGHT, true));
            am.put("Pressed.up", new MoveAction(player1, Player.Direction.UP, true));
            am.put("Pressed.down", new MoveAction(player1, Player.Direction.DOWN, true));

            am.put("Released.left", new MoveAction(player1, Player.Direction.LEFT, false));
            am.put("Released.right", new MoveAction(player1, Player.Direction.RIGHT, false));
            am.put("Released.up", new MoveAction(player1, Player.Direction.UP, false));
            am.put("Released.down", new MoveAction(player1, Player.Direction.DOWN, false));

            gameTimer = new Timer(5, new ActionListener() 
                @Override
                public void actionPerformed(ActionEvent e) 
                    player1.move();
                    repaint();
                
            );
            gameTimer.start();
        

        @Override
        public Dimension getPreferredSize() 
            return SCREEN_SIZE;
        

        @Override
        protected void paintComponent(Graphics g) 
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            draw(g2d);
            g2d.dispose();
        

        public void draw(Graphics2D g2D) 
            g2D.drawImage(backgroundImage, 0, 0, null);
            player1.paint(g2D);
            for (Map map1 : platform) 
                map1.paint(g2D);
            
        

        public void newPlayer() 
            player1 = new Player((SCREEN_WIDTH / 2) - (PLAYER_WIDTH / 2), (SCREEN_HEIGHT / 2) - (PLAYER_WIDTH / 2), PLAYER_WIDTH, PLAYER_HEIGHT);
        

        public void newMap() 
            for (int i = 50; i < 650; i += 50) 
                platform.add(new Map(i, 550, 50, 50));
            
        

        public void gameOver() 

        

        @Override
        public void actionPerformed(ActionEvent e) 

        
    

    public class MoveAction extends AbstractAction 

        private Player player;
        private Player.Direction direction;
        private boolean pressed;

        public MoveAction(Player player, Player.Direction direction, boolean pressed) 
            this.player = player;
            this.direction = direction;
            this.pressed = pressed;
        

        @Override
        public void actionPerformed(ActionEvent e) 
            if (pressed) 
                player.putDirection(direction);
             else 
                player.removeDirection(direction);
            
        

    

    public class Player extends Rectangle 

        enum Direction 
            UP, DOWN, LEFT, RIGHT
        

        private double velocityY = 0;
        private double velocityX = 0;
        private int speed = 2;

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

        public Player(int x, int y, int width, int height) 
            super(x, y, width, height);
        

        public void putDirection(Direction direction) 
            directions.add(direction);
        

        public void removeDirection(Direction direction) 
            directions.remove(direction);
        

        public void paint(Graphics2D g2D) 
            g2D.setColor(Color.RED);
            g2D.fill(this);
        

        protected boolean hasDirection(Direction direction) 
            return directions.contains(direction);
        

        public void move() 
            System.out.println(hasDirection(Direction.UP));
            if (hasDirection(Direction.LEFT) && hasDirection(Direction.RIGHT) || !hasDirection(Direction.LEFT) && !hasDirection(Direction.RIGHT)) 
                velocityX *= 0.8;
            
            if (hasDirection(Direction.LEFT) && !hasDirection(Direction.RIGHT)) 
                velocityX--;
            
            if (hasDirection(Direction.RIGHT) && !hasDirection(Direction.LEFT)) 
                velocityX++;
            
            if (velocityX > 0 && velocityX < 0.75) 
                velocityX = 0;
            
            if (velocityX < 0 && velocityX > -0.75) 
                velocityX = 0;
            

            if (velocityX > 7) 
                velocityX = 7;
            
            if (velocityX < -7) 
                velocityX = -7;
            

            if (hasDirection(Direction.UP)) 
                velocityY = -6;
            
            velocityY += 0.3;

            y += velocityY;
            x += velocityX;
        
    

    public class Map 

        int width;
        int height;
        int x;
        int y;
        Rectangle hitbox;

        public Map(int x, int y, int width, int height) 
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;

            hitbox = new Rectangle(x, y, width, height);
        

        public void paint(Graphics2D g2D) 
            g2D.setColor(Color.GRAY);
            g2D.fill(hitbox);
        

    


【讨论】:

以上是关于为啥我的平台不绘制当使用带有数组列表的 for 循环(访问多个平台)时的主要内容,如果未能解决你的问题,请参考以下文章

为啥带有pop-method(或del语句)的for循环不会遍历所有列表元素

pyqtgraph 用于绘制多个数据列表

使用带有两个列表的matplotlib绘制图形

循环,从数组中生成带有函数的按钮

为啥我要绘制的代码没有显示带有标题、xlabel 和 ylabel 的输出?

带有游标参数 (LOOP FETCH) 和 For 循环子查询的 PL/SQL 查询出错