Androidplot draw circle with given point and radius - java

I am using androidplot with PanZoom attached:
PanZoom.attach(plot);
Therefore I can zoom in and out as it should.
What I want next is to draw a circle at a given point.
Right now I use the strokewidth to set the dimension of the circle.
But when I zoom in and out, the circle size remains the same, although it should scale according to the zoom level. So imagine I zoom in infinitely, the circle should at a certain amount of zoom level cover the whole screen.
But it does not.
How can I achieve this?
I was thinking aboud increasing the strokewidth of the circle according to the zoomlevel but I was neither able to get the zoomlevel nor to get the domain levels on the left and right side of the plot.
EDIT:
In xml folder I create a file e.g. circle.xml:
<?xml version="1.0" encoding="utf-8"?>
<config
fillPaint.color="#00000000"
linePaint.color="#00000000"
linePaint.strokeWidth="0dp"
pointLabelFormatter.textPaint.color="#FFFFFF"
vertexPaint.color="#371cd1d4"
vertexPaint.strokeWidth="20dp"/>
and in java
sigmaLabelFormatter = new LineAndPointFormatter();
sigmaLabelFormatter.setPointLabelFormatter(new PointLabelFormatter());
sigmaLabelFormatter.configure(activity.getApplicationContext(), R.xml.circle);
sigmaLabelFormatter.setPointLabelFormatter(null);

Zoom only affects the drawing of XYSeries data; if you draw directly on the canvas, it will be drawn exactly where you specify on the canvas regardless of pan/zoom.
One thing you can do though is to make series to represent your circle and draw the circle there. This will make the circle respond to both pan and zoom actions. The tricky part will be picking enough points to ensure that the circle appears smooth at your highest supported zoom level.

I found a solution to my problem, since I finally managed:
to get the domain levels on the left and right side of the plot.
or to be more precise to get the width of the plot.
Since the dimensions of the plot is in meters, I do the calculation as follows:
private float calculateDP(float px){
return px / (densityDpi / densityDefault);
}
private float pixelsPerMeter(float value){
float w = plot.getGraph().getWidgetDimensions().canvasRect.width();
float w2 = plot.getBounds().getWidth().floatValue();
return value * (w / w2);
}
private void init(Activity activity){
densityDpi = activity.getResources().getDisplayMetrics().densityDpi;
densityDefault = android.util.DisplayMetrics.DENSITY_DEFAULT;
}
private void onCreate(){
// ... lots of stuff
labelFormatter.getVertexPaint().setStrokeWidth(calculateDP(pixelsPerMeter(2)));
}
Might it help somebody out there...

Related

Is it possible to select/click multiple parts of one image?

For an assignment I am making a Boardgame. (In java) This Boardgame has a map, with multiple fields/lands that have to be used. Units can be placed on them, they can move. Other things are also placed on them.
For the map I have one image I use. I looked online for solutions, but the only ones I found where for a grid game (such as chess or checkers) and the map of this game can not be divided in just squares. I tried this, but the field shapes are to different to make that work.
I had a few faint ideas as to how to work this out, but I can't quite put them into code examples and have no clue if they would work, or how.
The ideas I had:
Make some invisible buttons and bind them to specific coordinates in the picture. The problem I had with this solution was that it also had to be able to display things placed on it. It would also be very inconvenient if not all of the field was clickable.
I have a 'overlay' image with the outlines of all the fields and the 'insides' removed. I made this overlay so I could add a faint color overlay over the board. Would it be possible to use this in any kind of way?
First I though of cutting out all the loose fields and putting them together to form the one image. Only, I don't know how I would do this. Not just where to place it, but also, how can I make sure that the elements are Always in the same place compared to eachother, and my board doesn't mess up when changing screen/resolution size?
I am using javafx for the graphical elements in my game.
If there are any suggestions of something I haven't thought of myself, those are also very welcome.
If it's sufficient to retrieve the color of the pixel where the mouse was clicked, then you can do that fairly easily. If you know the image is displayed in the image view unscaled and uncropped, then all you need is:
imageView.setOnMouseClicked(e -> {
Color color = imageView.getImage().getPixelReader().getColor((int)e.getX(), (int)e.getY());
// ...
});
More generally, you may need to map the image view coordinates to the image coordinates:
imageView.setOnMouseClicked(e -> {
double viewX = e.getX();
double viewY = e.getY();
double viewW = imageView.getBoundsInLocal().getWidth();
double viewH = imageView.getBoundsInLocal().getHeight();
Rectangle2D viewport = imageView.getViewport();
double imgX = viewport.getMinX() + e.getX() * viewport.getWidth() / viewW;
double imgY = viewport.getMinY() + e.getY() * viewport.getHeight() / viewH ;
Color color = imageView.getImage().getPixelReader().getColor((int)imgX, (int)imgY);
// ...
});
Once you have the color you can do some simple analysis to see if it approximately matches the color of various items in your image, e.g. check the hue component, or check if the "distance" from a fixed color is suitably small.
A typical implementation of that might look like:
// choose a color based on what is in your image:
private final Color FIELD_GREEN = Color.rgb(10, 10, 200);
private double distance(Color c1, Color c2) {
double deltaR = c1.getRed() - c2.getRed();
double deltaG = c1.getGreen() - c2.getGreen();
double deltaB = c1.getBlue() - c2.getBlue();
return Math.sqrt(deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
}
private boolean colorsApproximatelyEqual(Color c1, Color c2, double tolerance) {
return distance(c1, c2) < tolerance ;
}
And the back in the handler you can do
if (colorsApproximatelyEqual(color, FIELD_GREEN, 0.1)) {
// process click on field...
}
Whether or not this is a viable approach depends on the nature of the image map. If the coloring in the map is too complex (or objects are not easily distinguishable by color), then you will likely need to place other elements in the scene graph and register handlers on each of them, as you describe in the question.

Why doesn't simply scaling things up in LibGDX and Box2D work correctly?

I'm trying to get rid of having to scale all the coordinates on my sprites when using Box2D and LibGDX.
Here are the settings for my viewport and physics world:
// Used to create an Extend Viewport
public static final int MIN_WIDTH = 480;
public static final int MIN_HEIGHT = 800;
// Used to scale all sprite's coordinates
public static final float PIXELS_TO_METERS = 100f;
// Used with physics world.
public static final float GRAVITY = -9.8f;
public static final float IMPULSE = 0.15f;
world.setGravity(new Vector2(0f, GRAVITY));
When I apply a linear impulse to my character (when the user taps the screen) everything works fine:
body.setLinearVelocity(0f, 0f);
body.applyLinearImpulse(0, IMPULSE, body.getPosition().x, body.getPosition().y, true);
The body has a density of 0f, but changing this to 1f or even 100f doesn't seem to have any real effect.
This means that I have to scale all the sprite's locations in the draw method by PIXELS_TO_METERS. I figured (perhaps incorrectly) that I could simply scale GRAVITY and IMPULSE by PIXELS_TO_METERS and have it work exactly the same. This doesn't seem to be the case. Gravity seems really small, and applying the impulse barely has any effect at all.
// Used to scale all sprite's coordinates
public static final float PIXELS_TO_METERS = 1f;
// Used with physics world.
public static final float GRAVITY = -9.8f * 100;
public static final float IMPULSE = 0.15f * 100;
So:
1) why doesn't simply scaling up all the values make it work the same?
2) Is there a better way to do this?
It looks like you're over complicating your design by using some imaginary pixel units (i doubt it are actual pixels you're referring to). I'd advice you to use meaningful units instead, for example meters, and stick to it. Thus, use meters for all coordinates (including your virtual viewport). So, practically modify you code to look like this:
// Used to create an Extend Viewport
public static final float MIN_WIDTH = 4.8f; // at least 4.8 meters in width is visible
public static final float MIN_HEIGHT = 8.0f; // at least 8 meter in height is visible
This completely removes the need to scale meter to your imaginary pixel units. The actual scaling from your units (virtual viewport size) to the screen (values between -1 and +1) is done by the camera. You should not have to think about scaling units in your design.
Make sure to remove your PIXELS_TO_METERS constant (don't set it to 1f, it is only complicating your code at no gain) and make sure you're not using imaginary pixels at all in your code. The latter includes all sprites that you create without explicitly specifying its size in meters.
It is still possible to "scale" your units (in your game logic) compared to SI units, because of valid reasons. For example, when creating a space game, you might find yourself using very large numbers when using meters. Typically you'd want to keep the values around 1f to avoid floating point errors. In such case it can be useful to use e.g. dekameters (x10), hectometers (x100) or kilometers (x1000) instead. If you do this, make sure to be consistent. It might help to add the units in comments so you don't forget to scale properly (e.g. GRAVITY = -0.0098f; // kilometer per second per second).
I have implemented as this:
// in declaration
float PIXELS_TO_METERS = 32; // in my case: 1m = 32 pixels
Matrix4 projection = new Matrix4();
// in creation
viewport = new FitViewport(
Application.width
, Application.height
, Application.camera);
viewport.apply();
// set vieport dimensions
camera.setToOrtho(false, gameWidth, gameHeight);
// in render
projection.set(batch.getProjectionMatrix());
projection.scl(PIXELS_TO_METERS);
box2dDebugRenderer.render(world, projection);
// in player body creation
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.x = getPosition().x / PIXELS_TO_METERS;
bodyDef.position.y = getPosition().y / PIXELS_TO_METERS;
CircleShape shape = new CircleShape();
shape.setRadius((getBounds().width * 0.5f) / PIXELS_TO_METERS);
// in player update
setPosition(
body.getPosition().x * PIXELS_TO_METERS - playerWidth,
body.getPosition().y * PIXELS_TO_METERS - playerHeight);
So to set pixels to meters in box2d methods you have to divide pixel-positions by PIXELS_TO_METERS and to set meters to pixels in player position you have to multiply box2d values by PIXELS_TO_METERS.
Set your PIXELS_TO_METERS correctly to how much pixels in your screens match to 1 meter.
Good luck.

LibGDX problems rotating sprite

OK so I'm really confused I've rotated sprites before and had no problem such as rotating a boat as it moves through an ocean, but for some reason I'm having a really big problem this time. So I create a texture in an assets file, but not static textures. I load the texture using the following:
class Assets{
Texture img;
public Assets(){
img = new Texture(Gdx.files.internal("images/PNG.png")
And then I call the assets in the main class by calling:
Assets assets = new Assets()
And then I have a class that is an animator just for this main character because his animation is so different and varied from other characters.
class Animations{
Guy MYGUY;
Texture firstTexture;
ArrayList<Texture> running;
Sprite CurrentSprite;
public Animations(Texture standingStill, Guy myGuy){
MYGUY = myGuy;
firstTexture = standingStill;
running = new ArrayList<Texture>();
running.add(firstTexture);
CurrentSprite = new Sprite(firstTexture);
public void update (int direction, int state){
CurrentSprite.setPosition(MYGUY.X, MYGUY.Y)
// I have a switch here, but it does nothing yet because I haven't added in different actions for the character.
//However I do have a switch for direction, because that is important right now
switch(state){
case Guy.LEFT:
CurrentSprite.set rotation(180);
//yes there are more, but even rotating 180 won't work correctly
}
Then I have a renderer class to draw everything, i have the object MyGuy in an object for the world called myLand and I draw it with:
myLand.GUY.animation.CurrentSprite(batch);
So my problem arises on the rotation, whenever it rotates 180 degrees it seems to always rotate around the coordinates (0, 0) instead of the center of the sprite. So it usually ends up where I move like five to the right, but then if I try to go left it does double the distance backwards, but the camera position stays the same, and the guy usually disappears off the left or right side of the screen.
Try use rotate(...)method instead of setRotation(...).
With setOrigin(widthSprite\2, heightSprite\2)
That action rotate sprite itself.
Try
sprite.setOriginCenter();
This should help
Instead of rotating the sprite, just flip it with this single line:
CurrentSprite.flip(true, false);
the first boolean is X flip (that's what you want to set as true when going left) and the second is the Y flip.

LWJGL first person camera using jBullet

I've got a camera set up, and I can move with WASD and rotate the view with the mouse. But now comes the problem: I want to add physics to the camera/player, so that it "interacts" with my other jBullet objects. How do I do that? I thought about creating a RigidBody for the camera and storing the position there, so that jBullet can apply its physics to the camera. Then, when I need to change something (the position), I could simply change it in the RigidBody. But I didn't find any methods for editing the position.
Can you push me in the right direction or maybe give me an example source code?
I was asking the same question myself a few days ago. My solution was as Sierox said. To create a RigidBody of BoxShape and add that to the DynaicsWorld. To move the camera arund, apply force to its rigidbody. I have damping set to .999 for linear and 1 for angular to stop the camera when no force is applied, i.e. the player stops pressing the button.
I also use body.setAngularFactor(0); so the box isn't tumbling all over the place. Also set the mass really low as not to interfere too much with other objects, but still be able to jump on then and run into them, and otherwise be affected by them.
Remember to convert your x,y, and z coordinates to cartesian a plane so you move in the direction of the camera. i.e.
protected void setCartesian(){//set xyz to a standard plane
yrotrad = (float) (yrot / 180 * Math.PI);
xrotrad = (float) (xrot / 180 * Math.PI);
float pd = (float) (Math.PI/180);
x = (float) (-Math.cos(xrot*pd)*Math.sin(yrot*pd));
z = (float) (-Math.cos(xrot*pd)*Math.cos(yrot*pd));
//y = (float) Math.sin(xrot*pd);
}//..
public void forward(){// move forward from position in direction of camera
setCartesian();
x += (Math.sin(yrotrad))*spd;
z -= (Math.cos(yrotrad))*spd;
//y -= (Math.sin(xrotrad))*spd;
body.applyForce(new Vector3f(x,0,z),getThrow());
}//..
public Vector3f getThrow(){// get relative position of the camera
float nx=x,ny=y,nz=z;
float xrotrad, yrotrad;
yrotrad = (float) (yrot / 180 * Math.PI);
xrotrad = (float) (xrot / 180 * Math.PI);
nx += (Math.sin(yrotrad))*2;
nz -= (Math.cos(yrotrad))*2;
ny -= (Math.sin(xrotrad))*2;
return new Vector3f(nx,ny,nz);
}//..
to jump just use body.setLinearVelocity(new Vector3f(0,jumpHt,0)); and set jumpHt to whatever velocity you wish.
I use getThrow to return a vector for other objects i may be "throwing" on screen or carrying. I hope I answered your question and didn't throw in too much non-essential information.I'll try and find the source that gave me this idea. I believe it was on the Bullet forums.
------- EDIT ------
Sorry to have left that part out
once you have the rigid body functioning properly you just have to get it's coordinates and apply that to your camera for example:
float mat[] = new float[16];
Transform t = new Transform();
t = body.getWorldTransform(t);
t.origin.get(mat);
x = mat[0];
y = mat[1];
z = mat[2];
gl.glRotatef(xrot, 1, 0, 0); //rotate our camera on teh x-axis (left and right)
gl.glRotatef(yrot, 0, 1, 0); //rotate our camera on the y-axis (up and down)
gl.glTranslatef(-x, -y, -z); //translate the screen to the position of our camera
In my case I'm using OpenGL for graphics. xrot and yrot represent the pitch and yaw of your camera. the code above gets the world transform in the form of a matrix and for the purposes of the camera you need only to pull the x,y, and z coordinates then apply the transform.
from here, to move the camera, you can set the linear velocity of the rigid body to move the camera or apply force.
Before you read this answer I would like to mention that I have a problem with the solution stated in my answer. You can follow my question about that problem so that you can have the solution too if you use this answer.
So. First, you need to create a new BoxShape:
CollisionShape cameraHolder = new BoxShape(SIZE OF CAMERAHOLDER);
And add it to your world so that it interacts with all the other objects. Now you need to change all the methods about camera movement (not rotation) so that the methods move your cameraHolder but not your camera. Then set the position of your Camera to the position of the cameraHolder.
Again, if you have a problem where you can't move properly, you can check my question and wait for an answer. You also can find a better way of doing this.
If you have problems or did not understand something about the answer, please state it as a comment.

LibGdx How to repeat background?

Few days ago I figured out how to do some scrolling in LibGdx. Now I'm triying to do something related. I want to repeat the background. My scrolling follows a ship (Is an s[ace ship game). In the background there is a space photo loaded as a Texture. When the ship reach the end of the backgorund, It keeps going and there's no background anymore. I have read about wrap but I don't really understand How It works. I did that:
px=new Pixmap(Gdx.files.internal("fondo.jpg"));
background=new Texture(px);
background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
And then, in my render method
spriteBatch.begin();
spriteBatch.draw(background,0,0,500,50);
drawShip();
spriteBatch.end();
Of course It doesn't work, It only draws the background once. I don't know how make this wrap method work. Any help?
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just paint both bck in your render mode.
Like Teitus said, do not load your texture multiple times, ever! Anyway, you where on the right track with the wrapper:
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
Now you can just use the draw method with the source location. The source location is the area you choose to draw on the texture.
batch.draw(texture, x, y, srcX, srcY, srcWidth, srcHeight)
To scroll your texture from right to left all you have to do is increase srcX incrementally. So create a int that increments in the update/render method.
int sourceX = 0;
//render() method
//Increment the variable where to draw from on the image.
sourceX += 10;
//Simply draw it using that variable in the srcX.
batch.draw(YourTexture, 0, 0, sourceX, 0, screenWidth, screenHeight);
Because you are wrapping the texture it will wrap/loop and scroll indefinitely. There might be a issue with the sourceX int if the game runs for a very long time because a int can only hold 2147483647. It takes a while but you can fix it by subtracting the image width each time the number goes over the total image width.
Don't to this, please:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
That will load your big background texture twice. That's a complete waste. If you want to keep your solution at least do:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=bkg1;
Regarding the texture Wrapping. If your texture is 500px wide, and you draw a 500px sprite, you won't see any repetition. If you want it repeated 2 times, draw it 1000px wide with 0-2 texture coordinates.
I'm not sure how spriteBatch handles the call you posted, you could try that one, or may be use the overload that uses a texture region and set your region manually.
I see this is a pretty old question, but I think there is an easier way to accomplish background scrolling. Just use the Sprite class. Here is a snippet I use for layered background images that scroll from right to left.
public class LevelLayer
{
public float speedScalar = 1;
private List<Sprite> backgroundSprites = new ArrayList<Sprite>();
public LevelLayer()
{
}
public void addSpriteLayer(Texture texture, float startingPointX, float y, int repeats)
{
for (int k = 0; k < repeats; k++)
{
Sprite s = new Sprite(texture);
s.setX(startingPointX + (k*texture.getWidth()));
s.setY(y);
backgroundSprites.add(s);
}
}
public void render(SpriteBatch spriteBatch, float speed)
{
for (Sprite s : backgroundSprites)
{
float delta = s.getX() - (speed * speedScalar);
s.setX(delta);
s.draw(spriteBatch);
}
}
}
Then you can use the same texture or series of textures like so:
someLayer.addSpriteLayer(sideWalkTexture1, 0, 0, 15);
someLayer.addSpriteLayer(sideWalkTexture2, 15 * sideWalkTexture1.getWidth(), 0, 7);
I change background repeating sections randomly in code and make new ones or reset existing sets when they go off screen. All the layers go to a pool and get pulled randomly when a new one is needed.
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just draw both bck in your render()

Categories

Resources