I'm trying to make a ball bounce up and down with the use of translate transition. I'm first trying to make the ball move up before it starts moving down. the code I used for moving it up is like this
public void moveUp(Circle player){
TranslateTransition goUp = new TranslateTransition(Duration.millis(500),player);
goUp.setByY(-20);
goUp.play();
}
and I'm updating the value of the ball(player) on every keypress as follows(p.s player is of type Circle)
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
if(keyEvent.getCode() == KeyCode.SPACE){
moveUp(player);
player.setCenterY(player.getCenterY-20);
}
}
});
the only problem is that the amount the ball moves is not the same as the amount I'm updating. Taking a few values as example(Take note that the player's original center was 400,300) I got 280 as the updated value of the player's centerY, yet the centreY of the ball on screen was at around the 260 which is far off. How do I fix this so that the player's centreY gets shifted by the same amount it moves on screen?
This is because the Circle (player) has a translateY property in addition to its centerY property as mentioned by #James_D. translateY is a property common to all nodes. Whenever a TranslateTransition is applied, the coordinates of the Node (player in this case) do not change. Instead its 'local origin' changes.
Circle player = new Circle(10);
TranslateTransition goUp = new TranslateTransition(Duration.millis(500),player);
goUp.setByY(-20);
goUp.play();
When this code is executed the origin for the player moves up by 20 pixels, and the centerY property stays the same. If the coordinates were originally (400,300), they stay the same, but are now referenced with respect to the new local origin.
This procedure of modifying the coordinate axes themselves, is common for all transformations as explained in the javadoc for Node.
A translation transformation is one which shifts the origin of the node's coordinate space along either the x or y axis.
Note that as with all transformations, the x, y, width, and height variables of the rectangle (which remain relative to the local coordinate space) have not changed, but rather the transformation alters the entire coordinate space of the rectangle.
If you want to change the centerY property instead of the translateY property, you can use the Timeline class instead of TranslateTransition. You could refer this SO answer for using the Timeline class for this purpose.
Related
I want to move blocks with different x-positions without changing their shape by reducing the x-position.
I have tried to run the following code, but it seems like the blocks move to a tow position way to fast (correct potion and other i can't see where).
downBlocks=new Arraylist<Rectangle>;
for (DownBlocks downBlocks:getBlocks()){
if(Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
downBlocks.x = (int) touchPos.x - downBlocks.x;
}
}
To do a drag, you need to remember the point where the finger last touched the screen so you can get a finger delta. And as a side note, avoid putting code inside your loop iteration if it only needs to be called once. It's wasteful to unproject the screen's touch point over and over for every one of your DownBlocks.
static final Vector3 VEC = new Vector3(); // reusuable static member to avoid GC churn
private float lastX; //member variable for tracking finger movement
//In your game logic:
if (Gdx.input.isTouching()){
VEC.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(VEC);
}
if (Gdx.input.justTouched())
lastX = VEC.x; //starting point of drag
else if (Gdx.input.isTouching()){ // dragging
float deltaX = VEC.x - lastX; // how much finger has moved this frame
lastX = VEC.x; // for next frame
// Since you're working with integer units, you can round position
int blockDelta = (int)Math.round(deltaX);
for (DownBlocks downBlock : getBlocks()){
downBlock.x += blockDelta;
}
}
I don't recommend using integer units for your coordinates, though. If you are doing pixel art, then I recommend using floats for storing coordinates, and rounding off the coordinates only when drawing. That will reduce jerky-looking movement. If you are not using pixel art, I would just use float coordinates all the way. Here's a good article to help understand units.
I'm having some difficulty implementing very basic collision within libGDX. The update code for the "player" is as so:
private void updatePosition(float _dt)
{
Vector2 _oldPos = _pos;
_pos.add(_mov.scl(_dt*50));
_bounds.setPosition(_pos.x-8, _pos.y-12);
if(_game.getMap().checkCollision(_bounds))
{
System.out.println("Collision Detected");
_pos = _oldPos;
_bounds.setPosition(_pos.x-8, _pos.y-12);
}
}
So, initially _oldPos is stored as the values of _pos position vector before applying any movement.
Movement is then performed by adding the movement vector _mov (multiplied by the delta-time * 50) to the position vector, the player's bounding rectange _bounds is then updated to this new position.
After this, the player's new bounding Rectangle is checked for intersections against every tile in the game's "map", if an intersection is detected, the player cannot move in that direction, so their position is set to the previous position _oldPos and the bounding rectangle's position is also set to the previous position.
Unfortunately, this doesn't work, the player is able to travel straight through tiles, as seen in this image:
So what is happening here? Am I correct in thinking this code should resolve the detected collision?
What is strange, is that replacing
_pos = _oldPos;
with (making the same move just made in reverse)
_pos.sub(_mov.scl(_dt*50));
Yields very different results, where the player still can travel through solid blocks, but encounters resistance.
This is very confusing, as the following statement should be true:
_oldPos == _pos.sub(_mov.scl(_dt*50));
A better solution for collision detection would be to have a Vector2 velocity, and every frame add velocity to position. You can have a method that tests if Up arrow key is pressed, add 1 (or whatever speed you would like) to velocity. And if down is pressed, subtract 1 (or whatever speed). Then you can have 4 collision rectangles on player, 1 on top of player, bottom, left, and right. You can say
if(top collides with bounds){
if(velocity.y > 0){
set velocity.y = 0.
}
}
And do the same for down, left and right (eg... for bottom, make sure to test if(velocity.y < 0) instead of if(velocity.y > 0).
EDIT: You code is not working because you set oldPos = pos without instantiating a new Vector2. Which means when you add onto pos, it also changes oldPos. So say oldPos = new Vector2(pos);
try to test future position before move. If collision, don't move.
I have a sprite arrow that rotates like a clock hand, I need my other sprite to spawn where the arrow is pointed.
//arrow rotation:
int x=Gdx.input.getX();
int y=Gdx.graphics.getHeight()-Gdx.input.getY();
double radians= Math.atan2(y - launcherSpr.getY(), x - arrowSpr.getX());
float angle=(float)radians*MathUtils.radiansToDegrees-85;
arrowSpr.setRotation(angle);
//The other sprite that is spawned whenever the method is called
public void newBullet(){
Sprite sprite=Pools.obtain(Sprite.class);
sprite.set(bulletSpr);
sprite.setPosition(300, 600);
bullets.add(sprite);
}
Right now when the method newBullet() is called, a bullet sprite will spawn and it's Y is translated by 5(going upward by 5 pixels per frame). What I want is that the bullet will spawn based on where the arrow is pointed and go upward or downward based on the situation.
I want to make a game where you can build stuff by dragging and dropping objects into place. I think LibGDX only supports DragNDrop on Actors, but I need physics on bricks in order to make them fall down if the construction is not stable.
So far, my approach to drag and drop is:
for(Brick b : map.getList()){
final Image im = new Image(b.ar);
stage.addActor(im);
im.setPosition(b.posX, b.posY);
im.setOrigin(b.posX, b.posY);
im.addListener((new DragListener() {
public void touchDragged (InputEvent event, float x, float y, int pointer) {
im.setOrigin(x, y);
im.setPosition(x, y);
//System.out.println("touchdragged ---> X=" + x + " , Y=" + y);
}
}));
}
where the map.getLists contains all bricks to be painted. b.ar is the texture to be painted.
With this aproach [this] is what happens. I don't know what may be causing it.
#Override
public void render(float delta) {
spritebatch.begin();
map.getWorld().step(1/60f, 6, 2);
renderer.render(map.getWorld(), camera.combined);
if(Gdx.input.justTouched()){
Vector3 touchPoint = new Vector3(Gdx.input.getX(), Gdx.input.getY(),0);
camera.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
System.out.println(touchPoint);
}
stage.draw();
spritebatch.end();
}
Of course i'd like to make the body fell (with the box 2d engine from libgdx) if you drop the object and it has nothing under it.
Thanks in advance
You're setting the origin in your listener callback to a screen coordinate. That is not going to work.
The origin is used to define the "center" of your object, so when you reposition it, Libgdx knows which part of the actor to put where. Generally the origin is either the bottom left corner of the object (I think this is the default) or its the center of the object.
I guess you may want to reset the origin so if someone taps on the left edge of a brick and then you reposition the object you'll reposition that point on the brick (and not reposition the bottom left corner of the brick). To do that you'll need to convert the screen coordinates into coordinates in the actor's space.
That's all somewhat icky though. I think you'd be better off just doing relative repositioning. Instead of trying to position the brick absolutely with setPosition just reposition it relatively:
im.setPosition(im.getX() + dx, im.getY() + dy);
Then it doesn't matter where the "origin" is.
You'll have to compute dx and dy in your listener based on the previous touch point.
It appears that the drag listener gives coordinates relative to the origin of the actor that is raising the event. That is a bit strange when you are moving that actor in response to the drag events, because the origin keeps changing. Essentially, I found that if I just move the actor by the x and y values of the event, it will follow the mouse or finger.
One improvement is to record the position that the drag started at and use it as an offset, so the pointer stays the same distance from the actor's origin.
Another option might be to add the listener to the stage instead of the button. I expect the coordinates would then be relative to the stage's origin, which is not changing. I haven't tried that technique.
Here's the code I used to drag a button horizontally:
DragListener dragListener = new DragListener() {
private float startDragX;
#Override
public void dragStart(
InputEvent event,
float x,
float y,
int pointer) {
startDragX = x;
}
#Override
public void drag(InputEvent event, float x, float y, int pointer) {
insertButton.translate(x - startDragX, 0);
}
};
dragListener.setTapSquareSize(2);
insertButton.addListener(dragListener);
If you want to drag something in two dimensions, just copy the x code for the y position.
I am using DigitalOnScreenControl to Move Player Sprite.But the Problem is that My Player Sprite goes out of Emulator Screen.I want player sprite be restricted to move in particular bounds and also camera to focus on player sprite as and when my sprite moves on.
i am trying this code:
public Scene onLoadScene() {
// Auto-generated method stub
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene mScene=new Scene();
mScene.setBackground(new ColorBackground(0.09804f, 0.6274f, 0.8784f));
final int centerX=(CAMERA_WIDTH-this.mPlayerTextureRegion.getWidth())/2;
final int centerY=(CAMERA_HEIGHT-this.mPlayerTextureRegion.getHeight())/2;
final Sprite player=new Sprite(centerX, centerY, this.mPlayerTextureRegion);
this.mCamera.setChaseEntity(player);
final PhysicsHandler physicsHandler=new PhysicsHandler(player);
player.registerUpdateHandler(physicsHandler);
mScene.attachChild(player);
this.mDigitalOnScreenControl=new DigitalOnScreenControl(0,CAMERA_HEIGHT-mOnScreenControlBaseTextureRegion.getHeight(),this.mCamera,this.mOnScreenControlBaseTextureRegion,this.mOnScreenControlKnobTextureRegion,0.1f,new IOnScreenControlListener() {
#Override
public void onControlChange(BaseOnScreenControl pBaseOnScreenControl,
float pValueX, float pValueY) {
// TODO Auto-generated method stub
physicsHandler.setVelocity(pValueX*100, pValueY*100);
}
});
this.mDigitalOnScreenControl.getControlBase().setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
this.mDigitalOnScreenControl.getControlBase().setAlpha(0.5f);
this.mDigitalOnScreenControl.getControlBase().setScaleCenter(0, 128);
this.mDigitalOnScreenControl.getControlBase().setScale(1.25f);
this.mDigitalOnScreenControl.getControlKnob().setScale(1.25f);
this.mDigitalOnScreenControl.refreshControlKnobPosition();
mScene.setChildScene(this.mDigitalOnScreenControl);
return mScene;
}
Honestly I am Very new in andEngine Development
please Help me With Heart
Thank in advance.
Binding the Player to the Camera
What you're asking for is a form of collision handling. Essentially, when you've moved the player outside of the scene, you want to move the player back into the scene, and you want to do that in the same update as you've moved the player, immediately after moving the player, so the out-of-scene location never gets rendered.
Lets take apart what I just said. You move the player here:
physicsHandler.setVelocity(pValueX*100, pValueY*100);
Moving the player with a physicsHandler is perfectly reasonable and takes into account variable frame-rate so, so far, good job. Now you want to move them back into the scene if they're outside it. So we're going to need a new method. Lets throw in a method call right after moving the player (we'll call it "adjustToSceneBinding()" so you have this:
physicsHandler.setVelocity(pValueX*100, pValueY*100);
adjustToSceneBinding(player);
Sidenote, I'd rather have this method be on the player (i.e., player.adjustToSceneBinding()), but your player object is just a sprite. I'd suggest you change that to a custom object that extends sprite so you can throw in your own code there. In any event, lets make the adjustToSceneBinding() method.
public boolean adjustToSceneBinding(Sprite player) {
// Correct the X Boundaries.
if (player.getX() < 0) {
player.setX(0);
} else if (player.getX() + player.getWidth() > CAMERA_WIDTH) {
player.setX(CAMERA_WIDTH - player.getWidth());
}
}
See what I did? If the player's X coordinate is less than zero, move them back to zero. If the player's X PLUS the player's width is more than the camera width, move them back to the camera width minus the player width. Don't forget the player X coordinate represents the left side of the sprite. That's why I'm taking into account the width in addition to the position for calculating the right side.
The above code only addresses left/right movement, but I'm going to let you extrapolate how to do the same for up down.
Binding the Player to the Map Size Instead
Now, what we did so far was really intended for the situation where the map "size" is no larger than the screen. But often what you'll want is a larger map than the screen size and a camera that chases the player around. To do that, just replace the code above, where I referred to the CAMERA_WIDTH with a number that represents the width of your "map". In other words, the map can be much larger than the camera. If you use larger numbers there (than, say, the width of the camera), and you set the camera to chase the player entity (as you have), then you'll have a map where the player can move around until they hit the bounds of the map.
Hope this helps! :)