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! :)
Related
I am making a simple game with JavaFX, where a ball bounces around the screen after being released from the bottom (via a button). When the ball is bouncing around the pane, if it hits a Rectangle it changes its color to blue.
I am attempting to add a method called checkBounds to keep track of when the ball (a Circle) hits the Rectangle. As soon as the ball comes into contact with the rectangle, the score should increase by 10. The scoring mechanism works, but it continues to increment with each frame that the ball takes through the Rectangle, instead of only incrementing once when it enters. (eg. It should only go up by 10 one time, not continue going up by 10 the whole time the ball passes through). I callcheckBounds() 3 times in my timeline loop to check each rectangle on each loop iteration.
checkBounds(ball, gameSquare);
checkBounds(ball, gameSquare2);
checkBounds(ball, gameSquare3);
How would I fix this logic error? I've attempted several different options, but none seem to work.
private void checkBounds(Shape block, Rectangle rect) {
boolean collisionDetected = false;
Shape intersect = Shape.intersect(block, rect);
if (intersect.getBoundsInLocal().getWidth() != -1) {
collisionDetected = true;
}
if (collisionDetected) {
score.setText(Integer.toString(currentScore.getCurrentValue()));
currentScore.incrementBy(10);
rect.setFill(Color.BLUE);
}
}
I believe what you want to detect is the state change of your collisionDetected from false to true. One way to do this is to keep the state of the previous value as a member variable for each collision object. To do this, we need some identifying id for the rectangle, so you may want to pass in the id into the checkBounds method:
private void checkBounds(Shape block, Rectangle rect, int id) {
we also need to create a member variable to store the states:
private HashMap<Integer,Boolean> previousCollisionStateMap = new HashMap<>();
and then inside your checkBounds code, you can modify the condition to check for changes
Boolean prevState = previousCollisionStateMap.get(id);
if (prevState == null) { // this is just to initialize value
prevState = false;
previousCollisionStateMap.put(id,false);
}
if (!prevState && collisionDetected) {
score.setText(Integer.toString(currentScore.getCurrentValue()));
currentScore.incrementBy(10);
rect.setFill(Color.BLUE);
}
and don't forget to update the state at the end
previousCollisionStateMap.put(id,collisionDetected);
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.
OK so I'm really confused I've rotated sprites before and had no problem such as rotating a boat as it moves through an ocean, but for some reason I'm having a really big problem this time. So I create a texture in an assets file, but not static textures. I load the texture using the following:
class Assets{
Texture img;
public Assets(){
img = new Texture(Gdx.files.internal("images/PNG.png")
And then I call the assets in the main class by calling:
Assets assets = new Assets()
And then I have a class that is an animator just for this main character because his animation is so different and varied from other characters.
class Animations{
Guy MYGUY;
Texture firstTexture;
ArrayList<Texture> running;
Sprite CurrentSprite;
public Animations(Texture standingStill, Guy myGuy){
MYGUY = myGuy;
firstTexture = standingStill;
running = new ArrayList<Texture>();
running.add(firstTexture);
CurrentSprite = new Sprite(firstTexture);
public void update (int direction, int state){
CurrentSprite.setPosition(MYGUY.X, MYGUY.Y)
// I have a switch here, but it does nothing yet because I haven't added in different actions for the character.
//However I do have a switch for direction, because that is important right now
switch(state){
case Guy.LEFT:
CurrentSprite.set rotation(180);
//yes there are more, but even rotating 180 won't work correctly
}
Then I have a renderer class to draw everything, i have the object MyGuy in an object for the world called myLand and I draw it with:
myLand.GUY.animation.CurrentSprite(batch);
So my problem arises on the rotation, whenever it rotates 180 degrees it seems to always rotate around the coordinates (0, 0) instead of the center of the sprite. So it usually ends up where I move like five to the right, but then if I try to go left it does double the distance backwards, but the camera position stays the same, and the guy usually disappears off the left or right side of the screen.
Try use rotate(...)method instead of setRotation(...).
With setOrigin(widthSprite\2, heightSprite\2)
That action rotate sprite itself.
Try
sprite.setOriginCenter();
This should help
Instead of rotating the sprite, just flip it with this single line:
CurrentSprite.flip(true, false);
the first boolean is X flip (that's what you want to set as true when going left) and the second is the Y flip.
I am currently developing a game for android using libgdx library .
Lets say we have a lizard, now the user creates paths by sliding fingers on the screen, on which the lizard can walk on.
The question is , how do restrict the lizard to walk on only where the finger touched the screen( on the path - between the bounds).
public class Block {
static final float SIZE = 1f;
Vector2 position = new Vector2();
Rectangle bounds = new Rectangle();
public Block(Vector2 pos) {
this.position = pos;
this.bounds.width = SIZE;
this.bounds.height = SIZE;
}
}
In this example we can see a block, the bounds of the block is a rectangle on which the lizard can walk on.
how do I make some similar bounds only using a circle?
Here is what i got so far:
I have created a doubled layer bitmap that overlap each other. When the user touches the screen , he erases the first bitmap reveling the second bitmap underneath the first one ( only the part where the user touched get removed).
here is the function that erases the first bitmap.
public void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(bgr, 0, 0, null);
c2.drawCircle(X, Y, 40, pTouch);
Paint new_paint = new Paint(/*Paint.ANTI_ALIAS_FLAG*/);
new_paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
//new_paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawBitmap(overlay, 0, 0, new_paint);
}
Notice#
the bitmap is removed using a circle shape.
It would be great if i could add to the circle that's removing the bitmap, a property of bound, on which the lizard can walk on.
Any ideas?
u should update the cordinates of bounds as per the lizard position
bounds.x=position.x;
bounds.y=position.y;
So that your bounds follow the lizard
Also instead of using recatangle for bounds try to use
sprite.getBoundingRectangle()
this method gives u the exact rectangular bounds of the image so no need to maintain bounds.
Provided you use AtlasSprite or Sprite for your image.
I shared my game Bomberman early. You can find code you needed in GameScreen class
p.s. also you can find different interesting samples of LibGDX usage here
Few days ago I figured out how to do some scrolling in LibGdx. Now I'm triying to do something related. I want to repeat the background. My scrolling follows a ship (Is an s[ace ship game). In the background there is a space photo loaded as a Texture. When the ship reach the end of the backgorund, It keeps going and there's no background anymore. I have read about wrap but I don't really understand How It works. I did that:
px=new Pixmap(Gdx.files.internal("fondo.jpg"));
background=new Texture(px);
background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
And then, in my render method
spriteBatch.begin();
spriteBatch.draw(background,0,0,500,50);
drawShip();
spriteBatch.end();
Of course It doesn't work, It only draws the background once. I don't know how make this wrap method work. Any help?
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just paint both bck in your render mode.
Like Teitus said, do not load your texture multiple times, ever! Anyway, you where on the right track with the wrapper:
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
Now you can just use the draw method with the source location. The source location is the area you choose to draw on the texture.
batch.draw(texture, x, y, srcX, srcY, srcWidth, srcHeight)
To scroll your texture from right to left all you have to do is increase srcX incrementally. So create a int that increments in the update/render method.
int sourceX = 0;
//render() method
//Increment the variable where to draw from on the image.
sourceX += 10;
//Simply draw it using that variable in the srcX.
batch.draw(YourTexture, 0, 0, sourceX, 0, screenWidth, screenHeight);
Because you are wrapping the texture it will wrap/loop and scroll indefinitely. There might be a issue with the sourceX int if the game runs for a very long time because a int can only hold 2147483647. It takes a while but you can fix it by subtracting the image width each time the number goes over the total image width.
Don't to this, please:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
That will load your big background texture twice. That's a complete waste. If you want to keep your solution at least do:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=bkg1;
Regarding the texture Wrapping. If your texture is 500px wide, and you draw a 500px sprite, you won't see any repetition. If you want it repeated 2 times, draw it 1000px wide with 0-2 texture coordinates.
I'm not sure how spriteBatch handles the call you posted, you could try that one, or may be use the overload that uses a texture region and set your region manually.
I see this is a pretty old question, but I think there is an easier way to accomplish background scrolling. Just use the Sprite class. Here is a snippet I use for layered background images that scroll from right to left.
public class LevelLayer
{
public float speedScalar = 1;
private List<Sprite> backgroundSprites = new ArrayList<Sprite>();
public LevelLayer()
{
}
public void addSpriteLayer(Texture texture, float startingPointX, float y, int repeats)
{
for (int k = 0; k < repeats; k++)
{
Sprite s = new Sprite(texture);
s.setX(startingPointX + (k*texture.getWidth()));
s.setY(y);
backgroundSprites.add(s);
}
}
public void render(SpriteBatch spriteBatch, float speed)
{
for (Sprite s : backgroundSprites)
{
float delta = s.getX() - (speed * speedScalar);
s.setX(delta);
s.draw(spriteBatch);
}
}
}
Then you can use the same texture or series of textures like so:
someLayer.addSpriteLayer(sideWalkTexture1, 0, 0, 15);
someLayer.addSpriteLayer(sideWalkTexture2, 15 * sideWalkTexture1.getWidth(), 0, 7);
I change background repeating sections randomly in code and make new ones or reset existing sets when they go off screen. All the layers go to a pool and get pulled randomly when a new one is needed.
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just draw both bck in your render()