I'm currently programming very simple game for Android (API level 7) to discover and learn the android SDK. This game involve drawing shape on the screen that will change colour when touched.
Some shapes may embed one or several holes. My issue is : if I touch the shape, the whole thing's colour change, even the holes'. Here is the pseudo code I use, shape is the polygon I want to draw, boundary it's outer boundary, holes an array of its holes. Hole and boundary hold an array of their points.
Path MyPath = Path();
Path.moveTo(boundary.points[0].x, boundary.point[0].x);
for (point in boundary) {
MyPath.lineTo(point.x, point.y);
}
Path.close();
for (hole in shape.holes) {
MyPath.moveTo(hole.points[0].x,hole.points[0].y);
for (point in hole) {
MyPath.lineTo(point.x, point.y);
}
MyPath.close();
}
// setting Paint here...
canvas.drawPath(MyPath, MyPaint);
Is their something I'm missing regarding Path in Android or do you have some alternative way to do it?
Are you sure you are using the correct path filling rule? If you are using for example WINDING as filling rule the holes must be in the opposite directions in respect to the outer boundary (e.g. border counter-clockwise and holes clockwise)
Related
I'm designing a custom widget which have a gauge similar to this blue one :
(except this is a continuous gauge and not a splited one)
I tried to draw a path with two arcs :
private void drawGauge(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
float degreesToDraw = positionToDegree();
gaugePath.addArc(secondArcRect, 90, degreesToDraw);
gaugePath.addArc(faceRect, 90, degreesToDraw);
gaugePath.close();
canvas.drawPath(gaugePath, gaugePaint);
canvas.restore();
}
my two arcs are well drawn but the gaugePath.close() don't work as excepted since it close the path with the gauge start points (lower points). What I want is to draw a line between the two end points of the arcs(the higher points).
Unfortunately, I've no idea about how to find their coordinates to draw this wanted line.
FYI, I'm currently drawing this :
Any idea/help ? :)
The trouble was that faceRect and secondArcRect hadn't their center aligned on the y axis.
Simply fixing this and making them sharing the same y position for their bottom-right point(to have the two arcs cross themselves at the start and then fill properly) is enough
Does Android Region (android.graphics.Region) always have a rectangular area or can it be polygonal or rounded (curvy)?
Actually I have to do some Region.Op.UNION and Region.Op.INTERSECTION operation with multiple regions.
I want to know the shape of Ultimate Output Region, does it still have a rectangular area or not?
It can be complex (isComplex()), i.e. it consists of more than one rectangle. Not sure what do you mean by "curvy", but it can be polygonal. If I understand it correctly, you can use getBoundaryPath() to get the Path describing resulting shape.
Nothing in the documentation would lead one to conclude that a Region can be anything but a rectangle, it being constructed from either a rectangle, an x,y coordinate plus width and height, or by another region.
One can describe a rectangle from a path, so getBoundaryPath() does not necessarily conclude that a non-rectangle is possible. An encompassing rectangular boundary may instead be implied.
The isComplex() property only says that it consists of multiple rectangles. Are they all bound by a single exterior, defining rectangle? If so, how do we separate them? In the absence of sufficient documentation, one cannot tell without experimentation:
The following code describes a path and creates a polygonal region. We start with an array of any number of coordinate pairs. Then:
//describe a path corresponding to the transformed polygon
Path transformPath;
transformPath = new Path();
//starting point
transformPath.moveTo(getTransformedPolygon()[0], getTransformedPolygon()[1]);
//draw a line from one point to the next
for(int i = 2; i < arrayCoordinates.length; i = i + 2)
{
transformPath.lineTo(arrayCoordinates[i], arrayCoordinates[i + 1]);
}
//then end at the starting point to close the polygon
transformPath.lineTo(arrayCoordinates[0], arrayCoordinates[1]);
//describe a region (clip area) corresponding to the game area (my example is a game app)
Region clip = new Region(0, 0, gameSurfaceWidth, gameSurfaceHeight);
//describe a region corresponding to the transformed polygon path
transformRegion = new Region();
transformRegion.setPath(transformPath, clip);
If you display the region as a string, you will see the several pair of coordinates that make up the polygonal shape.
In Android I use a SurfaceView to display a simple 2D game. The bitmaps (.png) with alpha (representing the game objects) are drawn on the canvas.
Now I would like to do a simple but accurate collision detection. Checking whether these bitmaps are overlapping is quite easy.
But how do I check for collisions when these bitmaps have transparent areas? My challenge is detecting whether two balls collide or not. They fill up the whole bitmap in width and height both but in all four edges, there are transparent areas of course as it's a circle in a square.
What is the easiest way to detect collisions there only if the balls really collide, not their surrounding bitmap box?
Do I have to store coordinates of as many points on the ball's outline as possible? Or can Android "ignore" the alpha-channel when checking for collisions?
Another method I can think of will work with simple objects that can be constructed using Paths.
Once you have two objects whose boundaries are represented by paths, you may try this:
Path path1 = new Path();
path1.addCircle(10, 10, 4, Path.Direction.CW);
Path path2 = new Path();
path2.addCircle(15, 15, 8, Path.Direction.CW);
Region region1 = new Region();
region1.setPath(path1, clip);
Region region2 = new Region();
region2.setPath(path2, clip);
if (!region1.quickReject(region2) && region1.op(region2, Region.Op.INTERSECT)) {
// Collision!
}
Once you have your objects as Paths, you can draw them directly using drawPath(). You can also perform movement by transform()ing the path.
If it is ball collision you can perform analitical collision detection - it will be much faster then per-pixel detection. You only need to have two centers of balls (x1,y1) and (x2,y2) and radius r1 for the first ball and r2 for second one. Now if distance between centers of ball is less or equal of sum of radius then the balls are colliding:
colide = sqrt((x1-x2)^2+(y1-y2)^2)<=r1+r2
but a little faster way is to compare square of this value:
colide = (x1-x2)^2+(y1-y2)^2<=(r1+r2)^2
It's much easier to use an existing library like AndEngine instead of reinventing the wheel. I'm not sure if it can be used with a SurfaceView though. Check this article: Pixel Perfect Collision Detection for AndEngine.
I want a cylindrical, spider web like layout:
I know that I can use canvas to draw this but I also need all portions to be clickable, and canvas is very hard to handle touch for all portion.
Ideas?
can i want layout like spider...
Yes you can want it. But if you want to actually create that layout then you cannot do it with the standard android widgets.
If you want to make it then I would suggest drawing it on a Canvas manually and using the onTouchListener to catch the key presses.
I am not sure but i hope this can help you ...
The Path class holds a set of vector-drawing commands such as lines,
rectangles, and curves. Here’s an example that defines a circular path:
circle = new Path();
circle.addCircle(150, 150, 100, Direction.CW);
This defines a circle at position x=150, y=150, with a radius of 100
pixels. Now that we’ve defined the path, let’s use it to draw the circle’s
outline plus some text around the inside:
private static final String QUOTE = "Now is the time for all " +
"good men to come to the aid of their country." ;
canvas.drawPath(circle, cPaint);
canvas.drawTextOnPath(QUOTE, circle, 0, 20, tPaint);
You can see the result in this Figure
If you want to get really fancy, Android provides a number of PathEffect
classes that let you do things such as apply a random permutation to a
path, cause all the line segments along a path to be smoothed out with
curves or broken up into segments, and create other effects.
I want to create a speech balloon type shape, where there is a rectangle or ellipse with a triangular shape jutting out of it.
How I'm attempting to do this is to create a Path object that combines the triangle with the other shape (round rect).
I'm doing it as follows:
Path path = new Path();
// Create triangular segment
Point drawOffset = getAttributes().getDrawOffset();
int leaderGap = getAttributes().getLeaderGapWidth();
// Recall that we have a coordinate system where (0,0) is the
// bottom midpoint of the annotation rectangle.
// the point to left of gap
int x1 = -leaderGap/2;
int y1 = 0;
// the point to right of gap
int x2 = leaderGap/2;
int y2 = 0;
// The point where we're drawing to; the end of the pointy segment of triangle
int x3 = -drawOffset.x;
int y3 = drawOffset.y;
path.moveTo(x2, y2);
path.lineTo(x3, y3);
path.lineTo(x1, y1);
// path.close();
// Add the rectangular portion to the path
path.addRoundRect(backgroundShape, 5, 5, Path.Direction.CW);
The problem is that the roundRect is a closed path, so its edge shows through underneath the triangular section.
A picture's worth a thousand words, so here you go:
What I want is for the line segment between those two endpoints of the triangle to disappear, so that it looks like one seamless path.
If all I were doing were a straight rectangle, I could create the whole path myself from scratch. But I'd like to do the rounded corners, and it'd be a bit of a paint to do that with the Path (yes I know you can do quad to and arcTo but it's still not as clean a solution as I'd like).
So in general, is it possible to combine two paths and create a single union object that traces the perimeter of both?
Yes this is possible as of API 19. You can perform logical operations between 2 paths. As in your case, you can create a UNION of the two paths, using Path.op(). For a complete list of the operations that can be performed refer here.
I can't see a convenient way to combine paths in this manner. I would normally achieve this by manually drawing the rounded rectangular parts with Path.arcTo() and Path.lineTo(), it's a little extra effort but it will achieve the result you are looking for.
Another option which is perhaps more flexible if you decide to change the theme is to use a ninepatch drawable there's even an editor to let you create them called Draw 9-patch