Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (495)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Performance Issues: CPU  (Read 2273 times)
0 Members and 1 Guest are viewing this topic.
Offline jevans

Junior Newbie





« Posted 2008-05-10 05:28:44 »

I'm having a ton of issues with performance and it seems to be a CPU issue.  I think I might be trying to do far too much with my game.

Its a top down RTS style game and you have 20 units.  The problem is that I'm addicted to loops and arraylists.  I dont know any other way to do some of the things I need to do.  I am using active rendering and FSEM.  My FPS is supposed to be 60.  I'm going to post most of the relevant code, but it is quite long so don't feel obligated to sift through my horrible...horrible code.

Be warned, its ugly and probably bad programming.  All of this gets done 60 times a second.  I'm sure that there is a much better way to do this so it doesn't need to be done every 60 seconds.  But the screen needs to move in response to the mouse going to the edge of the screen so things need to be updated constantly.  Also, I have never made a habit out of commenting so seriously, DO NOT FEEL OBLIGATED TO READ MY CODE, but any help would be appreciated. Thanks to anyone who will hold my hand through this =)

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
private void gameRender(Graphics dbg)
    {
        counter++;
        if(counter == 61)counter = 0;
       if(dbImage == null){
            dbImage = createImage(pWidth, pHeight);
            if(dbImage == null){
                System.out.println("dbImage is null!");
                return;
            }else
                dbg = dbImage.getGraphics();
        }
        g2 = (Graphics2D)dbg;
        dbg.setColor(Color.black);
        dbg.fillRect(0, 0, pWidth, pHeight);
        //draw game elements
       //draw main screen
       screen = new Rectangle2D.Double(-x, -y, 1024, 588);
        for(int i = 0; i < 12; i++){
                for(int p = 0; p < 7; p++){
                  int tile;
                  int xMod;
                  int yMod;
                  int x1Mod;
                  int y1Mod;
                  xMod = 0;
                  yMod = 0;
                  x1Mod = x%100;
                  y1Mod = y%100;
                  if(-x > 99) xMod = -(x/100);
                  if(-y > 99) yMod = -(y/100);
                  tile = mL.getTile(xMod + i, yMod + p);
                  if(tile == 48) g2.drawImage(grass, (i*100)+x1Mod, (p*100)+y1Mod, null);
                  if(tile == 49) g2.drawImage(tree, (i*100)+x1Mod, (p*100)+y1Mod, null);
                }
        }
       
        for(int i = 0; i < 20; i++){
            if(counter == 60)combat(i);
            if(p1Units.get(i).getBox().intersects(screen)){
                if(playerNum == 2){
                    g2.setColor(Color.red);
                    g2.draw(new Ellipse2D.Double(p1Units.get(i).getBox().getX()+x+2.5, p1Units.get(i).getBox().getY()+45+y, p1Units.get(i).getBox().getWidth(),p1Units.get(i).getBox().getWidth()));
                }
                for(int p = 0; p < 5; p++){
                    if(i == selectedUnit[p]){
                        g2.setColor(Color.white);
                        g2.draw(new Ellipse2D.Double(p1Units.get(i).getBox().getX()+x+2.5, p1Units.get(i).getBox().getY()+45+y, p1Units.get(i).getBox().getWidth(),p1Units.get(i).getBox().getWidth()));                    
                    }
                }
                if(p1Units.get(i).getType() == "tank"){
                    g2.drawImage(tank.get(p1Units.get(i).getFacing()-1), (int)p1Units.get(i).getX() + x, (int)p1Units.get(i).getY() + y, null);
                }
                if(p1Units.get(i).getType() == "artillery"){
                    g2.drawImage(artillery.get(p1Units.get(i).getFacing()-1), (int)p1Units.get(i).getX() + x, (int)p1Units.get(i).getY() + y, null);
                }
            }
            if(p2Units.get(i).getBox().intersects(screen)){
                if(playerNum == 1){
                    g2.setColor(Color.red);
                    g2.draw(new Ellipse2D.Double(p2Units.get(i).getBox().getX()+x+2.5, p2Units.get(i).getBox().getY()+45+y, p2Units.get(i).getBox().getWidth(),p2Units.get(i).getBox().getWidth()));
                   
                }
                g2.drawImage(tank.get(p2Units.get(i).getFacing()), (int)p2Units.get(i).getX() + x, (int)p2Units.get(i).getY() + y, null);
                //if(playerNum == 1){
                   //g2.fill(new Rectangle2D.Double(p2Units.get(i).getX()+x+40, p2Units.get(i).getY()+y+100, 100, 10));
                   //g2.setColor(Color.green);
                  // g2.fill(new Rectangle2D.Double(p2Units.get(i).getX()+x+40, p2Units.get(i).getY()+y+100, p2Units.get(i).getHealth(), 10));
              // }
           }
            if(p1Units.get(i).getType() == "artillery" && p1Units.get(i).isFiring()){
                Point2D point = explosionHandler.drawExplosion(i, counter);
                if(point.getX() != 0 && point.getY() != 0){
                    g2.drawImage(explosion, (int)point.getX()-55+x, (int)point.getY()-48+y, null);
                }
            }
        }
        //draw border
       g2.setColor(Color.white);
        g2.drawImage(hud, 0, 588, null);
        g2.drawImage(minimap, 849, 593, null);
        for(int i = 0; i < 20; i++){
            g2.setColor(Color.blue);
            g2.fill(new Rectangle2D.Double((p1Units.get(i).getX()/22.86) + 849, (p1Units.get(i).getY()/22.86)+593, 4.37, 4.37));
            g2.setColor(Color.red);
            g2.fill(new Rectangle2D.Double((p2Units.get(i).getX()/22.86) + 849, (p2Units.get(i).getY()/22.86)+593, 4.37, 4.37));
        }
        if(selectedUnit[0] != 21){
            if(p1Units.get(selectedUnit[0]).getType() == "artillery"){
                Unit u = p1Units.get(selectedUnit[0]);
                if(u.getStance() == "mobile") g2.drawImage(mobile, 775, 598, null);
                else g2.drawImage(fire, 775, 598, null);
            }
        }
        g2.setColor(Color.yellow);
        g2.draw(new Rectangle2D.Double((849+(-x/22.86)), (593 + (-y/22.86)), 44.79, 25.94));
        //g2.fill(new Rectangle2D.Double(0, 568, 1024, 200));
       
    }
    private void combat(int index){
        int i2 = p1Units.get(index).getTheTarget();
        if(p1Units.get(index).isFiring()){
           
            if(i2 != 21){
                if(!p2Units.get(i2).isDead()){
                    if(!p1Units.get(index).isInRange(p2Units.get(p1Units.get(index).getTheTarget()).getX(), p2Units.get(p1Units.get(index).getTheTarget()).getY())){
                        p1Units.get(index).setIsFiring(false);
                        p1Units.get(index).setTarget((int)p2Units.get(i2).getX(), (int)p2Units.get(i2).getY());
                        p1Units.get(index).setIsMoving(true);
                    }
                    p2Units.get(i2).attacked(p1Units.get(index).getExplosionAttack(), p1Units.get(index).getBulletAttack());
                }else{
                    p1Units.get(index).setTarget(21);
                    p1Units.get(index).setIsFiring(false);
                }
            }
           
        }
       
        for(int i = 0; i < 20; i++){
            if(p1Units.get(index).isInRange(p2Units.get(i).getX(), p2Units.get(i).getY())){
                p1Units.get(index).setIsFiring(true);
                p1Units.get(index).setTarget(i);                  
            }
        }
        if(i2 != 21){
            if(p2Units.get(i2).isDead()){
                    p1Units.get(index).setTarget(21);
                    p1Units.get(index).setIsFiring(false);
            }
        }
    }
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #1 - Posted 2008-05-10 06:00:53 »

a) There are magic numbers.
b) == isn't for string comparison (use equals() instead).
c) Use a profiler to identify the bottlenecks.

弾幕 ☆ @mahonnaiseblog
Offline jevans

Junior Newbie





« Reply #2 - Posted 2008-05-10 06:07:24 »

a) There are magic numbers.
b) == isn't for string comparison (use equals() instead).
c) Use a profiler to identify the bottlenecks.

a) What?
b) It seems to work, is there a reason to use equals() instead?
c) How do I use a profiler?

EDIT: Okay, wiki'd magic numbers and I'm assuming you're refering to my poorly named, non-documented variables.  This was is mentioned in my post and it makes my code horribly unreadable, I know, I'm trying to fix that habit.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #3 - Posted 2008-05-10 06:17:40 »

>It seems to work, is there a reason to use equals() instead?

== only happens to work if both references point to the very same object. Just being identical isn't enough. (So, it may stop working later on... once you moved some of the source around.)

>How do I use a profiler?

Netbeans has a good one. You should be able to find lots of tutorials for that one. The JDK also ships with a very basic one (the -Xprof switch).

>[...]I'm assuming you're refering to my poorly named, non-documented variables.

No, it's stuff like the 20 here:
for(int i = 0; i < 20; i++)

or the 21 there:
if(i2 != 21){

弾幕 ☆ @mahonnaiseblog
Offline jevans

Junior Newbie





« Reply #4 - Posted 2008-05-10 06:25:43 »

I see, so for good programming conventions in the future I should just use properly named constants for those?


Profiler stats incoming soon.
Offline jevans

Junior Newbie





« Reply #5 - Posted 2008-05-10 06:41:32 »

Profiler screenshot:


EDIT: If that is unreadable, its telling me my CPU is spending most of its time in gameRender() by a long shot.
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #6 - Posted 2008-05-10 07:19:22 »

>I see, so for good programming conventions in the future I should just use properly named constants for those?

Yes. Or enums. E.g. those string comparisons could be replaced with enum comparisons like bla.getType()==Type.foo.

isInRange also seems to take some cpu. Keep in mind that you don't need sqrt if you don't need the exact distance.

You also don't need to clear the screen if everything is overdrawn anyways.

You can also inspect the rendering in detail via:
-Dsun.java2d.trace=log
(try searching the forum for this)

弾幕 ☆ @mahonnaiseblog
Offline Jackal von ÖRF

Junior Member





« Reply #7 - Posted 2008-05-10 09:26:12 »

its telling me my CPU is spending most of its time in gameRender() by a long shot.

Split the gameRender() method into a couple of smaller methods (using Extract Method refactoring),  so that one method does one thing and one thing only (Single Responsibility Principle). Then the profiler can show better which part of gameRender() takes the most time.

Offline fletchergames

Senior Member





« Reply #8 - Posted 2008-05-10 14:27:27 »

1  
2  
3  
4  
5  
6  
7  
8  
       if(dbImage == null){
            dbImage = createImage(pWidth, pHeight);
            if(dbImage == null){
                System.out.println("dbImage is null!");
                return;
            }else
                dbg = dbImage.getGraphics();
        }

Why aren't you using BufferStrategy.getDrawGraphics?  Are you using active rendering?  If not, you should, given that performance is an issue.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
        //draw main screen
       screen = new Rectangle2D.Double(-x, -y, 1024, 588);
        for(int i = 0; i < 12; i++){
                for(int p = 0; p < 7; p++){
                  int tile;
                  int xMod;
                  int yMod;
                  int x1Mod;
                  int y1Mod;
                  xMod = 0;
                  yMod = 0;
                  x1Mod = x%100;
                  y1Mod = y%100;
                  if(-x > 99) xMod = -(x/100);
                  if(-y > 99) yMod = -(y/100);
                  tile = mL.getTile(xMod + i, yMod + p);
                  if(tile == 48) g2.drawImage(grass, (i*100)+x1Mod, (p*100)+y1Mod, null);
                  if(tile == 49) g2.drawImage(tree, (i*100)+x1Mod, (p*100)+y1Mod, null);
                }
        }

First, why are you declaring the variables before setting them?  Why not the following:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
        //draw main screen
       screen = new Rectangle2D.Double(-x, -y, 1024, 588);
        for(int i = 0; i < 12; i++){
                for(int p = 0; p < 7; p++){
                  int xMod = 0;
                  int yMod = 0;
                  int x1Mod = x%100;
                  int y1Mod = y%100;
                  if(-x > 99) xMod = -(x/100);
                  if(-y > 99) yMod = -(y/100);
                  int tile = mL.getTile(xMod + i, yMod + p);
                  if(tile == 48) g2.drawImage(grass, (i*100)+x1Mod, (p*100)+y1Mod, null);
                  if(tile == 49) g2.drawImage(tree, (i*100)+x1Mod, (p*100)+y1Mod, null);
                }
        }


It doesn't really matter, but the other way had more lines of code.

Second, get rid of the if statements.  Instead of some kind of array "tileImages" and use this code:
1  
g2.draw(tileImage[tile], (i*100)+x1Mod, (p*100)+y1Mod, null);


It's the same for this code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
        for(int i = 0; i < 20; i++){
            if(counter == 60)combat(i);
            if(p1Units.get(i).getBox().intersects(screen)){
                if(playerNum == 2){
                    g2.setColor(Color.red);
                    g2.draw(new Ellipse2D.Double(p1Units.get(i).getBox().getX()+x+2.5, p1Units.get(i).getBox().getY()+45+y, p1Units.get(i).getBox().getWidth(),p1Units.get(i).getBox().getWidth()));
                }
                for(int p = 0; p < 5; p++){
                    if(i == selectedUnit[p]){
                        g2.setColor(Color.white);
                        g2.draw(new Ellipse2D.Double(p1Units.get(i).getBox().getX()+x+2.5, p1Units.get(i).getBox().getY()+45+y, p1Units.get(i).getBox().getWidth(),p1Units.get(i).getBox().getWidth()));                    
                    }
                }
                if(p1Units.get(i).getType() == "tank"){
                    g2.drawImage(tank.get(p1Units.get(i).getFacing()-1), (int)p1Units.get(i).getX() + x, (int)p1Units.get(i).getY() + y, null);
                }
                if(p1Units.get(i).getType() == "artillery"){
                    g2.drawImage(artillery.get(p1Units.get(i).getFacing()-1), (int)p1Units.get(i).getX() + x, (int)p1Units.get(i).getY() + y, null);
                }
            }
            if(p2Units.get(i).getBox().intersects(screen)){
                if(playerNum == 1){
                    g2.setColor(Color.red);
                    g2.draw(new Ellipse2D.Double(p2Units.get(i).getBox().getX()+x+2.5, p2Units.get(i).getBox().getY()+45+y, p2Units.get(i).getBox().getWidth(),p2Units.get(i).getBox().getWidth()));
                   
                }
                g2.drawImage(tank.get(p2Units.get(i).getFacing()), (int)p2Units.get(i).getX() + x, (int)p2Units.get(i).getY() + y, null);
                //if(playerNum == 1){
                   //g2.fill(new Rectangle2D.Double(p2Units.get(i).getX()+x+40, p2Units.get(i).getY()+y+100, 100, 10));
                   //g2.setColor(Color.green);
                  // g2.fill(new Rectangle2D.Double(p2Units.get(i).getX()+x+40, p2Units.get(i).getY()+y+100, p2Units.get(i).getHealth(), 10));
              // }
           }
            if(p1Units.get(i).getType() == "artillery" && p1Units.get(i).isFiring()){
                Point2D point = explosionHandler.drawExplosion(i, counter);
                if(point.getX() != 0 && point.getY() != 0){
                    g2.drawImage(explosion, (int)point.getX()-55+x, (int)point.getY()-48+y, null);
                }
            }
        }

You should have a class for the unit type and give the class a drawTo method.  Different unit types will implement this method differently, though you can probably just make all the unit types the draw an image be different instances of the same class.  Then you can replace all those if statements by
1  
p1Units.get(i).drawTo(xCoordinate, yCoordinate);
.  You may need to have a drawTo method in the unit class if there's ever a circumstance where 2 units of the same type look different.

Getting rid of the if statements might not improve performance, but it would make your code actually readable.

One person suggested splitting up your method into multiple methods for the profiler.  That will probably help you zoom in on the problem, though I wouldn't recommend it except for making it easier to profile.  Splitting up one easy-to-understand method into several methods scattered around your code won't help anyone.  (Of course, the method isn't "easy-to-understand" right now, but splitting it up won't make it any better.  Getting rid of the if statements will make it easy-to-understand.)
Offline jevans

Junior Newbie





« Reply #9 - Posted 2008-05-10 15:32:08 »

Quote
You should have a class for the unit type and give the class a drawTo method.  Different unit types will implement this method differently, though you can probably just make all the unit types the draw an image be different instances of the same class.

How do I draw images outside of gameRender()?

Do I just pass my Graphics2D variable to the method and use it to draw in the method? 

I'm not sure how that works if that isn't how you do it.


And yes I am using active rendering I'm sure if it, I'm using the same animation loop for FSEM active rendering as is in Killer Game Programming in Java.

I had the dbImage buffering commented out, I'm not sure why all of a sudden it is in now.

The irony of this whole thing is that this is the second time writing this game and this time it was supposed to be more readable and CPU efficient.  So much for that.

EDIT: I've been surfing around some of the other posts on this forum and it seems that swing and active rendering are a problem.  All of this code is in a JFrame is that a problem?  What else do I use if not JFrame?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 798
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #10 - Posted 2008-05-10 17:26:35 »

Quote
How do I draw images outside of gameRender()?

Do I just pass my Graphics2D variable to the method and use it to draw in the method?

You should really read a book about the basics of programming. You'll find yourself severly constrained in making your game when you do not yet master these basic concepts of object oriented programming.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline jevans

Junior Newbie





« Reply #11 - Posted 2008-05-11 01:21:02 »

You should really read a book about the basics of programming. You'll find yourself severly constrained in making your game when you do not yet master these basic concepts of object oriented programming.

Any suggestions?  I'm more adept at Java than I let on perhaps by my questions.  Any books on basic program layout and programming basics would be greatly appreciated.

Offline fletchergames

Senior Member





« Reply #12 - Posted 2008-05-12 03:04:26 »

How do I draw images outside of gameRender()?

Do I just pass my Graphics2D variable to the method and use it to draw in the method? 
Yes.

That's just part of having good modular code.  Sprites (or whatever) should usually draw themselves upon demand.

The irony of this whole thing is that this is the second time writing this game and this time it was supposed to be more readable and CPU efficient.  So much for that.
If you were changing around the drawing code, it probably has nothing to do with the CPU.  It may be that some of your images were getting hardware accelerated before but aren't now for some reason.  You should look up hardware image acceleration on this forum.

The code you posted isn't especially CPU-intensive so far as I can tell.  It seems probable that it's been an issue with how your code is using the video card.

EDIT: I've been surfing around some of the other posts on this forum and it seems that swing and active rendering are a problem.  All of this code is in a JFrame is that a problem?  What else do I use if not JFrame?
There's nothing wrong with JFrame.  Active rendering isn't a problem; it's a solution.  Swing works just fine, but you might not have stumbled upon the magical "correct" way of doing things.

There's alot of odd little details that have to be taken care of for things to work properly.  For instance, some ways of loading images result in hardware accelerated images, while others do not.

The problem is probably elsewhere in your code, not in the code you posted.  The code you posted can certainly be improved, but nothing about it suggests that it would run especially slow.

If you have a good knowledge of Java but not so much knowledge of game programming, I would suggest buying Developing Games in Java or Killer Game Programming Java (or, preferably, both).  They're a few years old now, but I don't know of any better introductory Java game programming books.  Of course, I only buy so many.
Offline Eckish

Senior Newbie





« Reply #13 - Posted 2008-05-12 22:39:41 »

Killer Game Programming in Java can be found for free at https://fivedots.coe.psu.ac.th/~ad/jg/.  Just click on each chapter and open the pdf file to read it.

EDIT: Well they are at least draft versions of the book's chapters.  Still good enough to learn from, though.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Dwinin (28 views)
2014-09-12 09:08:26

Norakomi (57 views)
2014-09-10 13:57:51

TehJavaDev (73 views)
2014-09-10 06:39:09

Tekkerue (37 views)
2014-09-09 02:24:56

mitcheeb (57 views)
2014-09-08 06:06:29

BurntPizza (44 views)
2014-09-07 01:13:42

Longarmx (27 views)
2014-09-07 01:12:14

Longarmx (34 views)
2014-09-07 01:11:22

Longarmx (34 views)
2014-09-07 01:10:19

mitcheeb (40 views)
2014-09-04 23:08:59
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!