My application is made with openGL ES 2.0 on android and i'm having a rather serious problem with object position updates. My game loop is like this, Draw all objects --> update game object positions --> iterate. However, i have 2 different kind of position updates: one kind that is calculation based, that when a value is low or high enough, it will change direction. The other kind is touch based, when the user touch at any position and/or swipes the screen, the object will follow.
Now to the problem. When the user touches the screen and/or swipes, the objects that is supposed to only respond to touch also gets the changing x value of the calculation based objects, and i'm clueless as to why this is since they use entirely different position variables.
The code that follows here is an excerpt from the GLsurfaceView showing how the touch position values are passed into the GL renderer
public boolean onTouchEvent(MotionEvent e){
if(e != null){
if(e.getAction() == MotionEvent.ACTION_DOWN){
x = e.getX();
y = e.getY();
if(_renderer != null){
queueEvent(new Runnable(){
#Override
public void run() {
_renderer.touchInput(x, y);
}
});
return true;
}
}
if(e.getAction() == MotionEvent.ACTION_MOVE){
x = e.getX();
y = e.getY();
if(_renderer != null){
queueEvent(new Runnable(){
#Override
public void run() {
_renderer.touchInput(x, y);
}
});
}
}
The code that follows here is an excerpt from the GL renderer that shows how the touch values enters the renderer and is converted to world coordinates.
public void touchInput(float x, float y){
y = (float)_view[3] - y;
GLU.gluUnProject(x, y, -1.5f, _ModelMatrix, 0, _ProjectionMatrix, 0, _view, 0, touch_to_world_coords, 0);
_world_x = touch_to_world_coords[0] * touch_to_world_coords[3];
_world_y = touch_to_world_coords[1] * touch_to_world_coords[3];
}
Next up is the code that calculates the new position of the non-touch object
public void updateObjectCoords(){
_test_x += 0.05f;
_test_y += 0.05f;
}
and finally the onDrawFrame from the renderer which im using as a game loop.
public void onDrawFrame(GL10 glContext) {
//Tell OpenGL to use this program when rendering.
GLES20.glUseProgram(_current_shaderProgramHandle);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
//Sets the active texture unit to texture unit 0
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//Bind the texture to current unit
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _TextureDataHandle);
//Tells texture uniform sampler to use this texture in the shader by binding it to unit 0
GLES20.glUniform1i(_TextureUniformHandle, 0);
//Draw square, gets coordinates from gluUnproject method
Matrix.setIdentityM(_ModelMatrix, 0);
Matrix.translateM(_ModelMatrix, 0, _world_x, _world_y, -1.0f);
drawSquare();
//Draw square, gets coordinates from updateObjectCoords method
Matrix.setIdentityM(_ModelMatrix, 0);
Matrix.translateM(_ModelMatrix, 0, _test_x, _test_y, -1.0f);
drawSquare();
//GLES20.glUseProgram(_point_shaderProgramHandle);
//drawLight();
updateObjectCoords();
}
edit: noticed my bad explenations so im adding this instead to be more clear what happens when :)
(When cube 1 gets touch input and cube 2 gets coordinates from updateObjectCoords):
Application starts:
everything work as expected, cube 2(updateObjectCoords one) moves as expected.
User touches screen:
cube2 continue to move as its supposed to, cube1(touch controlled) coordinate data seem to get mixed with cube2 as its movements become seemingly twice as large and towards the same direction as cube2, you can still manipulate it a bit but its not very responding.
(Cube2 is made to be static, however updateObjectCoords are still active and is called on every frame to update the value of _test_x and _test_y):
Application starts:
everything is just as expected
User touches screen:
everything works perfectly
So it seems that it is specificly the continually relocating of cube2 thats interfering with the positioning of cube1.
hope this have made matters more clear! :)
Why does the coordinates of one object to be drawn effect all other translateM's? How come all other objects doesnt get effected by the touch coordinates?
I fixed this by just switching the drawing of cube1 with cube2. This seems to have solved everything. Assuming that drawing the touch controlled objects last will end the interference :D
Related
I have two textures drawn in my 2d scene. And I want to drag them each separately. When they are touched and dragged I want both textures to be dragged to each points. How it drag them individually, or is there any other method to implement. as I am a beginner to libgdx.
My code:
public class MyGdxGame implements ApplicationListener{
OrthographicCamera camera;
ShapeRenderer shapeRenderer;
float screenOffset=10,circleRadius=30;
Texture firstTexture;
Texture secondTexture;
float firstTextureX;
float firstTextureY;
float secondTextureX;
float secondTextureY;
float touchX;
float touchY;
SpriteBatch batch;
#Override
public void create()
{
firstTexture= new Texture("b1.jpg");
firstTextureX = 50;
firstTextureY = 50;
secondTexture = new Texture("b2.jpg");
secondTextureX = 250;
secondTextureY = 250;
batch = new SpriteBatch();
camera=new OrthographicCamera();
shapeRenderer=new ShapeRenderer();
shapeRenderer.setAutoShapeType(true);
}
#Override
public void render()
{
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin();
shapeRenderer.setColor(Color.RED);
shapeRenderer.circle(camera.viewportWidth/2,camera.viewportHeight/2,circleRadius);
shapeRenderer.rect(screenOffset,screenOffset,camera.viewportWidth-2*screenOffset,camera.viewportHeight-2*screenOffset);
shapeRenderer.line(screenOffset,screenOffset,camera.viewportWidth-screenOffset,camera.viewportHeight-screenOffset);
shapeRenderer.line(screenOffset,camera.viewportHeight-screenOffset,camera.viewportWidth-screenOffset,screenOffset);
shapeRenderer.line(screenOffset,camera.viewportHeight/2,camera.viewportWidth-screenOffset,camera.viewportHeight/2);
shapeRenderer.line(camera.viewportWidth/2,screenOffset,camera.viewportWidth/2,camera.viewportHeight-screenOffset);
shapeRenderer.end();
batch.begin();
batch.draw(firstTexture, firstTextureX, firstTextureY);
batch.draw(secondTexture, secondTextureX, secondTextureY);
batch.end();
}
Well, you should save the current position of the texture, and on the update, move the texture checking the movement of the mouse if the mouse right click is active. This is the general idea, valid for any framework or code.
I recommend you to move the texture to their own class, with a getter and a setter of the position and the texture, so it's easy to manage.
Using libdgx you can check if the mouse is clicked at any time with
Gdx.input.justTouched();
On every update you can check what was the last position of the mouse and calculate the difference with the new position on every update using
Gdx.input.getX()
Gdx.input.getY()
To syncronize the position inside your screen with the position on your camera you should use unproject on your camera, for example:
Vector3 mousePos = new Vector3();
mousePos.x = Gdx.input.getX();
mousePos.y = Gdx.input.getY();
mousePos.z = 0;
camera.unproject(mousePos); //this will convert the screen position to your camera position
TL;DR you need to check what was the last position of the mouse when it was clicked, and on the next update calculate the difference, and then you update the position of the texture.
BTW, although this is for when you get more experience, you can create a class that implements InputProcessor, alow the class to be processed by libgdx with, for example:
public class CameraControllerDesktop implements InputProcessor, ControllerListener {
public CameraControllerDesktop() {
Gdx.input.setInputProcessor(this);
}
and the you could use the function
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
to let libgx calculate the position of what you are dragging.
Sorry about not writing the entire solution, but if whit this info you can solve your problem, I'm pretty sure that you sooner or later will be able to make the game you want.
I am using AndEngine GLES1. I have created 2 sprites one is called sphere and the other is called user_sphere.
In the beginning, both are simply attached to the scene. When a certain condition arises, I want to attach the user_sphere as a child to the sphere.
Here is the code that runs to do it:
if(user_sphere_attached == false)
{
Log.d(TAG, "------------DETACHING and RE-ATACHING USER SPHERE-----------");
// Make sure we only do this once
user_sphere_attached = true;
// Detach the user_sphere from the scene
user_sphere.detachSelf();
// Add the user_sphere as a child of the main sphere
user_sphere.setParent(sphere);
// Convert the the scene coordinates of the mini_sphere to the local coordinates of the sphere
float[] coordinates = { sphere.getX(), sphere.getY() };
float[] localCoordinates = sphere.convertSceneToLocalCoordinates(coordinates);
// Reposition and scale the user_sphere to see if it shows up
user_sphere.setPosition(localCoordinates[0]+80, localCoordinates[1]+80);
user_sphere.setScale(5.0f);
}
}
However, when that block of code runs, the user_sphere simply disappears from the screen.
Any idea of what I might be doing wrong?
Thanks!!
I have a problem scrolling my childscene. I have created a CameraScene which i am trying to scroll with a touch event. My childscene is not scrolling, however, if i scroll on the camera attached to the engine the parent scene scrolls fine.
So how do i get my child scene to scroll without the objects attached to myparents scene scrolls along?
public StatsScene(Context context, VertexBufferObjectManager vbo) {
super(new SmoothCamera(0, 0, WITDH, HEIGHT, 0, SPEEDY, 0));
this.setOnSceneTouchListener(new IOnSceneTouchListener() {
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if(pSceneTouchEvent.getAction() == MotionEvent.ACTION_DOWN) {
mTouchY = pSceneTouchEvent.getMotionEvent().getY();
}
else if(pSceneTouchEvent.getAction() == MotionEvent.ACTION_MOVE) {
float newY = pSceneTouchEvent.getMotionEvent().getY();
mTouchOffsetY = (newY - mTouchY);
float newScrollX = getCamera().getCenterX();
float newScrollY = getCamera().getCenterY() - mTouchOffsetY;
getCamera().setCenter(newScrollX, newScrollY);
mTouchY = newY;
}
return true;
}
});
}
I'm not really into AndEngine and I'm not sure if I get your problem right (in your code is nothing about "myparents" or "childscene"), but when something is attached to your scene, then this implies it will move with it. You could scroll your children in the other direction to maintain their position, but that could get you into trouble in the longterm. If it is possible, try to seperate your scrolling scene and your objects, meaning, that they shouldn't be children of each other. Instead, if you want them to keep them related, give them a common parent. If you move one object now, the siblings won't. Hope that helps.
From your description I would think that your parent scene is the one getting your the input so I'm guessing, please correct me if I'm wrong, that you are setting your child scene something like this:
mMainScene.attachChild(mChildScene);
In this case you will have to deal with deviating the input to the child instead of the parent. However, you have a few options here:
If your child scene occupies full screen and you don't need to worry about updating/drawing your parent scene, simply swap scenes with
mEngine.setScene(mChildScene);
If you do need to keep drawing and updating your parent scene check the MenuScene pre-made class and Scene.setChildScene() method, there is one example on how using this in the AndengineExamples project I think. Using this class will let you take the input on the child scene but still drawing and updating your main scene, it even let's you set your child in a modal way.
I have customized BoundCamera and have overrided the update method as:
#Override
public void onUpdate(float pSecondsElapsed) {
// TODO Auto-generated method stub
super.onUpdate(pSecondsElapsed);
if(chaseEntity != null) {
tempHeight = (chaseEntity.getY() * PIXEL_TO_METER_RATIO_DEFAULT) + PlayLevelActivity.CAMERA_HEIGHT/2;
if(tempHeight < heightCovered) {
setBounds(0, 0, PlayLevelActivity.CAMERA_WIDTH, tempHeight);
heightCovered = tempHeight;
}
}
}
and have initialized the camera as:
mCamera = new MyBoundCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT, 0, CAMERA_WIDTH, 0, CAMERA_HEIGHT);
I want to keep chase entity in center all time. Now the problem I am facing is that in start, the camera chases the entity. As the entity goes higher and higher, it goes beyond screen bounds in y direction. I am updating camera bounds in on update method to keep entity always in center but not working. The chaseEntity.getY() gets the physics body y position. Does anyone know where I am going wrong?
If you use
this.mBoundChaseCamera.setChaseEntity(Sptite);
setBoundsEnabled(false);
then the sprite will still be in the center of the screen all the time. The downside is that the sprite can go beyond the bounds. You would have to implement your own method to keep the sprite within the bounds.
In the comments you mentioned that at some point you want the sprite to fall but don't want it to remain in the center while it is falling. You could just use
this.mBoundChaseCamera.setChaseEntity(null);
then drop the sprite to the bottom of the screen. That should provide an effect similar to papi jump.
I'm learning to use libgdx with universal-tween-engine and haven't been able to figure out how to touch (or click on the desktop app) a point on the screen and have a texture move all the way to the touched location without keeping the touch or click active until the end-point is reached.
When the touch event is initiated, the animation begins and the graphic moves towards the location. The graphic will follow the finger/mouse-pointer if a touch and drag is initiated. If I touch a point, the graphic will move towards the point until the touch is released. Then it stops where it was when touch is released.
I'm looking to touch-and-release and have that graphic move to the touched point, and am probably not understanding something about the tween engine implementation. I've pasted the tweening code below.
public void render() {
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(texture.getTexture(), texture.getBoundingBox().x, texture.getBoundingBox().y);
batch.end();
Tween.registerAccessor(Plane.class, new TextureAccessor());
TweenManager planeManager = new TweenManager();
float newX = 0;
float newY = 0;
boolean animateOn = false;
if(Gdx.input.isTouched()) {
newX = Gdx.input.getX();
newY = Gdx.input.getY();
animateOn = true;
}
if (animateOn == true && (texture.getX() != newX || texture.getY() != newY)) {
Tween.to(texture, TextureAccessor.POSITION_XY, 10)
.target(newX, newY)
.ease(TweenEquations.easeNone)
.start(planeManager);
planeManager.update(1);
if (texture.getX() == newX && texture.getY() == newY) {
animateOn = false;
}
}
}
Originally, I had the tweening code inside the conditional for isTouched() and didn't use the newX, newY or animateOn variables. I thought using isTouched() to only set the new coordinates and animation state would then make the loop trigger the tween. The older code looked like this:
if(Gdx.input.isTouched()) {
newX = Gdx.input.getX();
newY = Gdx.input.getY();
Tween.to(texture, TextureAccessor.POSITION_XY, 10)
.target(newX, newY)
.ease(TweenEquations.easeNone)
.start(planeManager);
planeManager.update(1);
}
I've also tried using justTouched(), but the graphic would only move very slightly toward the touched point.
I've been struggling with this for a few hours, I'd really appreciate it if anyone could point me in the right direction.
Thanks.
Tween.registerAccessor(Plane.class, new TextureAccessor());
TweenManager planeManager = new TweenManager();
These two lines should go in the create() method, not the render() one! Here, you're instantiating a new manager on every frame, you only need one manager, that's all, not an army of them!
Also, you need to update the manager on every frame, not just when animateOn is true, else you'll need to keep your finger pressed...
The correct code is as follows, learn from it, you'll get a better understanding of how the Tween Engine works :)
// Only one manager is needed, like a Spritebatch
private TweenManager planeManager;
public void create() {
Tween.registerAccessor(Plane.class, new TextureAccessor());
planeManager = new TweenManager();
}
public void render() {
// The manager needs to be updated on every frame.
planeManager.update(Gdx.graphics.getDeltaTime());
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(texture.getTexture(), texture.getBoundingBox().x, texture.getBoundingBox().y);
batch.end();
// When the user touches the screen, we start an animation.
// The animation is managed by the TweenManager, so there is
// no need to use an "animateOn" boolean.
if (Gdx.input.justTouched()) {
// Bonus: if there is already an animation running,
// we kill it to prevent conflicts with the new animation.
planeManager.killTarget(texture);
// Fire the animation! :D
Tween.to(texture, TextureAccessor.POSITION_XY, 10)
.target(Gdx.input.getX(), Gdx.input.getY())
.ease(TweenEquations.easeNone)
.start(planeManager);
}
}
I was trying to implement this behavior in the wrong way. Instead of using isTouched or justTouched(), I needed to use touchDown() from GestureListener.
I created a class that implemented GestureDetector (call it touchListener())inside of my main class (the one that implements ApplicationLisetener )in the main libgdx project and put the x and y capturing code inside of toucDown (I noticed tap() was also being triggered). I moved the tween functions (the actual tweening, the call to registerAccessor(), and the creation of the new tween manager) into the update() method of touchListener().
I added a call to touchListener()'s update function inside the render() loop of the main libgdx class.
I doubt I did this is the best way, but I hope it's helpful to someone else in the future.