Sign in to follow this  
Nils 762

Java2DGame rendering NPC's

Recommended Posts

Nils 762    130

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!

Share this post


Link to post
Share on other sites
nerdboy64    718

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
    }
}
Edited by nerdboy64

Share this post


Link to post
Share on other sites
Nils 762    130

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.

Share this post


Link to post
Share on other sites
nerdboy64    718

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.

Share this post


Link to post
Share on other sites
Nils 762    130

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.

Share this post


Link to post
Share on other sites
nerdboy64    718

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.

Share this post


Link to post
Share on other sites
Nils 762    130

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 :)

Share this post


Link to post
Share on other sites
TheChubu    9448
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

Edited by TheChubu

Share this post


Link to post
Share on other sites
nerdboy64    718

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.

Edited by nerdboy64

Share this post


Link to post
Share on other sites
Nils 762    130

So I managed to spawn NPC's of the same type in multiple locations. But now I'm having trouble updating them correctly. I have a start class(includes game loop), a levelLoader class(where I create and spawn NPC's appropriate for the level), and a seperate class for each NPC(each has it's own spawn and update method. I need to update each NPC from the Start class, but since I created the object in the LevelLoader class I can't update the correct variables of each NPC. I can't spawn the NPC's in the Start class because the LevelLoader class decides which NPC's to spawn depending on the level. I'm not sure if I said this in a very understandable way, but any help would be appreciated.

Share this post


Link to post
Share on other sites
Nicholas Kong    1535
You might want to rename your start class to be a game class. It is much more clear to people and it is very common class to use.

To answer your question, you can make npc to be an instance variable in that levelloader and then use accessor or getter method to refer to that npc.

You should post your code. It does help us a lot to see your code design. I also sense some design issues. Your npc should not be created in a levelloader class. Levelloader should do as it say load levels. You can create it in a class called level1 that would be more reasonable.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this