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.
Related
I am working on slide menu view which extends SurfaceView but when I try to change size of the view a canvas does not change.
For debug purpose, I am changing size of the view calling method:
public void changeSize() {
width += 10;
getLayoutParams().width = width;
this.setLayoutParams(getLayoutParams());
}
Then in a draw function I paint the canvas white and draw red line diagonally across the view:
public void draw() throws Exception {
SurfaceHolder surfaceHolder = getHolder();
if (surfaceHolder.getSurface().isValid()) {
Canvas canvas = surfaceHolder.lockCanvas();
Log.i(TAG, "draw > canvas size: " + canvas.getWidth() + " " + canvas.getHeight() );
paint.setColor(Color.rgb(255,0,0));
paint.setStrokeWidth(5);
canvas.drawColor(Color.rgb(255, 255, 255));
canvas.drawLine(0, getLayoutParams().height, getLayoutParams().width, 0, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
What I see is a white rectangle with fixed size and part of red line:
demo.
Also, when I call this.getWidth() I get unchanged width.
Why view size is not changing? Is it the same reason that the canvas is not changing? What can I do to fix it?
I found reason for myself.
I did not mention about something - that I thought was not important - I called changeSize() via other thread than created the view and this is not allowed because: Only the original thread that created a view hierarchy can touch its views. And this problem was many time solved, e.g. here
I could use Activity.runOnUiThread() method but I did not want to pass the Activity to the view so I use View.post() method in the changeSize() like this:
Runnable changeParams = new Runnable() {
#Override
public void run() {
getLayoutParams().width = width;
setLayoutParams(getLayoutParams());
}
};
this.post(changeParams);
Update:
Maybe I do not know about proper way of using the UI Thread but whatever I tried I can not change view parameters smoothly.
Some workarounds to implement a slide menu:
Do [Android navigation Drawer][4] -- you can custiomize it with restictions e.g. you can not do the navigation drawer moving from top.
Use [Android animations][5] -- with it you can move or scale a view but can not resizing it.
I can not put more than 2 links with my reputation:
(4): developer.android.com/training/implementing-navigation/nav-drawer.html
(5): developer.android.com/training/animation/index.html
By doing getLayoutParams().width = width; you are changing layout params of the View. But you are performing drawing on a Canvas that owns SurfaceHolder, and not the one an ordinary View will provide you.
So, in order to change the size of the SurfaceView, you have to interact with SurfaceHolder:
surfaceView.getHolder().setFixedSize(width, height);
I started work on libgdx a day before. I wanted to create a triangle whose points should be such that two corners should be at bottom left and bottom right and one point at top middle of screen. I am using perspective camera. My code example is:
public class Test1 implements ApplicationListener{
PerspectiveCamera camera;
Mesh triangle;
#Override
public void create() {
// TODO Auto-generated method stub
camera = new PerspectiveCamera(67, 45, 45 / (Gdx.graphics.getWidth() / (float)Gdx.graphics.getHeight()));
camera.near = 1;
camera.far = 200;
triangle = createTriangle();
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void render() {
// TODO Auto-generated method stub
GL10 gl = Gdx.gl10;
gl.glClearColor(0, 0, 0, 1);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glEnable(GL10.GL_DEPTH_TEST);
camera.update();
camera.apply(gl);
triangle.render(Gdx.gl10.GL_TRIANGLES);
}
public Mesh createTriangle() {
float[] vertices = {-45f, -27f, -67,
45f, -27f, -67,
0, 27f, -67
};
short[] indices = {0,1,2};
Mesh mesh = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE));
mesh.setVertices(vertices);
mesh.setIndices(indices);
return mesh;
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
// TODO Auto-generated method stub
}
}
I was reading that OpenGL is unitless so I decided to have 45 units wide and accordingly set its height. When I executed the application, the triangle is not as I expected. It is smaller than the width and height of the screen. I have no prior experience in 3D. Kindly guide me where I am wrong?
Here is the screen shot:
You say you wanted to create a rectangle? You have only specified 3 vertices? Did you mean Triangle and if so, what seems to be the problem with your result?
Cheers
EDIT 1:
Having reread your question I apologise for the answer I gave.
You need to implement the resize function, creating your camera there as it is called once when the window is created before render is called. Something along the lines of
#Override
public void resize(int width, int height) {
float aspectRatio = (float) width / (float) height;
camera = new PerspectiveCamera(67,2f * aspectRatio, 2f);
}
should be what you're looking for. Read more about it here in the camera section. It may be about an orthographic camera, but the basic principle still applies
Edit 2:
Units in OpenGl are application specific. You have to set up the units you use.
There are however conventions, for instance by defualt the camera will be "looking" down the negative Z axis, with the positive X to the right and positive Y up. This is called a right hand system.
You have set up your 3D camera to have a view width of 45 (so an object at the camera with a width of 45 would fill the screen) and a height of 45 over the aspect ratio. Something we must remember is that objects in 3D that are far away are smaller than when they are up close. So you may have been expecting the triangle to fill the screen, however the Z coordinate of the points of the triangle are far away (67 from the camera) so it makes the triangle look smaller.
If you are only interested in 2D then use something called an OrthographicCamera which makes it so what you draw does not change size with distance from the camera (it has no perspective)
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.
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
OK, Brief recap, Was asked to create an app for work that records data specific data and display it to the screen when finished. So it would function like so.
press start > press stop > display results.
However, I have just been told by the IT director of my company that he wants to display information in needle graphs (g-force, average speed, top speed) and also wants a flashy way of displaying the others (time taken, distance traveled)
My initial idea is this:
create a needle gauge like this, but on a smaller scale and have the digit value display below or beside the graph and to just display the distance traveled and time taken displayed as alarm clock style digits. This would all run down the left hand side of the screen in a thin column and then hava a map displaying the starting location and end location with the route taken for the journey
basically I would like it to look like this (sorry for the crudeness of the drawing)
Something along these lines would be perfect!
I think I could work out the map business and the digits for the time and distance readouts but I have never done any really fancy UI stuff.
How would I get started making the needle gauge?
I was thinking of trying a horizontal bar gauge forst maybe? Incase I cant get the needle gauge to work.
Also, I only have a til tuesday! :S
invision the following very basic idea:
We have our Custom View with a background image which is the gauge without the needle!
So we first implement this using a class that extends View
public class ourGauge extends View {
private Bitmap bgImage = null;
public ourGauge(Context context, Bitmap bgImage) {
super(context);
this.bgImage = bgImage;
}
public ourGauge(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgImage, 0, 0, null);
}
}
Now lets add a needle
public class ourGauge extends View {
private Bitmap bgImage = null;
private int indicator;
Paint paint = new Paint();
public ourGauge(Context context, Bitmap bgImage) {
super(context);
this.bgImage = bgImage;
}
public ourGauge(Context context) {
super(context);
}
public void setIndicator(int indicator){
this.indicator = indicator;
invalidate();
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgImage, 0, 0, null);
//you could set color based on indicator (speed or sth)
paint.setColor(Color.BLACK);
canvas.drawLine(0, 0, 20, 20, paint);
//you have to find the formula to get from where to where the line should drawn
}
}
To make it better
Don't draw the needle using drawLine but rather make it a shape
with dimensions
To create dynamic labels for speeds, you should draw them too
etc