JFrame and JPanel Both Displaying, Not Updating

Hey, everybody! I’ve been working on incorporating my tile engine into an actual menu-driven interface. I realized it didn’t make any sense that I was having my renderer component act as a JFrame when I should rather be using it as a JPanel to be contained within a JFrame, so I made some changes to both the renderer and the new program I created to act as the menu wrapper for the renderer.

What I wanted to do was have the JFrame (VastGame) run and display some menu options for the player. Right now, it just has a little message and allows the player to press Enter to switch to the renderer. The renderer was working perfectly beforehand, so I think I just messed up changing things around and making the renderer a JPanel instead of a JFrame, which it used to be. Upon pressing Enter, the message stays there rather than disappears but shows the renderer at a standstill, flickering in the background. I suppose this must mean they both run at the same time, without the renderer updating itself, so if anybody could offer some advice or assistance in how I could accomplish what I sought out to do, which is switch control between the menu display within the JFrame and the renderer’s display through the JPanel, I would be much appreciative. :]

Here is the code for both relevant classes:

The new menu class and JFrame, VastGame:


/*
 * VAST GAME EXECUTING CLASS (Version 0.1)
 *
 * The purpose of this class will be to run the actual game manager that controls all of VAST's constituents. For
 * this version, it will simply show a simple title screen, allow the user to create a level of his or her choice to
 * render, and then allow the player to explore the level. The player may then break any block within the level of his
 * or her choosing. If the player wishes to exit, they may press ESCAPE, at which point a prompt will verify that the
 * player wishes to terminate. Version 1.0 does not save any data nor contain items or enemies.
 */
 
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.JFrame;
import javax.swing.*;
import java.util.Random;
import java.awt.Color;
 
public class VastGame extends JFrame
{
	// level renderer object to actually display the level
	private static LevelRenderer myRenderer;
	
	// level object to store the needed tiles and methods
	private Level myLevel;
	
	// screen object
    private Screen s;
	
	// back buffer
    private static BufferStrategy buffer;
	
	// boolean to keep track of the game's running
	private boolean endGame = false;
	
	// Graphics object for the buffer strategy
	private Graphics graphics;
	
	// int to represent which layer of the menu the player is in
	private int menuLayer = 0;
	
	// CONSTRUCTOR
	public VastGame()
	{
		setPreferredSize(new Dimension(1280, 768));
        setIgnoreRepaint( true );
        setUndecorated( true );

        setFocusable(true);
        requestFocus();
        
        setResizable(false);
        
        addKeyListener( new KeyAdapter() 
        {
            public void keyPressed(KeyEvent e)
            { 
                processKey(e);  
            }
            
            public void keyReleased(KeyEvent e)
            {
                processRelease(e);
            }
        });
	}
	
	// execution of VastGame JFrame
	public void run(DisplayMode dm)
	{
		setBackground(Color.BLACK);
		s = new Screen();
        s.setFullScreen(dm, this);
        
        this.createBufferStrategy( 2 );
        buffer = this.getBufferStrategy();
		myRenderer = new LevelRenderer(buffer);
		
		while (!endGame)
        {
            do
            {
                do
                {
                    try
                    {   
                        update();
                        render();
                    }
                    catch (Exception ex) 
                    { 
                        System.err.println("Game Update Error: " + ex);
                    }
                    
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (Exception ex)
                    {
                        System.out.println("Can't sleep!");
                    }
                } while (buffer.contentsRestored());
                
                buffer.show();
                
            } while (buffer.contentsLost());
        }
		
		s.restoreScreen();
	}
	
	// updating method
	public void update()
	{
		// get new draw graphics
        graphics = buffer.getDrawGraphics();
	}
	
	// rendering method for the menus
	public void render()
	{
		switch (menuLayer)
		{
			// title screen with logo and "click to continue"
			case 0:
				// display frames per second...
				graphics.setFont( new Font( "Courier New", Font.PLAIN, 28 ) );
				graphics.setColor( Color.GREEN );
				graphics.drawString( "Welcome to the game!", 20, 20 );
				break;
				
			// menu layer with "create a level" and "exit"
			case 1:
			
				break;
				
			// menu layer with all of the level types
			case 2:
			
				break;
				
			// menu layer with "loading"
			case 3:
			
				break;
		}
	}
	
	// process key input
	private void processKey(KeyEvent e)
	{
		int keyCode = e.getKeyCode();
		
		// termination key
        if (keyCode == KeyEvent.VK_ESCAPE)
        {
            endGame = true;
        }
		
		// start renderer
		if (keyCode == KeyEvent.VK_ENTER)
		{
			// add renderer panel to the frame
			this.getContentPane().add(myRenderer);
		
			// run the renderer
			myRenderer.run(new DisplayMode(1280, 768, 32, DisplayMode.REFRESH_RATE_UNKNOWN));
		}
	}
	
	// process release of key
	private void processRelease(KeyEvent e)
	{
	
	}
	
	// restore screen of the game's JFrame
	public void restoreScreen()
	{
		s.restoreScreen();
	}
	
	// point of execution
	public static void main(String args[])
	{
		VastGame myGame = new VastGame();
		
		// display mode passed to the renderer
		DisplayMode dm = new DisplayMode(1280, 768, 32, DisplayMode.REFRESH_RATE_UNKNOWN);
		
		// run the game's code (basic menu system to lead to the renderer)
		myGame.run(dm);
		
		// restore screen when done with
		myGame.restoreScreen();
	}
}

And the renderer’s JPanel code:


/* This class's job is to manage a Player and Level object and call their render and update routines. */
 
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.JFrame;
import javax.swing.*;
import java.util.Random;
import java.awt.Color;

public class LevelRenderer extends JPanel
{   
    //
    // CONSTANTS
    //
    
    private final int TILE_SIZE = 32;
    private final int SCREEN_WIDTH = 1280;
    private final int SCREEN_HEIGHT = 768;
    private final int PLAYER_HEIGHT = 28;
    private final int PLAYER_WIDTH = 14;
    
    //
    // END OF CONSTANTS
    //
    
    // back buffer
    private BufferStrategy buffer;
    
    // character object
    private Player myPlayer;
    
    // level object
    private Level myLevel;
    
    // screen object
    private Screen s;
    
    // Graphics object for the buffer strategy
    private Graphics graphics;
    
    // boolean to determine when to end the game
    private boolean endGame;
    
    // Variables for counting frames per second
    private int fps = 0;
    private int frames = 0;
    private long totalTime = 0;
    private long curTime = System.currentTimeMillis();
    private long lastTime = curTime;
    
    // thread sleep count variables
    private long now = 0;
    private long rest = now;
    
    // CONSTRUCTOR
    public LevelRenderer(BufferStrategy bs)
    {
        setPreferredSize(new Dimension(1280, 768));
        setIgnoreRepaint( true );

        setFocusable(true);
        requestFocus();
		
		graphics = bs.getDrawGraphics();
        
        addKeyListener( new KeyAdapter() 
        {
            public void keyPressed(KeyEvent e)
            { 
                processKey(e);  
            }
            
            public void keyReleased(KeyEvent e)
            {
                processRelease(e);
            }
        });
        
        myPlayer = new Player();
        myLevel = new Level("obstaclemap");
        
        endGame = false;
    }
    
    // method to simply load an image from a path
    public static BufferedImage loadImage(String ref)
    {
        BufferedImage bimg = null;
           
        try
        {
           bimg = ImageIO.read(new File(ref));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
       
        return bimg;
    }
    
    // Run method for class
    public void run(DisplayMode dm)
	{	
        setBackground(Color.WHITE);

        while (!endGame)
        {
            update();
			render();
        }
	} 
    
    // method to update player and level
    private void update()
    {
        // count Frames per second...
        lastTime = curTime;
        curTime = System.currentTimeMillis();
        totalTime += curTime - lastTime;
        
        if( totalTime > 1000 ) 
        {
            totalTime -= 1000;
            fps = frames;
            frames = 0;
        } 
        ++frames;
        
        // get first reference to calculate sleep time
        now = System.currentTimeMillis();
        
        // edit/draw player and level
        myPlayer.animatePlayer();
        myLevel.updateOffsets();
    }   
    
    // method to render player, level, and FPS
    private void render()
    {
        // draw level and player
        myLevel.drawLevel(graphics, 0, 0);
        myPlayer.drawPlayer(graphics, (SCREEN_WIDTH / 2) - PLAYER_WIDTH / 2, (SCREEN_HEIGHT / 2) - PLAYER_HEIGHT / 2);
        myLevel.drawCollision(graphics);
        
        // display frames per second...
        graphics.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
        graphics.setColor( Color.GREEN );
        graphics.drawString( String.format( "FPS: %s", fps ), 20, 20 );
        
        // calculate sleep time
        rest = 1000 / 60 - (System.currentTimeMillis() - now);
                        
        if (rest < 0)
        {
            rest = 0;
        }
        
        // dispose graphics
        graphics.dispose();
    }
    
    // method to handle inputs and adjust the player accordingly
    public void processKey(KeyEvent e)
    {
        int keyCode = e.getKeyCode();
        boolean moved = false;
        int xDisplace, yDisplace;
        
        // termination key
        if (keyCode == KeyEvent.VK_ESCAPE)
        {
            endGame = true;
        }
        
        // 0 - up
        // 1 - left
        // 2 - right
        // 3 - down
        // 4 - jump
        
        switch (keyCode)
        {
            case KeyEvent.VK_UP:
                myPlayer.updatePlayer(0);
                myLevel.updateLevel(0);
                break;
            case KeyEvent.VK_LEFT:
                myPlayer.updatePlayer(1);
                myLevel.updateLevel(1);
                break;
            case KeyEvent.VK_RIGHT:
                myPlayer.updatePlayer(2);
                myLevel.updateLevel(2);
                break;
            case KeyEvent.VK_DOWN:
                myPlayer.updatePlayer(3);
                myLevel.updateLevel(3);
                break;
            case KeyEvent.VK_SPACE:
                myPlayer.updatePlayer(4);
                break;
        }
    }
    
    // method to handle inputs and adjust the player accordingly
    public void processRelease(KeyEvent e)
    {
        int keyCode = e.getKeyCode();
        boolean moved = false;
        int xDisplace, yDisplace;
        
        // 0 - up
        // 5 - left
        // 6 - right
        // 3 - down
        // 4 - jump
        
        switch (keyCode)
        {
            case KeyEvent.VK_UP:
                myPlayer.updatePlayer(0);
                myLevel.updateLevel(5);
                break;
            case KeyEvent.VK_LEFT:
                myPlayer.updatePlayer(5);
                myLevel.updateLevel(6);
                break;
            case KeyEvent.VK_RIGHT:
                myPlayer.updatePlayer(6);
                myLevel.updateLevel(7);
                break;
            case KeyEvent.VK_DOWN:
                myPlayer.updatePlayer(3);
                myLevel.updateLevel(8);
                break;
            case KeyEvent.VK_SPACE:
                myPlayer.updatePlayer(4);
                break;
        }
    }
}

Thank you guys for your help! :]

Best regards,
Colton

Couple questions:
#1. Why does LevelRenderer extend JPanel?
#2. There is a while loop inside LevelRenderer’s run method that does nothing but update and render. This method should return back to processKey(KeyEvent) so VastGame can call buffer.show()

There are too many other things wrong in your code but lets deal with those two for now :slight_smile:

ra4king,

Thank you for your reply!

I extended LevelRenderer to be a JPanel because it was my understanding that it could become a component of a JFrame and so that I could have multiple classes like it for different parts of my game (overworld, level renderer, menu, etc.). Initially, I looked into implementing it as a Canvas and read that JPanels are much more effective.

As for the buffer.show() problem, I just spent a few minutes fixing that and will show the code below. It now lets me exit the game with ESCAPE like I desired previously, but the renderer still does not update at all and stays at 0 FPS.

Here is the updated class code. Since you said there are many problems with it, I would also like to know these when the time is right, for I want to make sure I am doing everything properly. :]

VastGame:


/*
 * VAST GAME EXECUTING CLASS (Version 0.1)
 *
 * The purpose of this class will be to run the actual game manager that controls all of VAST's constituents. For
 * this version, it will simply show a simple title screen, allow the user to create a level of his or her choice to
 * render, and then allow the player to explore the level. The player may then break any block within the level of his
 * or her choosing. If the player wishes to exit, they may press ESCAPE, at which point a prompt will verify that the
 * player wishes to terminate. Version 1.0 does not save any data nor contain items or enemies.
 */
 
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.JFrame;
import javax.swing.*;
import java.util.Random;
import java.awt.Color;
 
public class VastGame extends JFrame
{
	// level renderer object to actually display the level
	private static LevelRenderer myRenderer;
	
	// level object to store the needed tiles and methods
	private Level myLevel;
	
	// screen object
    private Screen s;
	
	// back buffer
    private static BufferStrategy buffer;
	
	// boolean to keep track of the game's running
	private boolean endGame = false;
	
	// Graphics object for the buffer strategy
	private Graphics graphics;
	
	// int to represent which layer of the menu the player is in
	private int menuLayer = 0;
	
	// boolean that determines whether the renderer is activated
	private boolean rendererOn = false;
	
	// CONSTRUCTOR
	public VastGame()
	{
		setPreferredSize(new Dimension(1280, 768));
        setIgnoreRepaint( true );
        setUndecorated( true );

        setFocusable(true);
        requestFocus();
        
        setResizable(false);
        
        addKeyListener( new KeyAdapter() 
        {
            public void keyPressed(KeyEvent e)
            { 
                processKey(e);  
            }
            
            public void keyReleased(KeyEvent e)
            {
                processRelease(e);
            }
        });
	}
	
	// execution of VastGame JFrame
	public void run(DisplayMode dm)
	{	
		setBackground(Color.BLACK);
		s = new Screen();
        s.setFullScreen(dm, this);
        
        this.createBufferStrategy( 2 );
        buffer = this.getBufferStrategy();
		myRenderer = new LevelRenderer(buffer);
		
		while (!endGame)
        {
            do
            {
                do
                {
                    try
                    {   
						if (!rendererOn)
						{
							update();
							render();
						}
						else
						{
							myRenderer.update();
							myRenderer.render();
						}
                    }
                    catch (Exception ex) 
                    { 
                        System.err.println("Game Update Error: " + ex);
                    }
                    
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (Exception ex)
                    {
                        System.out.println("Can't sleep!");
                    }
                } while (buffer.contentsRestored());
                
                buffer.show();
                
            } while (buffer.contentsLost());
        }
		
		s.restoreScreen();
	}
	
	// updating method
	public void update()
	{
		// get new draw graphics
        graphics = buffer.getDrawGraphics();
	}
	
	// rendering method for the menus
	public void render()
	{
		switch (menuLayer)
		{
			// title screen with logo and "click to continue"
			case 0:
				// display simple message for now
				graphics.setFont( new Font( "Courier New", Font.PLAIN, 28 ) );
				graphics.setColor( Color.GREEN );
				graphics.drawString( "Welcome to the game!", 20, 20 );
				break;
				
			// menu layer with "create a level" and "exit"
			case 1:
			
				break;
				
			// menu layer with all of the level types
			case 2:
			
				break;
				
			// menu layer with "loading"
			case 3:
			
				break;
		}
	}
	
	// process key input
	private void processKey(KeyEvent e)
	{
		int keyCode = e.getKeyCode();
		
		// termination key
        if (keyCode == KeyEvent.VK_ESCAPE)
        {
            endGame = true;
        }
		
		// start renderer
		if (keyCode == KeyEvent.VK_ENTER)
		{
			// add renderer panel to the frame
			this.getContentPane().add(myRenderer);
			rendererOn = true;
		}
	}
	
	// process release of key
	private void processRelease(KeyEvent e)
	{
	
	}
	
	// restore screen of the game's JFrame
	public void restoreScreen()
	{
		s.restoreScreen();
	}
	
	// point of execution
	public static void main(String args[])
	{
		VastGame myGame = new VastGame();
		
		// display mode passed to the renderer
		DisplayMode dm = new DisplayMode(1280, 768, 32, DisplayMode.REFRESH_RATE_UNKNOWN);
		
		// run the game's code (basic menu system to lead to the renderer)
		myGame.run(dm);
		
		// restore screen when done with
		myGame.restoreScreen();
	}
}

and LevelRenderer:


/* This class's job is to manage a Player and Level object and call their render and update routines. */
 
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.JFrame;
import javax.swing.*;
import java.util.Random;
import java.awt.Color;

public class LevelRenderer extends JPanel
{   
    //
    // CONSTANTS
    //
    
    private final int TILE_SIZE = 32;
    private final int SCREEN_WIDTH = 1280;
    private final int SCREEN_HEIGHT = 768;
    private final int PLAYER_HEIGHT = 28;
    private final int PLAYER_WIDTH = 14;
    
    //
    // END OF CONSTANTS
    //
    
    // back buffer
    private BufferStrategy buffer;
    
    // character object
    private Player myPlayer;
    
    // level object
    private Level myLevel;
    
    // screen object
    private Screen s;
    
    // Graphics object for the buffer strategy
    private Graphics graphics;
    
    // boolean to determine when to end the game
    private boolean endGame;
    
    // Variables for counting frames per second
    private int fps = 0;
    private int frames = 0;
    private long totalTime = 0;
    private long curTime = System.currentTimeMillis();
    private long lastTime = curTime;
    
    // thread sleep count variables
    private long now = 0;
    private long rest = now;
    
    // CONSTRUCTOR
    public LevelRenderer(BufferStrategy bs)
    {
        setPreferredSize(new Dimension(1280, 768));
        setIgnoreRepaint( true );

        setFocusable(true);
        requestFocus();
		
		graphics = bs.getDrawGraphics();
        
        addKeyListener( new KeyAdapter() 
        {
            public void keyPressed(KeyEvent e)
            { 
                processKey(e);  
            }
            
            public void keyReleased(KeyEvent e)
            {
                processRelease(e);
            }
        });
        
        myPlayer = new Player();
        myLevel = new Level("obstaclemap");
        
        endGame = false;
    }
    
    // method to simply load an image from a path
    public static BufferedImage loadImage(String ref)
    {
        BufferedImage bimg = null;
           
        try
        {
           bimg = ImageIO.read(new File(ref));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
       
        return bimg;
    }
    
    // method to update player and level
    public void update()
    {
        // count Frames per second...
        lastTime = curTime;
        curTime = System.currentTimeMillis();
        totalTime += curTime - lastTime;
        
        if( totalTime > 1000 ) 
        {
            totalTime -= 1000;
            fps = frames;
            frames = 0;
        } 
        ++frames;
        
        // get first reference to calculate sleep time
        now = System.currentTimeMillis();
        
        // edit/draw player and level
        myPlayer.animatePlayer();
        myLevel.updateOffsets();
    }   
    
    // method to render player, level, and FPS
    public void render()
    {
        // draw level and player
        myLevel.drawLevel(graphics, 0, 0);
        myPlayer.drawPlayer(graphics, (SCREEN_WIDTH / 2) - PLAYER_WIDTH / 2, (SCREEN_HEIGHT / 2) - PLAYER_HEIGHT / 2);
        myLevel.drawCollision(graphics);
        
        // display frames per second...
        graphics.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
        graphics.setColor( Color.GREEN );
        graphics.drawString( String.format( "FPS: %s", fps ), 20, 20 );
        
        // calculate sleep time
        rest = 1000 / 60 - (System.currentTimeMillis() - now);
                        
        if (rest < 0)
        {
            rest = 0;
        }
        
        // dispose graphics
        graphics.dispose();
    }
    
    // method to handle inputs and adjust the player accordingly
    public void processKey(KeyEvent e)
    {
        int keyCode = e.getKeyCode();
        boolean moved = false;
        int xDisplace, yDisplace;
        
        // termination key
        if (keyCode == KeyEvent.VK_ESCAPE)
        {
            endGame = true;
        }
        
        // 0 - up
        // 1 - left
        // 2 - right
        // 3 - down
        // 4 - jump
        
        switch (keyCode)
        {
            case KeyEvent.VK_UP:
                myPlayer.updatePlayer(0);
                myLevel.updateLevel(0);
                break;
            case KeyEvent.VK_LEFT:
                myPlayer.updatePlayer(1);
                myLevel.updateLevel(1);
                break;
            case KeyEvent.VK_RIGHT:
                myPlayer.updatePlayer(2);
                myLevel.updateLevel(2);
                break;
            case KeyEvent.VK_DOWN:
                myPlayer.updatePlayer(3);
                myLevel.updateLevel(3);
                break;
            case KeyEvent.VK_SPACE:
                myPlayer.updatePlayer(4);
                break;
        }
    }
    
    // method to handle inputs and adjust the player accordingly
    public void processRelease(KeyEvent e)
    {
        int keyCode = e.getKeyCode();
        boolean moved = false;
        int xDisplace, yDisplace;
        
        // 0 - up
        // 5 - left
        // 6 - right
        // 3 - down
        // 4 - jump
        
        switch (keyCode)
        {
            case KeyEvent.VK_UP:
                myPlayer.updatePlayer(0);
                myLevel.updateLevel(5);
                break;
            case KeyEvent.VK_LEFT:
                myPlayer.updatePlayer(5);
                myLevel.updateLevel(6);
                break;
            case KeyEvent.VK_RIGHT:
                myPlayer.updatePlayer(6);
                myLevel.updateLevel(7);
                break;
            case KeyEvent.VK_DOWN:
                myPlayer.updatePlayer(3);
                myLevel.updateLevel(8);
                break;
            case KeyEvent.VK_SPACE:
                myPlayer.updatePlayer(4);
                break;
        }
    }
}

Thanks again!

Aha, the problem is that you are supposed to get a new Graphics object every frame. Move the line that says “graphics = bs.getDrawGraphics();” to the render() method in LevelRenderer.

EDIT: Also try using a debugger to run through your code line by line.

Ah, brilliant and thank you! The transition is seamless now. The only problem is that my renderer won’t take any input now :stuck_out_tongue: Is there an easy fix to this?

Also, I do from time to time go into my debugger in Netbeans and test some things out, as well as profile my code, but I suppose I should do so more often. For some reason, I’m very comfortable doing things through the command line :stuck_out_tongue: I’m sure I’ll get used to and become favorable toward an IDE eventually.

Thanks for your help, ra4king!

EDIT: I was able to figure it out :] I just put the processKey methods from LevelRenderer into those in VastGame. If there is any more advice you’d be willing to share in regard to how I can refactor or improve my code, though, I’d be very thankful.

Eclipse FTW! :smiley:

EDIT: Oh and there is no point to extend JPanel since you are not adding the JPanel to the JFrame and you are getting the BufferStrategy from the JFrame.

I used Eclipse in the past and was happy with it, as well. There was something about the aesthetics with Netbeans that appealed to me more, however, and the fact that it included the Javadoc integration so seamlessly, but I’m sure there’s an Eclipse plugin that lets you do the same thing.

I hadn’t realized through all the refactoring that I’d completely disregarded the getContentPane() call I’d used previously which had made me think I needed one. So what you’re essentially saying is I could make LevelRenderer a class that simply interacts with and renders to the BufferStrategy? So I wouldn’t in this sense ever really need a JPanel, just the BufferStrategy access, making my life much easier. If this is the case, then in which situation would I ever need a JPanel? I appreciate all your help. :]

Colton

Excuse me jumping straight into here, but I’ve had use for JFrames when I made a map editor. That way I could have one Canvas which my I drew the game at (I was using OpenGL, with Java2D you can just use a JFrame there), one for a tile chooser and a last one for a menu at the bottom of the screen. It’s convenient because you can easily change the layout of the components and get automatic resizing/interaction of everything through a layout manager. BorderLayout was awesome for this.

lol theagentd, You’re more than welcome to join in wherever you want. You’ve helped me a lot in the little time I’ve been here already. On top of that, I want to hear everything everyone wants or has to say if it concerns me and Java game development.

The multi-component interaction aspect does make sense. Once I expand my current game build to incorporate a more robust interface, I’ll surely end up experimenting with and experiencing these intricacies and layouts. For some aspects of my game, there will end up being parts that will require the kind of complexity you might find in something like a map editor, like for my eventual alchemy system. This whole process has been something of an adventure for me, because my experience with programming has been more on traditional programming aspects rather than GUI and event-based programming. That, and it’s been encouraging me to learn more about data structures. Everything I’ve been intending to accomplish has been mentally conceived without regard necessarily for the implementation details; I figure with tutorials, reading, API documentation, and kind people such as those I may find here ( O:] ), I can find the way. Thanks for the input, theagentd!

Colton