User talk:Nat/DrawingBot

From Robowiki
< User talk:Nat
Revision as of 14:08, 11 October 2009 by Nat (talk | contribs)
Jump to navigation Jump to search

Complex Graphics Rendering

Because my wave painter was very complicated (~200 java code), I always doing paint in onPaint(). If I need to paint data that aren't available globally, I'll make global variable(s) to store it. This isn't efficient I know, but it does save some skipped turns when I'm not painting (and I call nearly 10,000 trig operations for each wave in air, bot me and enemy if any)

Later when I make single Wave class that I use in many developing robots, I extract all painting code to class call WavePainter. I still do all painting in onPaint().

Recently when I was about to release Samekh, I switch the graphics system to the one similar to this (refer to User:Nat/DrawingBot) and Nfwu's mixed. I used to set isPainting = false and clear the renderables buffer in onScannedRobot() and set isPainting = true in onPaint(). This way I know if I need to calculate the graphics or not. That's when I realised something. I read somewhere:

“Complex graphics can to done by extend the Renderable abstract class.”

I then changed my WavePainter class to extends Renderable, create constructor, and I need not to check whanever I'm painting or not. If it isn't painting, then the render(Graphics2D) in my WavePainter won't be call. And if I put all calculation there I won't skipped turns due the calculation on the debug graphics.

When I look at some other robot's source that I know also do complex calculation in graphical debugging (although not as complex as mine), such as DrussGT and Diamond. For DrussGT he does painting in onPaint directly. For Diamond, he does what I used to do. Not the same, but similar. He check the paint time to decide is the painting is on or not, which make code complicated.

Pros of this method is the code is a lot cleaner. Some example of my waves:

public void onPaint(Grapgics2D g) {
    for (Wave wave : waves) {
        // 200+ lines of wave painting
    }
}

vs.

public void updateWave() {
    // notice this is in updateWave, not in onPaint
    for (Wave wave : waves) {
        wave.update(enemyLocation);
        graphics.draw(new WaveRenderer(wave));
    }
}

or in case of an arrow, which I first saw in Diamond, that I also use in my robots.

Diamond's code:

            if (paintStatus()) {
                DiaWave w = firingWaves.get(x);
                Point2D.Double angleHead = DiaUtils.project(myNextLocation, 
                    xFiringAngle, Math.min(400, 
                        w.targetDistance - 55));
                       
                _renderables.add(RoboGraphic.drawLine(myNextLocation,
                    angleHead, Color.red));
                _renderables.addAll(Arrays.asList(RoboGraphic.drawArrowHead(
                    angleHead, 10, xFiringAngle, Color.red)));
            }

versus my code:

for (Point2D pt : fireLocations)
    graphics.draw(new Arrow(myPosition, pt, Color.red));

Of course, they aren't comparable since it is under definitely different structure, but as you see my arrow drawing code is in separate class that only calculate when it is painting without need of the paintStatus() thing. Before some of you argue that Diamond's has system that allow disable/enable of graphics layer, my approach can implement the same thing too (in fact, all of this are implemented in Samekh, take a look at package nat.gfx if you like).

Comments? --Nat Pavasant 10:27, 11 October 2009 (UTC) Diamond's code above is under RWPCL. My code above I hereby make them public domain, although nothing much in it. I think we should define explicit license for all code in this site, even some code that won't worth copy at all.