Java2DGame rendering NPC's

Started by
10 comments, last by Nicholas Kong 10 years, 4 months ago

Hey everyone, I'm working on a 2D java game at the moment and have a graphics object created in my start class. I want to be able to draw my NPC's from their own threads(seperate class) but can't load the g.drawImage class from a different class. Any suggestions on how I can transfer the graphics object to the NPC threads? Thanks in advance!

Advertisement

You didn't give me an awful lot to work with, so I'm making some assumptions here. First, since you reference Graphics, I'm assuming your game is packaged as a Runnable object. Second, it sounds like you know how to use Graphics and are just having trouble getting your NPCs to paint to the same Graphics object.

First, make an abstract class which will be the parent of all NPCs, and give it an abstract method which accepts a Graphics object as an argument, like so:


public abstract class NPC {
    public abstract void render(Graphics g);
}

Then, have every NPC class extend the new class, for example:


public class Villager extends NPC {
    public void render(Graphics g){
        //rendering code goes here
    }
}

Then, in your game's central class, make an ArrayList of all the NPCs and iterate over it in your paint() method, like this:


public class JavaGame extends Runnable {
    public List<NPC> npcs = new ArrayList<NPC>(); //list of all NPCs currently in the game

    public void paint(Graphics g){
        //other rendering code goes here (any background images, UI pieces, etc.)
        for(NPC npc : npcs) npc.render(g); //loop through the list of NPCs and render each one
    }
}

My website: Brass Watch Games

Come check out Shipyard, my first real game project (Very WIP): Game Website Development Journal

Shipyard is a 2D turn-based strategy with a sci-fi theme, in which you build ships from individual parts rather than being given a selection of predefined models.

Sorry for my lack of immediate information. I'm a self taught programmer and I've only been doing this for maybe 6 months now. I lack proper terminology. :/

I think I understand most of what you're saying Nerdboy, but I want to be able to have multiple of the same NPC on screen at once, if I render 2 NPC's of the same name won't it only display 1 one of them, or both of them at the same position? I was planning on putting g.drawImage(variables..) in each one of the NPC threads, so they would run independently and I wouldn't run into the problem of them displaying in the same position. Would I still run into this problem if I were to use what you suggested and spawn 2 NPC's of the same type? Another question though, would it be better to use a paint method? Currently I have a BufferStrategy and I'm saying "bs.show" to display Images and I honestly barely know what I'm doing when it comes to graphic displays XD please forgive my lack of knowledge.

First of all, if every villager has its own Thread, something's not right. The game should have a single thread, and everything else should be called by a loop enclosing that thread. Here's an example of a typical run method:


public void run(){
while(true){ //An infinite loop
    if(quitGame){ //Make a boolean called quitGame and set it to false. When you want to quit, set it to true and the thread will stop running.
        break;
        onQuitGame(); //do whatever needs to be done after the game closes
    }
    
    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
			
    for(NPC npc : npcs) npc.update();//Put a method called "update" in your NPC class and override it for any subclasses you have.
                                     //This is where the NPC should do things like change its position, interact with the world, etc.

    repaint(); //goes through some Java wizardry, eventually calling the paint(Graphics g) method.
    try {
	Thread.sleep(1000 / 60); //Sleep for 1 60th of a second, giving a frame rate of 60FPS
    } catch(InterruptedException e) {}
			
	Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    }
}
}

This way, there is a single Thread which updates the entire game. Every NPC should have an update() method which, when called, changes their position and makes them interact with the world.

What you're talking about with the whole "multiple of the same NPC on screen at once" thing is the core concept of object-oriented programming. In Java, a Class is the type of object that defines what it is capable of and how it works. Then, you can have as many instances of that class, called Objects, as you want. Think of it like the classes of battleships: you might have three ships of the same class, all built from the same design, but each one is a separate boat with its own crew, cargo, weapons, etc.

The way it applies to your game is that you might have several individual villagers, each one an Object of the Class "Villager." To add them to your game, you would do this:


public class JavaGame implements Runnable {
    public List<NPC> npcs = new ArrayList<NPC>(); //list of all NPCs currently in the game

    public static void main(String[] args){
        JavaGame game = new JavaGame();
        game.npcs.add(new Villager(xPosition, yPosition, etc)); //Add one villager
        game.npcs.add(new Villager(xPosition, yPosition, etc)); //Add another villager
        game.npcs.add(new Villager(xPosition, yPosition, etc)); //Add a third villager
        game.run(); //Call the run method described above
    }

    public void paint(Graphics g){
        //other rendering code goes here (any background images, UI pieces, etc.)
        for(NPC npc : npcs) npc.render(g); //loop through the list of NPCs and render each one
    }
}

Now you have three separate villagers, and if you have a different xPosition and yPosition each time you spawn them, they'll be in different places. You could, in theory, add as many as you want. Instead of copying the add() code over and over, you could use a for loop and a random number generator to place them randomly on the screen.

My website: Brass Watch Games

Come check out Shipyard, my first real game project (Very WIP): Game Website Development Journal

Shipyard is a 2D turn-based strategy with a sci-fi theme, in which you build ships from individual parts rather than being given a selection of predefined models.

I just want to start off by saying thank you for your help on this. I've been developing this game engine for about 2 weeks now using threads for each character of the game. I was under the impression that by having a multitude of threads I would be able to run the AI's of each character more easily. Each NPC currently has a while loop based off of it's HP level, if it equals, or is below 0, the thread stops. I don't understand though, why not use threads rather than calling an update to each NPC? This might just be me trying to keep from rewritting this engine, but still, honest question.

I just want to start off by saying thank you for your help on this. I've been developing this game engine for about 2 weeks now using threads for each character of the game. I was under the impression that by having a multitude of threads I would be able to run the AI's of each character more easily. Each NPC currently has a while loop based off of it's HP level, if it equals, or is below 0, the thread stops. I don't understand though, why not use threads rather than calling an update to each NPC? This might just be me trying to keep from rewritting this engine, but still, honest question.

First, resources. Every thread is a separate loop that the computer has to think about, requiring processor cycles and such. It's more efficient to have one thread that loops through calculations than to have a separate thread for every object. It also keeps the objects in sync with each other, as giving each one a separate thread might cause some objects to lag behind others if there gets to be too great a load on the processor. Also, if an NPC or other object needs to be removed (for example, killing an enemy), the thread will continue to eat processor power unless it is properly closed, even if it isn't in use anymore.

Really, the only time you'd need more than one thread if if you wanted one thread for calculations and one for graphics, and that's beyond my expertise.

My website: Brass Watch Games

Come check out Shipyard, my first real game project (Very WIP): Game Website Development Journal

Shipyard is a 2D turn-based strategy with a sci-fi theme, in which you build ships from individual parts rather than being given a selection of predefined models.

I can see how it could be a strain on a processor if too many of one object were to be created. Also I didn't think about synchronization being a problem in the future. Thanks a lot of your input :)


public void run(){
while(true){ //An infinite loop

if(quitGame){ //Make a boolean called quitGame and set it to false. When you want to quit, set it to true and the thread will stop running.

break;

onQuitGame(); //do whatever needs to be done after the game closes

}



Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

            

for(NPC npc : npcs) npc.update();//Put a method called "update" in your NPC class and override it for any subclasses you have.

//This is where the NPC should do things like change its position, interact with the world, etc.



repaint(); //goes through some Java wizardry, eventually calling the paint(Graphics g) method.

try {

    Thread.sleep(1000 / 60); //Sleep for 1 60th of a second, giving a frame rate of 60FPS

} catch(InterruptedException e) {}

            

    Thread.currentThread().setPriority(Thread.MAX_PRIORITY);

}

}
}

There are a few problems with that piece of code. "onQuitGame()" is unreachable (loop breaks right before it gets called). You could move the condition to the while so you can do:


while(didntQuitGame)

{
// do stuff.

}
onQuitStuff();

Making the "onQuit" method reachable and the ending condition more obvious (if the didntQuitGame value gets set by another thread, then it should be volatile so the thread evaluates its finish condition with the most recent value of didntQuitGame, lest the VM optimize out the condition if the thread never sees it change).

Then the sleep call. What you're doing there is sleeping for 16 milliseconds, yes, that will make the loop run 60 times per second IF it had nothing else to do. Your frame time will be 16ms + whatever time it takes to do everything else in the game. Say that npc updating + repainting takes 4ms, your frame time will be of 16ms sleep + 4ms, ie 50 frames per second. Say that you do something heavy and your game takes 16 ms to compute a frame, something that would work wonderfully at 60 fps will work at a barely playable 30 fps with that sleep call in the middle.

And last, why there is a "setPriority()" there in the middle? What does accomplish? In any case, in Java (as with anything involving OS threads), the result of setting a priority of a thread is entirely OS dependent. So whatever results you get in Windows, won't be the same on Linux or OSX.

As for the "one thread per NPC"... I'll leave that for someone else biggrin.png

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

First, with the quit stuff, I meant for that to be outside the loop. That was an error on my part. As for the 16 milliseconds thing, I'm assuming that at this stage his game isn't so complex that it will cause the computer to lag behind that. Finally, with the priority stuff, that was in a tutorial I read several months ago. I myself am not entirely sure what it accomplishes, but it seemed legit at the time and I never had reason to stop using it. In hindsight that may not have been the soundest of logic, but it hasn't caused problems yet.

My website: Brass Watch Games

Come check out Shipyard, my first real game project (Very WIP): Game Website Development Journal

Shipyard is a 2D turn-based strategy with a sci-fi theme, in which you build ships from individual parts rather than being given a selection of predefined models.

You shouldn't follow tutorials which encourage you to mess up with the scheduler priorities IMO. My 2 cents.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

This topic is closed to new replies.

Advertisement