My Orthographic camera is initialized to be size 540x960 (the size of my HTC One screen). However, when I try it on another phone with a larger screen, whenever I tap to move my Texture, there is an offset from where I touch and where the Texture moves to. Should I use a different sizing technique? Such as size it by Gdx.graphics.getWidth() and .getHeight()?
From comment below:
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
xpos = x;
return false;
}
You are only getting the screen's x position. To convert it to world space (the coordinate system of your game), you need to put it into a Vector3 and unproject it from the camera like this:
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
Vector3 touchPoint = new Vector3(x, y, 0); //0 is arbitrary since this is in 2D
camera.unproject(touchPoint); //now touchPoint contains the world position of the touch
xpos = touchPoint.x;
ypos = touchPoint.y; //if you need it.
return false;
}
Related
I have a picture then used a flashlight type of light to only show where the mouse is hovering over. That part of the code works, but now I want to use if/else statements to zoom in on the selected area and then click again to zoom back out. Any other way to zoom in on specific area then back out of that area also helps. Really any help will be appreciated!
PImage ispy;
void setup () {
size(1024,768);
ispy = loadImage("ispy2.jpeg");
}
void draw () {
loadPixels();
ispy.loadPixels();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int loc = x+y*width;
float r = red(ispy.pixels[loc]);
float g = green(ispy.pixels[loc]);
float b = blue(ispy.pixels[loc]);
float d = dist(mouseX, mouseY, x, y); //
float factor = map(d, 0, 200, 2, 0);
pixels[loc] = color(r*factor, g*factor, b*factor);
}
}
updatePixels();
}
Here is my interpretation of what you are talking about. We store a isClicked boolean to store the state of whether we should zoom in or not. When we are going to draw the image, we translate() to the mouse, then we scale(), then we translate() back the same amount that we moved before, but in the opposite direction. What this does is it does the scale transform around the mouse position.
One thing that I couldn't find a way around way your way of updating the pixels directly from the image and the flashlight effect. What the program is doing instead is using your method to make a mask image and applying that to a PGraphics object. Another thing that I noticed is that when just rendering straight to the screen, there is considerable lag from the scaling. Instead, I have moved the drawing to a PGraphics object. This improves the performance.
In the end, to render, the program is drawing everything on the PGraphics object, then applying the mask to that object to get the flashlight effect.
Here is the code that I have:
PImage ispy, distMask;
boolean isClicked = false;
PGraphics renderer;
void createDistanceMask(PImage distMask){ //Takes image and changes its pixels to "alpha" for the PGraphics renderer
distMask.loadPixels();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int loc = x+(height-y-1)*width;
float d = dist(mouseX, mouseY, x, y); //
int factor = int(map(d, 0, 200, 400, 0)); //Pixel data will be between 0 and 255, must scale down later.
if (factor > 255)
factor = 255;
distMask.pixels[loc] = color(factor,factor,factor);
}
}
distMask.updatePixels();
}
void setup () {
size(1024,768, P2D);
ispy = loadImage("ispy2.jpeg");
distMask = new PImage(width,height);
renderer = createGraphics(width,height,P2D);
mouseX = width/2; //Not necessary, but will have black screen until mouse is moved
mouseY = height/2;
}
void draw () {
background(0);
pushMatrix();
createDistanceMask(distMask);
renderer.beginDraw(); //Starts processing stuff into PGraphics object
renderer.background(0);
if(isClicked){ //This is to get the zoom effect
renderer.translate(mouseX, mouseY);
renderer.scale(2);
renderer.translate(-mouseX, -mouseY);
}
renderer.image(ispy,0,0); //Render Image
renderer.endDraw();
renderer.mask(distMask); //Apply Distance mask for flashlight effect
image(renderer,0,0); //Draw renderer result to screen
popMatrix();
}
void mouseClicked(){
isClicked = !isClicked;
}
In my comment, I asked about having the screen move to the mouse, which is what this is doing. If you want to "freeze" the screen in one position, what you can do is store a lastMouseClickPosition PVector or simply just ints. Then, when translating, translate to the position instead of the PVector.
Here's the code that would change:
PVector lastClickPos = new PVector(); //Make the position
if(isClicked){ //When Rendering
renderer.translate(lastClickPos.x, lastClickPos.y);
renderer.scale(scalingFactor);
renderer.translate(-lastClickPos.x, -lastClickPos.y);
}
void mouseClicked(){ //At the bottom
isClicked = !isClicked;
lastClickPos.set(mouseX, mouseY);
}
I am programming a 2d platformer with libgdx, I'm trying to make a menu screen where the player can click a button and it will load that level. I use gdx.input for the click coordinates and TextureRegion.getRegionX() for the button coordinates. They don't sync together and I read that camera.unproject should fix this problem. I duly used it but the coords still don't match. camera.unproject seems to set 0,0 for x and y as the centre of the screen, while batch.draw (which is the method which draws the TextureRegion to screen) seems to be using the bottom left hand corner as x and y's 0, 0.
Here is the code, I left out what I didn't think was relevant:
public class LevelScreen implements Screen {
private TextureRegion level_bg;
private SpriteBatch batch;
private Camera camera;
private TextureAtlas textureAtlas;
private TextureRegion lockselectbg[]=new TextureRegion[10];
public LevelScreen(){
}
#Override
public void show() {
batch=new SpriteBatch();
camera = new OrthographicCamera(500,700);
LevelStatus.put();
LevelStatus.get();
textureAtlas=new TextureAtlas(Gdx.files.internal("levelatlas.pack"));
Array<AtlasRegion> atlasArrays = new Array<AtlasRegion>(textureAtlas.getRegions());
level_bg = atlasArrays.get(0);
lockselectbg[0] = atlasArrays.get(21);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(159/255.0f,220/255.0f,235/255.0f,0xff/255.0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(level_bg, -500/2,-348/2);
batch.draw(lockselectbg[0], -180,0);
batch.end();
if(Gdx.input.isTouched()){
Vector3 tmp = new Vector3(Gdx.input.getX(),Gdx.input.getY(), 0);
camera.unproject(tmp);
Rectangle textureBounds = new Rectangle(lockselectbg[0].getRegionX(), lockselectbg[0].getRegionY(), lockselectbg[0].getRegionWidth(), lockselectbg[0].getRegionHeight());
if(textureBounds.contains(tmp.x, tmp.y)) {
System.out.println("It worked");
}
}
}
#Override
public void dispose() {
textureAtlas.dispose();
batch.dispose();
}
Camera#unproject will convert touch coordinates to world coordinates. They have nothing to do with the location of the region on the texture, which is what TextureRegion is. You are practically comparing world (read: game logic) coordinates with asset coordinates. Those two are completely unrelated.
If you want to check whether your image on the screen is touched then compare the touch coordinate with the location and size of the image you used in the batch.draw call. For example:
float x = -180f;
float y = 0f;
float width = 200f;
float height = 150f;
...
batch.draw(region, x, y, width, height);
...
camera.unproject(tmp.set(Gdx.input.getX(),Gdx.input.getY(), 0));
boolean touched = tmp.x >= x && tmp.y >= y && tmp.x < (x + width) && tmp.y < (y + height);
if (touched)
System.out.println("It worked");
Btw, you might want to read this post: http://blog.xoppa.com/pixels as well, because you are coupling your logic with asset size.
I want an object to move away from the position of a touch event.
So far I have the following:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector3 touchPosition = new Vector3();
camera.unproject(touchPosition.set(screenX, screenY, 0));
Vector2 directionBody = body.getPosition();
Vector2 directionTouch = new Vector2(touchPosition.x, touchPosition.y);
Vector2 direction = directionBody.sub(directionTouch);
direction.nor();
float speed = 3;
body.setLinearVelocity(direction.scl(speed));
return true;
}
Using this code if I press at the right side of the screen the body moves to the left. If press at the left side of the screen the body will go to the right side. Could someone help me out please?
Your code is a bit fuzzy to me, maybe because you are using classes I don't but generally it's simple:
First you unproject touch coordinates to screen coordinate system, where your body object is, like you did.
Second calculate horizontal and vertical distance between touch place and your body object. Let's say you get dx and dy.
If you want constant speed you just have to check are those dx and dy positive or negative and depending on that you set positive or negative speed, i.e.:
if (dx >0) vx = SPEED_CONSTANT;
else vx = -SPEED_CONSTANT;
Same goes for vertical speed.
If you want your body to accelerate you should use those dx and dy multiplied with some constant. That is, the bigger dx is the higher vertical speed should be. Same goes for vertical speed:
vx = dx * SPEED_CONSTANT;
vy = dy * SPEED_SONSTANT;
If you want your body to decelerate then you should devide some constant value with those dx and dy, to have opposite effect:
vx = SPEED_CONSTANT / dx;
vy = SPEED_CONSTANT / dy;
Something like that. You can set value of that SPEED_CONSTANT by trying some values - tune it up.
I hope this will help.
So I finally did it.
Code snippet:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector3 touchPosition3D = new Vector3();
//Change touch coordinates to world coordinates
camera.unproject(touchPosition3D.set(screenX, screenY, 0));
//Add unit factor to the vector
touchPosition3D.x = Utility.convertToMeter(touchPosition3D.x);
touchPosition3D.y = Utility.convertToMeter(touchPosition3D.y);
Vector3 bodyPosition = new Vector3(body.getPosition().x, body.getPosition().y, 0 );
Vector3 finalVector = new Vector3(bodyPosition.x, bodyPosition.y, 0).sub(touchPosition3D);
Vector2 direction = new Vector2(finalVector.x, finalVector.y);
float speed = 3;
body.setLinearVelocity(direction.scl(speed));
return true;
}
Basically I had to unproject the touchDown coordinates and convert them to the units I'm using in my application.
Then I do a simple Vector operation, subtracting the calcualted touch vector drom the vector of my body.
Finally apply some linear velocity.
I override the pan method in ActorGestureListener to implement dragging actors in libgdx (scene2d).
When I move individual pieces on a board they move smoothly, but when moving the whole board, the x and y coordinates that is sent to pan is "jumping", and in an increasingly amount the longer it is dragged.
These are an example of the deltaY coordinates sent to pan when dragging smoothly downwards:
1.1156368
-0.13125038
-1.0500145
0.98439217
-1.0500202
0.91877174
-0.984396
0.9187679
-0.98439026
0.9187641
-0.13125038
This is how I move the camera:
public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) {
cam.translate(-deltaX, -deltaY);
I have been using both the delta values sent to pan and the real position values, but similar results. And since it is the coordinates that are wrong, it doesn't matter whether I move the board itself or the camera.
What could the cause be for this and what is the solution?
EDIT
When I move camera only half the delta-values, it moves smoothly but only at half the speed of the mouse pointer:
cam.translate(-deltaX / 2, -deltaY / 2);
It seems like the moving of camera or board affects the mouse input coordinates. How can I drag at "mouse speed" and still get smooth movements?
I'm aware this is really late and you've probably already solved the problem but for future readers:
This forum post helped me: http://badlogicgames.com/forum/viewtopic.php?f=11&t=12343
If you move the camera while part way through a pan or ANY gesture the coordinate system being used for the x and y coordinates is changed and that's why you get the jumpy deltas alternating between +ve and -ve values.
The fix I used is to not use the pan() gesture and implement it like so:
private Vector3 prevDragPos;
addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
}
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
x = Gdx.input.getX(pointer);
y = Gdx.input.getY(pointer);
if(prevDragPos == null) prevDragPos = new Vector3(x, y, 0);
getStage().getCamera().position.add(prevDragPos.x - x, y - prevDragPos.y, 0);
prevDragPos.set(x, y, 0);
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
prevDragPos = null ;
}
});
Gdx.input.getX() and Gdx.input.getY() don't get converted to camera coordinates so using them fixes the problem.
it's because you're using translate. Try this:
public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) {
camera.position.add((-x), (y), 0);
camera.update();
}
ok guys i want to rotate a PVector that i have in this method.
this method replaces the posX and posY by the x and y of the PVector.
the movement is determinated by a joystick that comes from arduino it moves the image in x and y but i would like to turn the vector depending on the axis the joystick is looking
public void moverPjUno(PVector coordenadas) {
if(areaXad==-1 && areaXat==-1){
miPersonaje.setPosX((miPersonaje.getPosX())+(int)coordenadas.x);
}
if(areaYab==-1 && areaYar==-1){
miPersonaje.setPosY((miPersonaje.getPosY())+(int)coordenadas.y);
}
}
I don't have an Arduino hooked up and I don't know what kind of information your joystick is giving you, so I made a Processing example that uses the mouse to imitate the joystick:
int rad = 100;
void setup() {
size(400, 400);
}
void draw() {
background(255);
ellipse(width/2, height/2, rad*2, rad*2);
// Using the mouse to mimic the position of the joystick
float theta = atan2(mouseY-height/2, mouseX-width/2);
// Get the new position
float x = width/2+cos(theta)*rad;
float y = height/2+sin(theta)*rad;
// Show the new position
ellipse(x, y, 30, 30);
}
The atan2 function gives the angle to the mouse position, replace the arguments with the equivalent of the joystick position. The smaller ellipse being drawn shows where your miPersonaje would be set based on x and y earlier in the code. The rad variable is arbitrary and just for displaying purposes, you can set it to be whatever you want (if needed at all).