有没有办法从 class 外部在 JPanel 对象上绘画?
Is there a way to paint on a JPanel object from ouside it's class?
我搜索并发现了一些措辞相似的问题,但没有一个适用于我的情况,所以我开始了。
我正在尝试制作一款具有不同级别的游戏,每个级别的玩法都完全不同。
最初,我的代码看起来像这样并且运行良好:
public class Life extends JPanel{
private Story story;
public Life(){
story = new Story(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
story.render(g)
public void terminate(){
story.terminate();
System.out.println("Terminated");
}
public static void main(String[] args){
final JFrame frame = new JFrame("Life");
final Life life = new Life();
frame.add(life);
}
}
public class Story {
private int phase;
private Life life;
public Story(Life life){
this.life = life;
phase = 0;
}
public void render(Graphics g){
if(phase == 0) levelOneRender(g);
if(phase == 1) levelTwoRender(g);
}
}
我担心我会在每个游戏滴答时浪费时间检查我处于哪个阶段。由于我计划有 20 个以上的阶段,代码会很快变得低效。
所以我有了一个想法,只需将 JPanel 中的图形对象从我的生活对象传递到我的故事对象,并为每个阶段在不同的 class 中绘制 Jpanel,如下所示:
public class Life extends JPanel{
public Life(){
story = new Story(this);
}
public static void main(String[] args){
final JFrame frame = new JFrame("Life");
final Life life = new Life();
}
}
public class Story {
private int phase;
private Intro intro;
private Life life;
public Story(Life life){
this.life = life;
phase = 0;
intro = new Intro(this);
}
public void nextPhase(){
this.phase++;
}
public Life getLife() {
return this.life;
}
}
public class Intro {
private static final int DELAY = 100; // in milliseconds, so 10 ticks per second
private Timer timer;
private Story story;
private Graphics g;
private int counter;
public Intro(Story story) {
this.story = story;
this.g = story.getLife().getGraphics();
this.counter = 0;
timer = new Timer(DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
tick();
story.repaint();
}
});
timer.start();
}
public void tick(){
if(counter <= 40){
terminate();
}
counter++;
render();
}
public void render(){
story.getLife().paint(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.draw(new Rectangle(0,0,10,10));
}
public void terminate(){
timer.stop();
story.nextPhase();
}
}
不幸的是,这不起作用,因为 story.getLife().paint(g);在 class Intro 抛出一个 nullPointerException,当我 运行 它。我很确定这不是我尝试这样做的唯一问题。
是否有正确的方法来实现我的目的?
非常感谢您抽出宝贵时间。任何见解将不胜感激。
public void render(Graphics g){
if(phase == 0) levelOneRender(g);
if(phase == 1) levelTwoRender(g);
}
这并没有你想象的那么严重。你现在拥有的很好。但是这些检查是可以避免的(正如你所要求的)。
与其在单独的方法中处理每个级别的绘画,不如在单独的对象中处理它们:
public bstract class Level {
public abstract void paint(Graphics g);
}
public final class LevelOne extends Level {
public void paint(Graphics g) {
//...
}
}
public final class LevelTwo extends Level {
public void paint(Graphics g) {
//...
}
}
这样,您无需检查 int
值来查看要绘制哪个渲染,只需切换 Level
值即可渲染新关卡:
Level one = new LevelOne();
Level two = new LevelTwo();
Level currentLevel = one;
public void paintComponent(Graphics g) {
super.paintComponent(g);
currentLevel.paint(g);
}
只需切换level
的值即可呈现不同的层次
我搜索并发现了一些措辞相似的问题,但没有一个适用于我的情况,所以我开始了。
我正在尝试制作一款具有不同级别的游戏,每个级别的玩法都完全不同。
最初,我的代码看起来像这样并且运行良好:
public class Life extends JPanel{
private Story story;
public Life(){
story = new Story(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
story.render(g)
public void terminate(){
story.terminate();
System.out.println("Terminated");
}
public static void main(String[] args){
final JFrame frame = new JFrame("Life");
final Life life = new Life();
frame.add(life);
}
}
public class Story {
private int phase;
private Life life;
public Story(Life life){
this.life = life;
phase = 0;
}
public void render(Graphics g){
if(phase == 0) levelOneRender(g);
if(phase == 1) levelTwoRender(g);
}
}
我担心我会在每个游戏滴答时浪费时间检查我处于哪个阶段。由于我计划有 20 个以上的阶段,代码会很快变得低效。
所以我有了一个想法,只需将 JPanel 中的图形对象从我的生活对象传递到我的故事对象,并为每个阶段在不同的 class 中绘制 Jpanel,如下所示:
public class Life extends JPanel{
public Life(){
story = new Story(this);
}
public static void main(String[] args){
final JFrame frame = new JFrame("Life");
final Life life = new Life();
}
}
public class Story {
private int phase;
private Intro intro;
private Life life;
public Story(Life life){
this.life = life;
phase = 0;
intro = new Intro(this);
}
public void nextPhase(){
this.phase++;
}
public Life getLife() {
return this.life;
}
}
public class Intro {
private static final int DELAY = 100; // in milliseconds, so 10 ticks per second
private Timer timer;
private Story story;
private Graphics g;
private int counter;
public Intro(Story story) {
this.story = story;
this.g = story.getLife().getGraphics();
this.counter = 0;
timer = new Timer(DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
tick();
story.repaint();
}
});
timer.start();
}
public void tick(){
if(counter <= 40){
terminate();
}
counter++;
render();
}
public void render(){
story.getLife().paint(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.draw(new Rectangle(0,0,10,10));
}
public void terminate(){
timer.stop();
story.nextPhase();
}
}
不幸的是,这不起作用,因为 story.getLife().paint(g);在 class Intro 抛出一个 nullPointerException,当我 运行 它。我很确定这不是我尝试这样做的唯一问题。
是否有正确的方法来实现我的目的?
非常感谢您抽出宝贵时间。任何见解将不胜感激。
public void render(Graphics g){
if(phase == 0) levelOneRender(g);
if(phase == 1) levelTwoRender(g);
}
这并没有你想象的那么严重。你现在拥有的很好。但是这些检查是可以避免的(正如你所要求的)。
与其在单独的方法中处理每个级别的绘画,不如在单独的对象中处理它们:
public bstract class Level {
public abstract void paint(Graphics g);
}
public final class LevelOne extends Level {
public void paint(Graphics g) {
//...
}
}
public final class LevelTwo extends Level {
public void paint(Graphics g) {
//...
}
}
这样,您无需检查 int
值来查看要绘制哪个渲染,只需切换 Level
值即可渲染新关卡:
Level one = new LevelOne();
Level two = new LevelTwo();
Level currentLevel = one;
public void paintComponent(Graphics g) {
super.paintComponent(g);
currentLevel.paint(g);
}
只需切换level
的值即可呈现不同的层次