How to add sprites at specific part of screen AndEngine - android

I use this method to add a Sprite to the screen randomly.
private void addFace() {
Random rand = new Random();
float x = (int) mCamera.getHeight() + mBallTextureRegion.getHeight();
float minY = mBallTextureRegion.getHeight();
float maxY = (int)(mCamera.getWidth() - mBallTextureRegion.getWidth());
float rangeY = maxY - minY;
float y = rand.nextInt((int)rangeY) + minY;
this.mFaceCount++;
Log.e("Faces: ", "Face" + this.mFaceCount);
Sprite face = null;
Body body = null;
The only problem is i would like for the sprites to be added at the top of the screen(which is the camera) but instead they are added on the side of the screen.
Any suggestions on how to do this?

First of all, the (x,y) coordinates of an entity are on it's top left. So, minY should be 0, or you could just do:
float y = rand.nextFloat(maxY);
You don't need all of these (int) casts, you can delete them.
In order to make to position random, get a random X too:
float maxX = this.mCamera.getWidth() - this.mBallTextureRegion.getWidth();
float x = rand.nextFloat(maxX);
This should work.

On the android screen, the origin of the coordinate system is in the upper left corner.
(0,0)......(1,0)
(0,1)......(1,1)
So if you want something to always spawn at the top of the screen, then Y will need to be 0. Always. the X value can be anything from 0 to the width, randomly. This will place the object at the top, and randomly in the X (left-right) direction

Related

How to draw watchface 'ticks' on a square watch?

I currently have this snippet generating the ticks around the outside of and android wear watchface
float innerMainTickRadius = mCenterX - 35;
for(int tickIndex = 0; tickIndex < 12; tickIndex++) {
float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
float innerX = (float) Math.sin(tickRot) * innerMainTickRadius;
float innerY = (float) -Math.cos(tickRot) * innerMainTickRadius;
float outerX = (float) Math.sin(tickRot) * mCenterX;
float outerY = (float) -Math.cos(tickRot) * mCenterX;
canvas.drawLine(mCenterX + innerX, mCenterY + innerY, mCenterX + outerX, mCenterY + outerY, mTickPaint);
}
Which generates the ticks well on a round watchface but on a square it turns out like this:
but I'd like them to not be circular, but instead fit the shape a bit more suitably, e.g:
Is there a standard way to do this? I'm guessing I can't use trig again...
Of course you use geometry and trig. For example any line you put on the clock face you want to point to the center so one part will be the given (x,y) and the other will be arctan2(cy-y,cx-x) giving you the angle from the point you have towards the center (cx,cy) then simply draw the line in the direction of the center of a given length r, by drawing the line from x,y to cos(angle) * r, sin(angle) * r.
However, given your sample image you might want to draw the line from x,y to x+r,y then rotate the canvas by angle so that you can draw those numbers tweaked like that. Be sure to do canvas.save() before tweaking the canvas' matrix and canvas.restore() after the tweak.
This leaves the math of whatever shape you want to draw your ticks from and the positions thereto. You can do this within a Path. So define the path for a rounded rectangle and then use the PathMeasure class to get the getPosTan() and then ignore the tangent and just use the position it gives you to find your position around a rounded rectangle. That or simply calculate those positions as the positions through either a line segment or a bezier section depending on the decided shape.
For example:
static final int TICKS = 12;
static final float TICKLENGTH = 20;
In the draw routine,
float left = cx - 50;
float top = cy - 50;
float right = cx + 50;
float bottom = cy + 50;
float ry = 20;
float rx = 20;
float width = right-left;
float height = bottom-top;
Path path = new Path();
path.moveTo(right, top + ry);
path.rQuadTo(0, -ry, -rx, -ry);
path.rLineTo(-(width - (2 * rx)), 0);
path.rQuadTo(-rx, 0, -rx, ry);
path.rLineTo(0, (height - (2 * ry)));
path.rQuadTo(0, ry, rx, ry);
path.rLineTo((width - (2 * rx)), 0);
path.rQuadTo(rx, 0, rx, -ry);
path.rLineTo(0, -(height - (2 * ry)));
path.close();
PathMeasure pathMeasure = new PathMeasure();
pathMeasure.setPath(path,true);
float length = pathMeasure.getLength();
float[] pos = new float[2];
float r = TICKLENGTH;
for (int i = 0; i < TICKS; i++) {
pathMeasure.getPosTan(i * (length/TICKS),pos,null);
double angle = Math.atan2(cy - pos[1], cx - pos[0]); //yes, y then x.
double cos = Math.cos(angle);
double sin = Math.sin(angle);
canvas.drawLine(pos[0], pos[1], (float)(pos[0] + cos * r), (float)(pos[1] + sin * r), paint);
}
Admittedly it looks like:
So it would take a lot more work to get it looking like your image. But, it's totally doable. The path measure trick thing will work for any shape. I avoided using path.addRoundRect because of the Lollipop+ restriction. You can see my answer to that question here. And the other answers which are plenty fine to how to draw a rounded rectangle-esque shape. You can, if you would like to write an envelope function simply scale your current picture to the envelope of the rectangle according to the factor t, as it goes around the clock.
The angle is a function of the position now. I'm not immediately seeing the trick for getting a closed form in this case. But in the most general case, you could end up just storing the position of each tickmark, then you're just drawing the line that goes through that point and the center. so the angle at second i is just
theta(i)=arctan(y_pos(i) / x_pos(i))
assuming the center has coordinates (0,0). In this case, you only need to store the positions for 8 consecutive ticks because the face is periodic every 90 degrees and symmetric about the diagonals as well.

How to check the touch points of the circles as in the image in Libgdx?

I am facing problem in getting the touch point of the circle for the game i was developing
I tried to solve this by getting the points as below
public Actor hit(float x, float y, boolean touchable){
if(!this.isVisible() || this.getTouchable() == Touchable.disabled)
return null;
// Get center-point of bounding circle, also known as the center of the Rect
float centerX = _texture.getRegionWidth() / 2;
float centerY = _texture.getRegionHeight() / 2;
// Calculate radius of circle
float radius = (float) (Math.sqrt(centerX * centerX + centerY * centerY))-5f;
// And distance of point from the center of the circle
float distance = (float) Math.sqrt(((centerX - x) * (centerX - x))
+ ((centerY - y) * (centerY - y)));
// If the distance is less than the circle radius, it's a hit
if(distance <= radius) return this;
// Otherwise, it isn't
return null;}
I am getting hit positions inside circle but also the points around it near black spots, i only need the touch points near circle.
Would some body suggest the approach for achieving this.
Im guessing that you are comparing local rect coordinates (ie centerX, centerY) with screen coordinates x,y parameters that you are feeding to the function.
So you probably want to subtract the rect's x,y position from the parameters x,y so your parameters are in local coordinates.
So:
float lLocalX = x-rectX (assuming this is the rects x position on the screen)
float lLocalY = y-rectY (assuming this is the rects y position on the screen)
now you can compare them!
float distance = (float) Math.sqrt(((centerX - lLocalX ) * (centerX - lLocalX ))
+ ((centerY - lLocalY ) * (centerY - lLocalY )));
You can have a Circle object in your Actor: http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Circle.html
Then check if the circle contains that point using the circle.contains(float x, float y) function.
Basically it'll look something like this:
public Actor hit(float x, float y, boolean touchable){
if(!this.isVisible() || this.getTouchable() == Touchable.disabled)
return null;
if (circle.contains(x,y)) return this;
return null;
}
Of course the downside is that if this is a dynamic object and it moves around a lot, then you'd have to constantly update the circles position. Hope this helps :)

Android OpenGL ES: Normalized MotionEvent coordinate

I am trying to take a touch event and move a shape to wherever the touch event moves.
public boolean onTouchEvent(MotionEvent e) {
mRenderer.setPosition(e.getX(), e.getY());
return true;
}
The problem is the coordinates I get from the MotionEvent are the screen location in pixels, not the normalized coordinates [-1, 1]. How do I translate screen coordinates to the normalized coordinates? Thanks in advance!
float x = e.getX();
float y = e.getY();
float screenWidth;
float screenHeight;
float sceneX = (x/screenWidth)*2.0f - 1.0f;
float sceneY = (y/screenHeight)*-2.0f + 1.0f; //if bottom is at -1. Otherwise same as X
To add a bit more general code:
/*
Source and target represent the 2 coordinate systems you want to translate points between.
For this question the source is some UI view in which top left corner is at (0,0) and bottom right is at (screenWidth, screenHeight)
and destination is an openGL buffer where the parameters are the same as put in "glOrtho", in common cases (-1,1) and (1,-1).
*/
float sourceTopLeftX;
float sourceTopLeftY;
float sourceBottomRightX;
float sourceBottomRightY;
float targetTopLeftX;
float targetTopLeftY;
float targetBottomRightX;
float targetBottomRightY;
//the point you want to translate to another system
float inputX;
float inputY;
//result
float outputX;
float outputY;
outputX = targetTopLeftX + ((inputX - sourceTopLeftX) / (sourceBottomRightX-sourceTopLeftX))*(targetBottomRightX-targetTopLeftX);
outputY = targetTopLeftY + ((inputY - sourceTopLeftY) / (sourceBottomRightY-sourceTopLeftY))*(targetBottomRightY-targetTopLeftY);
With this method you can translate any point between any N-dimensional orthogonal systems (for 3D just add the same for Z as is for X and Y). In this example I used the border coordinates of the view but you can use ANY 2 points in the scene, for instance this method will work all the same if using screen center and top-right corner. The only limitaions are
sourceTopLeftX != sourceBottomRightX for every dimension

Drawing an arrow head in android

I am trying to draw an arrow to point to objects in am image. I have been able to write code to draw the line but cant seem to be able to find a way to draw the arrowhead.The code I wrote to draw a dragabble line is as follows.I need to draw an arrowhead on ACTION_UP event to the direction in which the line is pointing
if(event.getAction() ==MotionEvent.ACTION_DOWN) {
if (count==1){
x1 = event.getX();
y1 = event.getY();
System.out.println(count+"count of value a;skd");
Toast.makeText(getApplicationContext(), ""+(radius+count), Toast.LENGTH_LONG).show();
Log.i(TAG, "coordinate x1 : "+String.valueOf(x1)+" y1 : "+String.valueOf(y1));
}
}
else if(event.getAction() ==MotionEvent.ACTION_MOVE){
imageView.setImageBitmap(bmp2);
x2 = event.getX();
y2 = event.getY();
posX=(float)(x1+x2)/2;
posY=(float)(y1+y2)/2;
radius=(float) Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))/2;
onDraw();
Toast.makeText(getApplicationContext(), ""+radius, Toast.LENGTH_LONG).show();
}
Hi, for anyone still needing help .This is how I did it in the end
float h=(float) 30.0;
float phi = (float) Math.atan2(y2 - y1, x2 - x1);
float angle1 = (float) (phi - Math.PI / 6);
float angle2 = (float) (phi + Math.PI / 6);
float x3 = (float) (x2 - h * Math.cos(angle1));
float x4 = (float) (x2 - h * Math.cos(angle2));
float y3 = (float) (y2 - h * Math.sin(angle1));
float y4 = (float) (y2 - h * Math.sin(angle2));
c.drawLine(x1, y1,x2,y2 ,pnt);
c.drawLine(x2, y2,x3,y3 ,pnt);
c.drawLine(x2, y2,x4,y4 ,pnt);
I got help from the accepted answer and ios section in stackoverflow
How I would do this is to find the slope of the line, which is drawn between two points(start and end). The slope would be (dy/dx), and that would be a good start point for your arrow. Assuming you want the base of the arrowhead to be perpendicular to the line of the arrow, to find the slope of the base you would find the opposite reciprocal of the slope of the line. for example, lets say that your line has a slope of 2. The slope for the base of your triangle would be (-1/2), because you do (1/(oldslope)) and multiply by -1. I don't know android very well, but if I remember correctly, in Java, you would use a drawPolygon method, and you would have to specify 4 points(3 unique and 1 the same as the first to close it). Given the slope of the base of the tip, we can get our first two points and our final point. You should know before you start the dimensions of the arrowhead you wish to draw, so in this case b will be the length of your baseline. If you take ϴ=arctan(dy/dx), that will give you an angle between the x axis and your baseline. With that ϴ value, you can do ydif = b*sin(ϴ) to get the difference in y value between the two base corners of your arrow. Doing the same thing but with xdif = b*cos(ϴ) gives you the difference in the x value between the two base points. If the location of the final point of the line that the user drew is, say, (x1, y1), then the locations of the basepoints of the triangle would be (x1-(xdif/2), y1-(ydif/2)) and (x1+(xdif/2), y1+(ydif/2)). These two points, p1 and p2, are the first, second, and fourth points in the draw polygon method. To find the third point, we need to find the angle of the original line, by doing ϴ=arctan(dy/dx), this time using your original dy/dx. with that angle. Before we finish the actual calculation of the point, you first have to know how far from the end of your line the tip of the arrow should actually be, in my case, I will use the var h and h = 10. To get the cordinate, (x,y), assuming the cordinate for the line tip is (x1, y1)you would do (x1+hcosϴ, y1+hsinϴ). Use that for the third value in drawPolygon(), and you should be done. sorry if I kind of rushed at the end, I got kind of tired of typing, comment if you need help.
If you managed to draw a line from the input event, you might additionally draw a triangle on its end indicating the direction.
On another project I drew a square everytime a magnetic point on a grid was touched (as you can see here) Sorry I can not provide you any sample code right now. But if that's a suitable approach for you, I might post it later.
Here is a good code, its not mine, It was a Java Graphics2D code that I converted to Canvas. All credit go to the original guy/lady who wrote it
private void drawArrowHead(Canvas canvas, Point tip, Point tail)
{
double dy = tip.y - tail.y;
double dx = tip.x - tail.x;
double theta = Math.atan2(dy, dx);
int tempX = tip.x ,tempY = tip.y;
//make arrow touch the circle
if(tip.x>tail.x && tip.y==tail.y)
{
tempX = (tip.x-10);
}
else if(tip.x<tail.x && tip.y==tail.y)
{
tempX = (tip.x+10);
}
else if(tip.y>tail.y && tip.x==tail.x)
{
tempY = (tip.y-10);
}
else if(tip.y<tail.y && tip.x==tail.x)
{
tempY = (tip.y+10);
}
else if(tip.x>tail.x || tip.x<tail.x)
{
int rCosTheta = (int) ((10)*Math.cos(theta)) ;
int xx = tip.x - rCosTheta;
int yy = (int) ((xx-tip.x)*(dy/dx) + tip.y);
tempX = xx;
tempY = yy;
}
double x, y, rho = theta + phi;
for(int j = 0; j < 2; j++)
{
x = tempX - arrowLength * Math.cos(rho);
y = tempY - arrowLength * Math.sin(rho);
canvas.drawLine(tempX,tempY,(int)x,(int)y,this.paint);
rho = theta - phi;
}
}
Just call this for both sides of your line and it will draw an arrow at each side!

How to know image was translated or not with matrix?

I'm using TouchImageView from github and using matrix.posttranslate to handle user control of dragging zoom image. Problem is I need to know when user drag to border of image, so image can't move horizontally any more. Has anyone have ideal about that?
If you are not rotating your Matrix then second and fifth elements are translateX and translateY:
final Matrix matrix = ...;
final float[] values = new float[9];
matrix.getValues(values);
final float translateX = values[2];
final float translateY = values[5];
Thanks. And after deeply read sourcecode of gallery on github, i got solution. To check whether swipe to right border or not:
float scaledWidth = Math.round(mOrigWidth * mSaveScale);
if (Math.abs(mViewWidth - translateX - scaledWidth) <= 1.0) {
// drag to right border
ALog.d("touchimageview", "right x: "
+ (mViewWidth - translateX - scaledWidth));
touchEventListener.onZoomToOriginal();
break;
}

Categories

Resources