i have been testing to create a function which would do something, if two objects touch(if one contains or it is just touching the another one). I found this:
public boolean inBounds(float cx, float cy, int size)
{
Rectangle rec1 = new Rectangle(x, y, this.size, this.size);
Rectangle rec2 = new Rectangle(cx, cy, size, size);
if(rec1.contains(rec2)) return true;
return false;
}
}
So, this is a touch function in my Entity class. So, in my update function which i am calling in render function, i have:
if (e instanceof Worm && player1.inBounds(e.x, e.y, e.size))
{
entities.remove(i); //remove object from the scene
i--;
player1.incScore(); //increase score
}
This works perfectly, but only if my charracter is biger than that object, i need it everytime, no only if charracter is biger than object. So what to do now? i Found a function that i can use like if (rec1.overlaps(rec2)) return true; but now, it works, yes.. but the texture of my object is not so ultimate(this is the object: http://img24.cz/images/08705660216361901876.png ), so it looks bad. if the object is near the player, it activates my function, i want to have it only if the object is in the player, so i can create better texture, which is really hard for me, or i can ... I dont know what i can to do, so, help me please. :D
Ok.
First.
Use temporary rectangles, don't create new one every frame!
You are checking rectangle.contains(otherRectangle); which tells you if otherRectangle is inside the rectangle.
You want to check if the rectangle overlaps the other one.
private Rectangle tmpRect1=new Rectangle();
private Rectangle tmpRect2=new Rectangle();
And in your method
public boolean inBounds(float cx, float cy, int size)
{
tmpRect1.set(x, y, this.size, this.size);
tmpRect2.set(cx, cy, size, size);
return tmpRect1.overlaps(tmpRect2); // returns true if rectangles are overlapping, and false if not
}
Yes, but it doesnt fix my problem. my problem was that, that if i am using the overlaps function, it looks unreal. Because(look at http://img24.cz/images/08705660216361901876.png ), you can see that the top of the image is clean, there is not my fish, my fish is only in the middle of image, so it looks bad, if the player is under or over the fish, it gives me a score(because it is overlapping(because of that non-ultimate image)). The contain function was better, because it looked reallistic. So i wanted a help, how do i can make it better.
Related
I have a libgdx application that contains a class Button. The constructor of Button takes three arguements: Filename of graphics, position, and game (the latter being used for callbacks of various sorts).
The button scales itself based on the graphics provided, thus setting its width and height based on the properties of the graphics.
The main class, Game, when a click is detected compares the coordinates of the click up against the coordinates of the button combined with its width and height.
Now, the main issue is that there is a little bit of a horizontal offset between the button and the click coordinates, so the effect is that the graphics show up a few pixels to the right of the clickable area. I cannot for the life of me figure out the source of this discrepancy, so I would greatly appreciate some fresh eyes to see where I'm going wrong here.
Button, constructor and polling-method for clickable area.
public Rectangle getClickArea() {
return new Rectangle(pos.x - (img.getWidth() / 2), pos.y + (img.getHeight() / 2), w, h);
}
public Button(String assetfile, int x, int y, Game game) {
this.game = game;
img = new Pixmap(new FileHandle(assetfile));
pos = new Vector2(x, y);
this.w = img.getWidth();
this.h = img.getHeight();
}
A relevant snippet from InputHandler. It listens for input and passes on the event. Please note that the vertical click position is subtracted from the vertical size of the screen, as vertical 0 is opposite in InputHandler:
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
tracker.click(screenX, Settings.windowSize_Y - screenY);
return false;
}
ClickTracker (referenced as tracker in the above snippet), the Class that does the actual comparison between clicks and clickables:
public void click(int x, int y) {
Vector2 clickPos = new Vector2(x, y);
for (Tickable c : world.getPaintables())
{
if (!(c instanceof Unit))
continue;
if (((Clickable)c).getClickArea().contains(clickPos)) {
System.out.println("Clicked on unit");
}
}
for (Clickable c : clickables)
{
if (c.getClickArea().contains(clickPos)) {
c.clicked(x, y);
}
}
In short: The vertical alignment works as intended, but the horizontal is slightly off. The button graphics appear maybe around 10-20 pixels to the right of the clickable area.
I'll gladly post more info or code if needed, but I believe I have the relevant parts covered.
Edit:
As Maciej Dziuban requested, here's the snipped that draws the UI elements. batch is a SpriteBatch as provided by libgdx:
for (Paintable p : ui) {
batch.draw(new Texture(p.getImg()), p.getImgPos().x, p.getImgPos().y);
}
the getImgPos() is an interface method implemented by all drawable items:
public Vector2 getImgPos() {
return new Vector2(pos.x - (getImg().getWidth() / 2), pos.y);
}
It's worth noting that half of the horizontal image size is subtracted from the X pos, as X pos refers to the bottom center.
You have inconsistency in your position transformations:
Your clickArea's corner is pos translated by [-width/2, height/2] vector.
Your drawArea's corner is pos translated by [-width/2, 0] vector
They clearly should be the same, so if you want your pos to represent bottom-center of your entity (as you've explicitly stated) you have to change your getClickArea() method to, so it matches getImgPos().
public Rectangle getClickArea() {
return new Rectangle(pos.x - (img.getWidth() / 2), pos.y, w, h);
}
Side note: as Tenfour04 noticed, you create new texture each frame and this is huge memory leak. You should make it a field initialized in constructor or even a static variable given some buttons share the texture. Don't forget to call dispose() on resources. For more powerful asset management check out this article (note it may be an overkill in small projects).
I'm trying to make a simple bit of code that will detect whether a model was clicked on. So far the best method I've seen is to create some sort of rectangle around the mesh and detect with Gdx.input.justTouched() to get the x,y coordinates, and then check if the rectangle contains the coordinates returned by justTouched().
I have no idea if there's a better way to do this, some kind of mesh onClick listener or something that LibGDX has in place that I'm unaware of (I've been scouring Google and the javadocs but I can't seem to find anything). I don't really need to deal with the z-axis coordinate, at least I don't think so. I only have the one PerspectiveCamera and it's not going to be moving around that much (not sure if this matters?)
Anyways, in my render() method I have:
if (Gdx.input.justTouched()) {
//this returns the correct values relative to the screen size
Vector2 pos = new Vector2(Gdx.input.getX(), Gdx.input.getY());
//I'm not sure how to get the correct rectangle to see what the
//width and height are for the model relative to the screen?
Rectangle modelBounds = new Rectangle(<<not sure what to put here>>);
if (modelBounds.contains(pos.x, pos.y) {
System.out.println("Model is being touched at: " + pos.x + ", " + pos.y);
}
}
I'm really not sure if this is the correct way to do this. I can get the position of the model with:
modelInstance.getNode("Node1").globalTransform.getTranslation(new Vector3());
but I'm not sure how to get the width and height as a rectangle relative to the screen size, if it's even possible.
I'm also unsure if this would cause massive lag, as I'm going to have about 7 nodes total that I need to detect if they're clicked on or not.
Is there a better way to do this? If not, is there a way to get the model width & height relative to the screensize (or camera, maybe)?
EDIT: Read about using Bounding Boxes, seems like what I need. Not quite sure how to implement it properly, however. I've changed my code to such:
public ModelInstance modelInstance;
public BoundingBox modelBounds;
#Override
public void create() {
...
//omitted irrelevant bits of code
modelInstance = new ModelInstance(heatExchangerModel);
modelBounds = modelInstance.calculateBoundingBox(new BoundingBox());
}
#Override
public void render() {
...
if (Gdx.input.justTouched()) {
Vector3 pos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
System.out.println(pos);
if (modelBounds.contains(pos)) {
System.out.println("Touching the model");
}
}
}
I'm not really sure what the output of BoundingBox is supposed to be, or how the numbers it gives me correlates to the position in a 2d space. Hmm..
EDIT2: Think I'm getting closer.. Read about Rays and the .getPickRay method for my PerspectiveCamera. .getPickRay seems to return completely unusable numbers though, like really tiny numbers. I think I need to do something like:
if (Gdx.input.justTouched()) {
Vector3 intersection = new Vector3();
Ray pickRay = perspectiveCamera.getPickRay(Gdx.input.getX(), Gdx.input.getY());
Intersector.intersectRayBounds(pickRay, modelBounds, intersection);
}
and then intersection should give me the point where they overlap. It appears to be not working, however, giving me really small numbers like (4.8066642E-5, 2.9180354E-5, 1.0) .. hmmm..
I am currently trying to make a selector box for an RTS game. For this I need to be able to drag the mouse in order to create the selection box, however this can lead to a negative length/width.
In Libgdx is there a way to make rectangle from just using 2 sets of coordinates?
Thanks.
this is a simple idea, if I understand what you want to do:
to create a rectangle you can use this, Rectangle(float x, float y, float width, float height) for more inforamacion you can read it here http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Rectangle.html
this a psuedo code more or less:
create a listener that captures keystrokes, mouse or them as appropriate,
in touchdown catches x, y, and assign a:
yourVariableTouchDown.x = x;
yourVariableTouchDown.y = y;
then when the touchup captures the x is executed, and the point where it makes up touch and assign a:
yourVariableTouchUp.x = x;
yourVariableTouchUp.y = y;
after create the rectagle:
private Rectangle yourRectangle = new Rectangle();
yourRectangle(yourVariableTouchDown.x, yourVariableTouchDown.y,
(yourVariableTouchDown.x - yourVariableTouchUp.x),
(yourVariableTouchDown.y - yourVariableTouchUp.y));
if you want to see it you can use ShapeRenderer:
look this http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/glutils/ShapeRenderer.html
add for test in variable class
private ShapeRenderer sRDebugRectangel = new ShapeRenderer();
add for test in update or draw
sRDebugRectangel.begin(ShapeType.Filled);
sRDebugRectangel.identity();
sRDebugRectangel.rect(yourRectangle.getX(),
yourRectangle.getY(),
yourRectangle.getWidth(),
yourRectangle.getHeight());
sRDebugRectangel.end();
you can look on that listener use:
https://www.google.es/#q=listener+libgdx
P.S: what you say negative, will be a matter of check when touchup is less than touchdown change where the rectangle is created that was just what I happened to you have test it and adjust the variables to create the rectangle now because you can not be created desirably when negative, now I have time to get with it, in fact eh not tested this why I said it was pseudo code, hope you serve, idea
P.S: You can also look at this https://stackoverflow.com/tour
I'm trying to determine whether two rectangles border each other. If they share an edge or part of an edge, then I want to include them, if they only share a vertice then I don't.
I've tried using android android.graphics.Rect, I was hoping that the intersect method would return true giving me a rectangle, with 0 width but the points of the intersecting edge. I'm using andEngine and also tried the collideswith method of org.andengine.entity.primitive.Rectangle however that returns true, even if the rectangle only share one corner vertice.
Is there a nice way of doing this? The only other way I can think of is to try and create a collection of all the edges then see if they're equal or are in someway partly equal.
Here's an image to demonstrate what I want. If I click on rect 1 then I want to return rects 2,3 and 4, but not 5.
"Map":
It sounds like you need a new class to do this. I would take the coordinates of each corner of the rectangles. Then, when you are selecting a rectangle, you can get those adjacent to it by finding them one side at a time. Starting with the top for an example, you check which other rectangles have corners at the same height. From that list, you check to see which ones exist on at least one point between the two top corners. So, if top left is 0,3 and top right is 4,3 then you would look for the list of corners at y=3. From that list you find all corners where 0<=x<=4 and anything that fits will be adjacent. You then do the same thing for each additional side. It should be an easy class to make, but I am not going to write any code as I do not know anything about how you stored your data or how you would reference this in your code. If you need help with that, write a comment.
Write a function to find which rectangles share edges with rectangles within all considered rectangles.
Then, map these rectangles which share edges to one another. An Adjacency List is just a way of representing a graph in code.
Sometimes code is easier to understand, so here's code. I have not tested this, but it should get you most the way there.
Also, I'm not sure what you're end goal is here but here's a question I answered that deals with rectangular compression.
List<Rectangle> allRectangles;
public boolean shareAnEdge(Rectangle r1, Rectangle r2){
int y1 = r1.y + r1.height;
int y2 = r2.y+r2.height;
int x1 = r1.x+r1.width;
int x2 = r2.x+r2.width;
boolean topShared = (y1 == r2.y && r2.x == r1.x);
boolean bottomShared = (y2 == r2.y && r2.x==r1.x);
boolean rightShared = (x1 == r2.x && r2.y==r1.y);
boolean leftShared = (x2 == r1.x && r2.y==r1.y);
if (topShared || bottomShared || rightShared || leftShared) {
return true;
}
return false;
}
public List<Rectangle> findSharedEdgesFor(Rectangle input){
List<Rectangle> output = new List<Rectangle>();
for(Rectangle r : allRectangles){
if(r!=input && shareAnEdge(r, input)){
output.add(r);
}
}
}
public AdjacencyList createGraph(List<Rectangle> rectangles){
AdjacencyList graph = new AdjacencyList();
for(Rectangle r : rectangles){
List<Rectangle> sharedEdges = findSharedEdgesFor(r);
for(Rectangle shared : sharedEdges){
graph.createEdgeBetween(r, shared);
}
}
}
I have some sprite objects at different positions on the screen. When I draw a shape around one or several of those objects, I want to know which object that are inside. For this I'm using the Region class and the contains() method. The drawn shape is stored as a path. For now I have only made some code to check for any the objects position, but it's not working? It seems like it's not finding any positions despite that I have a shape around them. What have I done wrong? Or is there a better way?
// Create path
path.moveTo(touchDownX, touchDownY);
for(Point point: points) {
path.lineTo(point.x, point.y);
}
// Draw path
canvas.drawPath(path, paint);
Region region = new Region();
region.setPath(path, region);
// Loop throw all circle objects
for (int i=0; i<5;i++) {
int x = circleManager.getCirclePositionX(i);
int y = circleManager.getCirclePositionY(i);
if(region.contains(x, y))
Log.i("YES!", "");
}