I am developing a game using libgdx and i want to draw a smooth line using shape renderer.
shaperenderer.begin(ShapeType.Line);
shaperenderer.line(fisrstVec2,secondVec2);
shaperenderer.end();
I have tried Multi Sample anti aliasing from libgdx blog.
I have also went through Anti aliased filed shape in libgdx
but unfortunately these line is not in latest verson of libgdx.
Gdx.gl.glEnable(GL10.GL_LINE_SMOOTH);
Gdx.gl.glEnable(GL10.GL_POINT_SMOOTH);
Enable anti-alising in the configuration:
For Desktop:
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.samples = 2;
new LwjglApplication(new MyGdxGame(Helper.arrayList(arg)), config);
For Android:
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.numSamples = 2;
initialize(new MyGdxGame(null), config);
Or you could create a white pixmap of 1x1 and use it to create a sprite and draw the line using that sprite, I personally prefer this method istead of ShapeRenderer (note that there is no rotation in this method):
/**
* draws a line on the given axis between given points
*
* #param batch spriteBatch
* #param axis axis of the line, vertical or horizontal
* #param x x position of the start of the line
* #param y y position of the start of the line
* #param widthHeight width or height of the line according to the axis
* #param thickness thickness of the line
* #param color color of the line, if the color is null, color will not be changed.
*/
public static void line(SpriteBatch batch, Axis axis, float x, float y, float widthHeight, float thickness, Color color, float alpha) {
if (color != null) sprite.setColor(color);
sprite.setAlpha(alpha);
if (axis == Axis.vertical) {
sprite.setSize(thickness, widthHeight);
} else if (axis == Axis.horizontal) {
sprite.setSize(widthHeight, 1);
}
sprite.setPosition(x,y);
sprite.draw(batch);
sprite.setAlpha(1);
}
With some modifications to the previous method, you can come up with this method to draw a line with rotation.
public static void rotationLine(SpriteBatch batch, float x1, float y1, float x2, float y2, float thickness, Color color, float alpha) {
// set color and alpha
if (color != null) sprite.setColor(color);
sprite.setAlpha(alpha);
// set origin and rotation
sprite.setOrigin(0,0);
sprite.setRotation(getDegree(x2,y2, x1, y1));
// set position and dimension
sprite.setSize(distance(x1,y1,x2,y2),thickness);
sprite.setPosition(x1, y1);
// draw
sprite.draw(batch);
// reset rotation
sprite.rotate(0);
}
public static float getDegree(float x, float y, float originX, float originY) {
float angle = (float) Math.toDegrees(Math.atan2(y - originY, x - originX));
while (angle < 0 || angle > 360)
if (angle < 0) angle += 360;
else if (angle > 360) angle -= 360;
return angle;
}
public static float distance(float x, float y, float x2, float y2) {
return (float) Math.sqrt(Math.pow((x2 - x), 2) + Math.pow((y2 - y), 2));
}
Related
I need to make lucky wheel like view, and there texts are drawn regarding the radius, as you can see image below. ( there you can see red line, I want to draw texts along that red line )
This is the result I want to achieve but, right now with my method, it just draws text based on circle like below
private void drawText(Canvas canvas, float tempAngle, float sweepAngle, String text) {
Path path = new Path();
Log.d("mytag", "tempAngle = " + tempAngle + ", sweepAngle = " + sweepAngle);
path.addArc(range, tempAngle, sweepAngle);
float textWidth = textPaint.measureText(text);
int hOffset = (int) (radius * Math.PI / mWheelItems.size() / 2 - textWidth / 2);
int vOffset = (radius / 2 / 3) - 15; // here 15 is distance from image
canvas.drawTextOnPath(text, path, hOffset, vOffset, textPaint);
}
Instead of creating an arc to draw the text on, you need a path from the outside of the circle to the center. I think you need something like this
int radius = 180;
float centerX = width/2f;
float centerY = height/2f
double radians = radius * Math.PI / 180;
float x = (float)Math.sin(radians);
float y = (float)-Math.cos(radians);
Path path = new Path();
path.moveTo(x,y);
path.lineTo(centerX, centerY);
canvas.drawTextOnPath(text, path, hOffset, vOffset, textPaint);
First, find the slice centre points.
Kotlin sample snippet
val arcCenter = startAngle + (arcProgress / 2)
//middle point radius is half of the radius of the circle
val pointRadius = size.width / 4
/*Calculate the x & y coordinates
* find points using angle and radius
*https://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates
* */
val x =
(pointRadius * cos(Math.toRadians(arcCenter.toDouble()))) +
size.center.x
val y =
(pointRadius * sin(Math.toRadians(arcCenter.toDouble()))) +
size.center.y
Then Rotate your canvas to the arch centre angle, Draw your text and restore the canvas to a normal position
it.nativeCanvas.rotate( arcCenter, x, y)
it.nativeCanvas.drawText(...)
it.nativeCanvas.rotate( -arcCenter, x, y)
I am developing an android app which visualize the map of an environment and currently i am using libgdx to draw the map, also like any map application the user should be capable of zoom, rotate and moving the map,
I have developed a GestureHandler class which implements GestureListener interface and interacts with a PerspectiveCamera(since i will use 3d components in the future):
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
float tempX = (mapView.getCamera().position.x - deltaX * 0.5f);
float tempY = (mapView.getCamera().position.y + deltaY * 0.5f);
mapView.getCamera().position.set(
MathUtils.lerp(mapView.getCamera().position.x, tempX, mapView.getCamera().fieldOfView / 100),
MathUtils.lerp(mapView.getCamera().position.y, tempY, mapView.getCamera().fieldOfView / 100),
mapView.getCamera().position.z);
mapView.getCamera().update();
return false;
}
float initialDistance = 0;
float initialAngle = 0;
float distance = 0;
private void zoom(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2)
{
initialDistance = initialPointer1.dst(initialPointer2);
float iDeltaX = initialPointer2.x - initialPointer1.x;
float iDeltaY = initialPointer2.y - initialPointer1.y;
initialAngle = (float)Math.atan2((double)iDeltaY,(double)iDeltaX) * MathUtils.radiansToDegrees;
if(initialAngle < 0)
initialAngle = 360 - (-initialAngle);
distance = initialPointer1.dst(pointer2);
float deltaX = pointer2.x - initialPointer1.x;
float deltaY = pointer2.y - initialPointer1.y;
newAngle = (float)Math.atan2((double)deltaY,(double)deltaX) * MathUtils.radiansToDegrees;
if(newAngle < 0)
newAngle = 360 - (-newAngle);
//Log.e("test", distance + " " + initialDistance);
//Log.e("test", newAngle + " " + initialAngle);
float ratio = initialDistance/distance;
mapView.getCamera().fieldOfView = MathUtils.clamp(initialZoomScale * ratio, 1f, 100.0f);
Log.e("zoom", String.valueOf(mapView.getCamera().fieldOfView));
mapView.getCamera().update();
}
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
zoom(initialPointer1, initialPointer2, pointer1, pointer2);
float delta1X = pointer2.x - pointer1.x;
float delta1Y = pointer2.y - pointer1.y;
newAngle = (float)Math.atan2((double)delta1Y,(double)delta1X) * MathUtils.radiansToDegrees;
if(newAngle < 0)
newAngle = 360 - (-newAngle);
System.out.println("new "+newAngle);
if(newAngle - currentAngle >= 0.01000f)
{
System.out.println("Increasing");
mapView.getCamera().rotate(0.5f,0,0,1);
}
else if(newAngle - currentAngle <= -0.010000f) {
System.out.println("DEcreasing");
mapView.getCamera().rotate(-0.5f,0,0,1);
}
if(Math.abs(newAngle - currentAngle) >= 0.01000f)
{
currentAngle = newAngle;
}
return true;
}
Everything is fine until as far as i don't rotate the camera, just like this unsolved similar question after rotating the camera, movements will be affected by applied rotation.Any help specially sample codes?
Edit:
After lots of efforts i finally solved it,
As Tenfour04 said in his answer i had to use two separate matrices for transformation and rotations, and finally set the result of their multiplication to view matrix of camera using:
camera.view.set(position).mul(orientation);
Also the most important thing is to set the Transformation Matrix of my batch to camera.view:
batch.setTransformationMatrix(camera.view)
Instead of applying the gestures directly to the camera, apply them to a pair of Matrix4's that you use to store the orientation and position separately. Then in the render method, multiply the two matrices and apply them to your camera's view.
In the render() method:
camera.view.set(orientation).mul(position); //Might need to swap orientation/position--don't remember.
camera.update();
Your zoom method is fine because field of view affects the camera's projection matrix rather than its view matrix.
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 :)
I am trying to create a pad-like view in android. I got a circle that follows user's gestures and I am using distance to keep the circle of going outside the main circle of the pad control.
My problem is I want the circle to keep following the gesture, but to stay inside of the main circle. I am using the formula for finding a point using angle and radius, but it does some funky stuff.
I am translating the canvas, so that the center of the main circle is at 0, 0.
Here is the code:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(this.mainRadius, this.mainRadius);
canvas.drawCircle(0, 0, this.mainRadius, this.debugPaint);
canvas.drawCircle(this.handleX, this.handleY, this.handleRadius, this.handlePaint);
}
private void translateHandle(MotionEvent event) {
int x = (int) (event.getX() - this.mainRadius);
int y = (int) (event.getY() - this.mainRadius);
double distance = distanceFromCenter(x, y);
if (distance <= this.maxDistance) {
this.handleX = x;
this.handleY = y;
} else {
float angle = (float) Math.toDegrees(Math.atan2(y, x));
if (angle < 0)
angle += 360;
this.handleX = (int) ((this.mainRadius - this.handleRadius) * Math.cos(angle));
this.handleY = (int) ((this.mainRadius - this.handleRadius) * Math.sin(angle));
}
//onTranslateHandle(distance);
}
And here is the funky stuff in a gif image:
I cannot verify this change into your code snippet but do hope it gives some idea how to proceed further anyway;
private void translateHandle(MotionEvent event) {
float x = event.getX() - this.mainRadius;
float y = event.getY() - this.mainRadius;
double distance = distanceFromCenter(x, y);
if (distance > this.maxDistance) {
// If distance is i.e 2.0 and maxDistance is 1.0 ==> adjust is 0.5
// which repositions x and y making distance 1.0 maintaining direction
double adjust = this.maxDistance / distance;
x = (float)(x * adjust);
y = (float)(y * adjust);
}
this.handleX = (int)x;
this.handleY = (int)y;
}
I can update the answer where needed if this does not give any useful results.
here's my problem: I'm making a pool game in android and I want to make the camera rotate freely around the center of the table. The thing is that when I stop my movement it looks like the glulookat resets itself because I only see the same thing ver and over again. If somebody knows a way on how to solve this or another way to do what I watn to do i'd be REALLY appreciated
This is my renderer class:
public void onDrawFrame(GL10 gl) {
// Redraw background color
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Set GL_MODELVIEW transformation mode
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity(); // reset the matrix to its default state
// Screen position to angle conversion
theta = (float) ((360.0/screenHeight)*mMoveY*3.0); //3.0 rotations possible
phi = (float) ((360.0/screenWidth)*mMoveX*3.0);
// Spherical to Cartesian conversion.
// Degrees to radians conversion factor 0.0174532
eyeX = (float) (r * Math.sin(theta/**0.0174532*/) * Math.sin(phi/**0.0174532*/));
eyeY = (float) (r * Math.cos(theta/**0.0174532*/));
eyeZ = (float) (r * Math.sin(theta/**0.0174532*/) * Math.cos(phi/**0.0174532*/));
// Reduce theta slightly to obtain another point on the same longitude line on the sphere.
eyeXtemp = (float) (r * Math.sin(theta/**0.0174532*/-dt) * Math.sin(phi/**0.0174532*/));
eyeYtemp = (float) (r * Math.cos(theta/**0.0174532*/-dt));
eyeZtemp = (float) (r * Math.sin(theta/**0.0174532*/-dt) * Math.cos(phi/**0.0174532*/));
// Connect these two points to obtain the camera's up vector.
upX=eyeXtemp-eyeX;
upY=eyeYtemp-eyeY;
upZ=eyeZtemp-eyeZ;
// Set the view point
GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, 0,0,0, upX, upY, upZ);
and here's my onTouch method in my activity class:
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
// reverse direction of rotation above the mid-line
/*if (y > getHeight() / 2) {
dx = dx * -1 ;
}
// reverse direction of rotation to left of the mid-line
if (x < getWidth() / 2) {
dy = dy * -1 ;
}*/
mRenderer.mMoveX = dx * TOUCH_SCALE_FACTOR/100;
mRenderer.mMoveY = dy * TOUCH_SCALE_FACTOR/100;
requestRender();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
When you do the math, you're using mMoveX and mMoveY. It looks like you should be adding those to other, more persistent x/y variables instead.
Something like:
mCamX += mMoveX;
mCamY += mMoveY;
theta = (float) ((360.0/screenHeight)*mCamY*3.0); //3.0 rotations possible
phi = (float) ((360.0/screenWidth)*mCamX*3.0);