onPaint caveats
Description of onPaint: "called when the script should paint it's debug".
We are generously going to assume the onPaint(Graph) method gets called 30 times per seconds.
@Override
public void onPaint(Graphics2D g2d) {
super.onPaint(g2d);
// Insert custom behavior here.
}
1. The method's thread of execution should never be ceased or paused
This will lead to inaccurate or lagged rendering, stuttering and an overall unpleasant experience for your end-user.
@Deprecated
@Override
public void onPaint(Graphics2D g2d) {
super.onPaint(g2d);
/*
* BAD CODE!
*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
If your IDE notifies you about an unhandled InterruptedException in your onPaint method, you're probably doing something wrong.
2. Calculate values at efficient intervals
Always keep in mind that this method gets called 30 times per seconds however:
- Accurate calculation of elapsed seconds requires only one or two calculations per second.
- Other calculations (experience, profit, etc...) require even less than that.
3. ... and cache them where possible
Avoid recalculation of values (such as elapsed time) used in other calculations, store and re-use where possible!
Demonstration of caveats 2 and 3:
@ScriptManifest(author = "Traum", info = "Tutorial", logo = "", name = "Tutorial - Paint", version = 0)
public class TutorialPaint extends Script {
// The String component that will be rendered.
private String paintcomponentTime = "Time:";
// We store the starting system's clock time in milliseconds.
private long startMilliseconds = System.currentTimeMillis();
// We store the elapsed amount of milliseconds (so we can reuse it instead of having to recalculate it when necessary.
private long elapsedMilliseconds = 0;
// We use this single thread executor to automatically recalculate / update the paint-required values (every 500 milliseconds).
private ScheduledExecutorService paintValueExecutor = Executors.newSingleThreadScheduledExecutor();
// The runnable that will be executed by the executor.
private Runnable paintValueRunnable = () -> {
// We calculate the elapsed amount of milliseconds.
elapsedMilliseconds = System.currentTimeMillis() - startMilliseconds;
// We also build the string value of the component that our onPaint method is going to draw, doing this here will save the cost of rapid repeated concatenation.
paintcomponentTime = "Time: " + elapsedMilliseconds;
};
@Override
public void onStart() throws InterruptedException {
super.onStart();
paintValueExecutor.scheduleAtFixedRate(paintValueRunnable, 0, 500, TimeUnit.MILLISECONDS);
}
@Override
public int onLoop() throws InterruptedException {
// ...
return 200;
}
@Override
public void onPaint(Graphics2D g2d) {
super.onPaint(g2d);
// No object or value is being calculated or created here! (except for the mandatory pixel arrays and stuff like that of course).
g2d.drawString(paintcomponentTime, 50, 50);
}
@Override
public void onExit() throws InterruptedException {
super.onExit();
paintValueExecutor.shutdown();
}
}
4. Avoid transparency
Avoid using transparency in your colors and images, your CPU and those of your end-users will thank me later.
Only use transparency cleverly where it improves usability, don't use it just for the looks of it.
More to come soon, feel free to suggest your best onPaint() tip(s)!