I want to change my dark and depressing background to a happy grassy background, in real-time, such that the happy background is shown in a radius around a game character.
A forcefield of happiness, if you will.
How can this be done as performantly as possible when rendering to a canvas in a custom view?
UPDATE: Here's how it works in my head:
private int hModeX, hModeY;
private float hModeRadius = 0.1f;
private float hModeStart = 0;
happyModeBg = Bitmap.createScaledBitmap(happyModeBg, getWidth(),getHeight(), true);
hModeX = getWidth()/2;
hModeY = getHeight()/2;
private void initHappyMode(Canvas canvas){
hModeRadius = 75 * thread.getDelta();
if(hModeRadius > 500) {
hModeStart = timestep; //What is timestep?
}
//context.arc(x, y, radius, 0, 2 * Math.PI, false); <- your version
canvas.save();
canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint) // <- my version
//context.clip(); <- dont know what this does or if there is an equivilant
canvas.drawBitmap(happyModeBg, 0, 0, null);
canvas.restore();
//requestAnimationFrame(step); <- dont know what this does since I cant seem to find it for android
}
I'm using canvas.drawArc()
to make a circle, but I'm definitely missing something.
Answer
GameDev Meta: Henshin Main!! :D
The code uses a canvas
clip
region and requestAnimationFrame
for maximum quality and efficiency. (It's better live.)
I assumed you meant HTML canvas
! Even if you didn't, other rendering engines (such as Android's 2D rendering pipeline, which you might have meant) also support hardware-accelerated clip regions. The code will likely look similar.
Requesting animation frames with requestAnimationFrame
(or another platform's provided solution) results in higher-quality animation by letting the engine determine render timing.
This renders smoothly on a low-range netbook and on my Android phone.
To make this more generally useful, let's really understand clipping.
Let's say we have these two rectangles:
Clipping works just as well on lines, points, images or anything else you might want to render. I'm just sticking to rectangles for simplicity.
We don't want the red rectangle to be visible here (black circle) at all.
So we can instruct the renderer to clip the red rectangle by that circle.
In other words, when the red rectangle is drawn, it is drawn everywhere except where that black circle would have been.
Different renderers have different ways of specifying what region to clip by. In JavaScript, with the HTML , I did essentially
// Draw the blue rectangle
context.save(); // Save the current state of the graphics context,
// so we can go back to it.
// Draw the black circle
context.clip(); // Tell the renderer that was our clip region,
// since the last `context.save()`.
// Draw the red rectangle.
// It will appear clipped by the black circle.
context.restore(); // Tell the renderer we should restore all
// the clipping settings back to what they were
// `context.save`d as.
// From here on, nothing is clipped anymore.
Now, in an Android Canvas
, you'll want to be doing a similar thing, but the renderer expects slightly different code:
// Draw the blue rectangle
canvas.save(); // Same idea as above -- just setting a point we can
// restore to later.
// Now, `canvas.clipPath` expects a `Path` object.
// Let's create one that contains a circle.
Path path = new Path();
path.addCircle(100, 100, 100, Direction.CW);
canvas.clipPath(path);
// Draw the red rectangle
// It will be clipped by the circle defined in the `path` that we
// used as the `clipPath`.
canvas.restore(); // Aaaand restore the state.
// Things drawn here won't be clipped anymore.
Android documentation on the matter might be handy. There are good questions like this one on StackOverflow about more things you might want to try with it.
No comments:
Post a Comment