I'm a beginner with java and libgdx, and i'm trying to make a simple sprite of a rectangle slowly going out/in of the screen when I swipe (with GestureDetector).
Is there any tool with libgdx to do a simple task like that?
Here the code I have without any animation :
private Sprite rect;
private void drawRect(){
//some code to draw the rectangle as a sprite on a SpriteBatch
// (the rectangle's position is a the top right of the screen)
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
//swipe right to close
if (velocityX >= 150 && !rectClosed) {
rect.setPosition(rect.getX() + rectWidth, rect.getY());
rectClosed = true;
}
//swipe left to open
if (velocityX <= -150 && rectClosed) {
rect.setPosition(xRectOrigine, rect.getY());
rectClosed = false;
}
return false;
}
Thank you !
Related
I made a game in which a turtle had to collect StarFish but when I added walking animation it doesn't work. What happens is it only shows up the first frame and the whole animation doesn't play and I get no errors.
And I'm using diffrent images to load animation
Here is my animation method-
// used to load animation from multiple files
public Animation loadAnimationFromFiles(String[] fileNames, float frameDuration, boolean loop)
{
int fileCount = fileNames.length;
Array<TextureRegion> textureArray = new Array<TextureRegion>();
for (int n = 0; n < fileCount; n++)
{
String fileName = fileNames[n];
Texture texture = new Texture( Gdx.files.internal(fileName) );
texture.setFilter( TextureFilter.Linear, TextureFilter.Linear );
textureArray.add( new TextureRegion( texture ) );
}
Animation anim = new Animation(frameDuration, textureArray);
if (loop) {
//setAnimation(anim);
System.out.println("animation run");
anim.setPlayMode(Animation.PlayMode.LOOP);
}
else {
anim.setPlayMode(Animation.PlayMode.NORMAL);
}
if (animation == null) {
System.out.println("animation null");
setAnimation(anim);
}
return anim;
}
And here is my turtle class where I used animation-
public class Turtle extends BaseActor
{
public Turtle(float x, float y, Stage s)
{
super(x, y, s);
String[] fileNames = {
"turtle2.png",
"turtle.png",
};
loadAnimationFromFiles(fileNames, 0.1f, true);
}
public void act(float dt)
{
super.act(dt);
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
this.moveBy(-5,0);
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
this.moveBy(5,0);
if (Gdx.input.isKeyPressed(Input.Keys.UP))
this.moveBy(0,5);
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
this.moveBy(0,-5);
}
}
You just created the animation, but never used it. To make use of the animation you need to get the textures from it, by measuring the delta time, that passed.
Your turtle class should look more like this:
public class Turtle extends BaseActor
{
private Animation<TextureRegion> animation;//store the animation in a field to use it
private float time;//use a timer for the animation to be played
public Turtle(float x, float y, Stage s)
{
super(x, y, s);
String[] fileNames = {
"turtle2.png",
"turtle.png",
};
//store the animation to the field instead of just creating it
animation = loadAnimationFromFiles(fileNames, 0.1f, true);
//set the animations timer
time = 0;
}
public void act(float dt)
{
//increase the time since the animation was started by the delta time
time += dt;
//tell the animation how much time passed, so it can give you the current animation texture
TextureRegion texture = animation.getKeyFrame(time);
//TODO draw texture
//I assume the super.act call also draws a texture; that should be deleted to not draw over the already created texture
super.act(dt);
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
this.moveBy(-5,0);
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
this.moveBy(5,0);
if (Gdx.input.isKeyPressed(Input.Keys.UP))
this.moveBy(0,5);
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
this.moveBy(0,-5);
}
}
I have an animation of a flipping coin made of five Textures. I would like to delete the animation when the player's Rectangle overlaps the coin's Rectangle but since I haven't found how to do this, I want to just stop it.
With this code, I can draw a Texture above the Animation, but just if the player is overlapping. How can I make it definite? Thanks for the help.
public boolean catchcoin(Rectangle player, Rectangle coin){
if (Intersector.overlaps(player, coin)) {
return true;
}
return false;
}
public boolean changecoin(Rectangle play, Coin coin ) {
boolean b = m.pegamoeda(play, coin.getRectangle());
if(b){
return true;
}
return false;
}
Part of the render method:
public void render(float delta){
currentframe = (Texture) coin.returnsanimatio().getKeyFrame(stateTime, true);
currentframe2 =(Texture)coin2.returnsanimation().getKeyFrame(stateTime, true);
currentframe3 =(Texture)coin3.returnsanimation().getKeyFrame(stateTime, true);
sp.draw(currentframe, coin.getx(),coin.gety(), 30,30);
sp.draw(currentframe2, coin2.getx(),coin2.gety(), 30,30);
sp.draw(currentframe3,coin3.getx(),coin3.gety(), 30,30);
boolean b = changecoin(player, coin);
if(b){
sp.draw(bluecoin, coin.getx(), coin.gety(), 30,30);
}
sp.end();
}
I’m trying to make a scrollwheel component like this in LibGDX:
I’m using ScrollPane since it has input and fling handling built in. I have an image for the scrollwheel that is divided into 14 sections, the scrollpane itself is two sections shorter so that there will be one section on the right and left sides that it can scroll to in either direction. Once the scroll position reaches the end in either direction I want to reset the scroll position back to the center. Doing this over and over again should create the illusion of an infinite scrolling wheel (hopefully).
The problem I’m having is how to position the ScrollPane in code to reset the image once it reaches either end. So far nothing I have tried to set the scroll position has worked. I’ve tried setScrollX() and scrollTo() methods. I’ve also tried setting the size of the scrollpane to be various sizes (same size as image and two sections smaller than the image). I’ve tried calling layout, invalidate, and pack on the scrollpane to make sure it is laid out correctly before I set the scroll value. I thought that updateVisualScroll() might force it to update the scroll position, but this also has no effect.
No matter what I do it simply ignores all of my calls to change the scroll position so I’m clearly missing something. In my code below I'm trying to get the scrollwheel to start in the center of the image and instead it's starting position is all the way at the left.
I also need to be able to get the current scroll position to detect when it has reached either end. I tried overriding the act() method and printing out scrollPane.getX(), but this value was always “0” even when I manually clicked and dragged it to scroll the ScrollPane.
The scrolling does work when manually clicking and dragging, so I believe the ScrollPane is set up correctly, I just can’t get it to scroll within the code.
Here is my code, and for simplicity I took all of my experimentation code out because none of my experimenting worked.
public class MyScrollWheel extends Container<ScrollPane> {
private ScrollPane scrollPane;
private Image image;
private int scrollOffset;
public MyScrollWheel(){
Texture texture = new Texture(Gdx.files.internal("internal/scrollwheel.png"));
image = new Image(texture);
scrollOffset = (int)(image.getWidth()/14);
scrollPane = new ScrollPane(image);
scrollPane.setOverscroll(false, false);
setActor(scrollPane);
size(image.getWidth()-(scrollOffset*2), image.getHeight());
scrollPane.setScrollX(scrollOffset); // << this doesn't scroll
scrollPane.updateVisualScroll();
}
}
Well, I hopefully managed to get something you can build upon. What I simply did was extending actor and have it accept a Texture so I could use Texture.wrap and have it draw with SpriteBatch.draw(). I am able to keep scrolling it now and based on the scroll delta you can figure out how far it has been scrolled. I don't see any need to reset the wheel but if you really want to you can just do wheel.setScroll(0);.
One limitation is that it is not a Drawable so it cannot be scaled like a NinePatch. You have to give it a plain wheel texture draw it the size you want it to spear, you can add normal scaling however and keep aspect ratio manually. Then add the sides to it and perhaps overlay a gradient on those to create depth.
ScrollWheel:
public class ScrollWheel extends Actor {
Texture wheelTexture;
private int scroll = 0;
public int getScroll() {
return scroll;
}
public void setScroll(int scroll) {
this.scroll = scroll;
}
public ScrollWheel(Texture texture)
{
wheelTexture = texture;
wheelTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.ClampToEdge);
setWidth(texture.getWidth());
setHeight(texture.getHeight());
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
batch.draw(wheelTexture, getX(), getY(), scroll, 0,
wheelTexture.getWidth(), wheelTexture.getHeight());
}
}
usage in a Screen:
public class TestScreen implements Screen {
Stage stage;
ScrollWheel wheel;
public TestScreen() {
stage = new Stage();
Table t = new Table();
t.setFillParent(true);
stage.addActor(t);
wheel = new ScrollWheel(new Texture("hud/wheel_part.png"));
wheel.addListener(new DragListener() {
#Override
public void drag(InputEvent event, float x, float y, int pointer) {
super.drag(event, x, y, pointer);
wheel.setScroll(wheel.getScroll() + (int)getDeltaX());
}
});
t.add(wheel);
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(.3f, .36f, .42f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
//...Other mandatory screen methods...
}
So just create a wheel texture that is tillable and include that with the ScrollWheel constructor. It will draw the wheel in the center of the screen if you use this exact code.
The scroll variable essentially holds the amount of scroll so if you you want limit this between 0 and 100 you would just add this functionality in setScroll().
if (scroll > 100) scroll = 100;
else if (scroll < 0) scroll = 0;
You could then add a step to it. So if you want to rotate a image with the slider you could set the rotation by scroll * 3,6f or scroll * (maxScroll / maxStep)
I really liked the way this turned out, I will be using this for my slider in the future :D. I have extended and altered it a bit already and you can see my implementation here: https://youtu.be/RNLk5B-VfYg
Expanding on Menno Gouw's scroll wheel, I've added some more features:
Fling support with setting for fling time
Precision setting to adjust sensitivity of the wheel
Takes a Drawable
Compatible for use inside of a ScrollPane
NOTE: For my purposes I have it take in a Label in the constructor, but this can easily be changed if you don't want it tied to a Label.
Here is a video I recorded on phone demoing the scroll wheel.
https://www.youtube.com/watch?v=RwVrez4BZsY&feature=youtu.be
- EDIT 1: Layout bugs have now been fixed (hopefully). It now updates its position when moved in a ScrollPane and the Drawables are clipped to the border of the Actor.
- EDIT 2: Added support for a stationary drawable for shading and a method to change the wheel's direction (setRightPositiveDirection()).
public class ScrollWheel extends Actor {
private Drawable wheelDrawable, wheelShading;
private Label label;
private int unscaledScrollValueX=0, scrollValueX=0;
private boolean isNotEdge;
private int precision=40;
private int direction=1;
private int minValue=Integer.MIN_VALUE, maxValue=Integer.MAX_VALUE;
// MANUAL SCROLL
private int separator;
private int wheelWidth;
// FLING
private float flingTimer, flingTime=1f;
private float velocityX;
public ScrollWheel(Drawable wheelDrawable, Drawable wheelShading, Label label) {
this.wheelDrawable = wheelDrawable;
this.wheelShading = wheelShading;
this.label = label;
wheelWidth = (int)wheelDrawable.getMinWidth();
separator = wheelWidth;
setWidth(wheelDrawable.getMinWidth());
setHeight(wheelDrawable.getMinHeight());
// stops ScrollPane from overriding input events
InputListener stopTouchDown = new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
event.stop();
return false;
}
};
addListener(stopTouchDown);
ActorGestureListener flickScrollListener = new ActorGestureListener() {
public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) {
updateScroll(deltaX);
}
public void fling (InputEvent event, float x, float y, int button) {
if (Math.abs(x) > 150) {
flingTimer = flingTime;
velocityX = x;
}
}
public boolean handle (Event event) {
if (super.handle(event)) {
if (((InputEvent)event).getType() == InputEvent.Type.touchDown) flingTimer = 0;
return true;
}
return false;
}
};
addListener(flickScrollListener);
}
private void updateScroll(float delta){
unscaledScrollValueX += (delta * direction);
scrollValueX = (int)(unscaledScrollValueX / precision);
isNotEdge = true;
if (scrollValueX <= minValue){
scrollValueX = minValue;
unscaledScrollValueX = minValue * precision;
isNotEdge = false;
}
else if (scrollValueX >= maxValue){
scrollValueX = maxValue;
unscaledScrollValueX = maxValue * precision;
isNotEdge = false;
}
if (isNotEdge){
separator += delta;
if (separator <= 0){
separator = wheelWidth;
}
else if (separator >= wheelWidth) {
separator = 0;
}
}
updateLabel();
}
private void updateLabel(){
label.setText("" + scrollValueX);
}
public void setMinValue(int minValue){ this.minValue = minValue; }
public void setMinValueToNone(){ minValue=Integer.MIN_VALUE; }
public void setMaxValue(int maxValue){ this.maxValue = maxValue; }
public void setMaxValueToNone(){ minValue=Integer.MAX_VALUE; }
public void setFlingTime(float flingTime){ this.flingTime = flingTime; }
public void setPrecision(int precision){ this.precision = precision; }
public void setRightPositiveDirection(boolean rightPositive){ direction = (rightPositive) ? 1 : -1; }
#Override
public void act(float delta){
super.act(delta);
boolean animating = false;
if (flingTimer > 0) {
float alpha = flingTimer / flingTime;
updateScroll(velocityX * alpha * delta);
flingTimer -= delta;
if (flingTimer <= 0) {
velocityX = 0;
}
animating = true;
}
if (animating) {
Stage stage = getStage();
if (stage != null && stage.getActionsRequestRendering()){
Gdx.graphics.requestRendering();
}
}
}
#Override
public void draw(Batch batch, float parentAlpha){
super.draw(batch, parentAlpha);
batch.flush();
if (clipBegin(getX(), getY(), getWidth(), getHeight())){
wheelDrawable.draw(batch, getX() + separator - wheelWidth, getY(), wheelDrawable.getMinWidth(), wheelDrawable.getMinHeight());
wheelDrawable.draw(batch, getX() + separator, getY(), wheelDrawable.getMinWidth(), wheelDrawable.getMinHeight());
wheelShading.draw(batch, getX(), getY(), wheelShading.getMinWidth(), wheelShading.getMinHeight());
batch.flush();
clipEnd();
}
}
}
Please excuse my bad english. I am having a problem while implementing a 2d camera. I made the camera to follow the player until it reaches near the edge of the game-level, where only the player moves and the camera stops. I made this easily but my problem is that the camera is not proper. The camera continues to move 1 extra pixel every time you reach at the edge of the game-level limit in all four directions (The code I posted only shows horizontal movement. This I did for simplicity). This means if you move 40 times to and fro near the left edge of the game, camera will move 40 extra pixels right! I have no idea how to solve this.
I posted a very simplified version from my original code below and made it as small as i could to show how the program works. Following just moves the player and camera horizontally across the screen.
This is 'theGamePanel' class (it is the main class) :-
public class TheGamePanel extends JPanel implements Runnable, KeyListener
{
private boolean left, right;
private float cameraX, cameraY;
private World world = new World();
private Player player = new Player();
public TheGamePanel()
{
//setting the size of panel
}
public static void main(String[] args)
{
//setting the window
}
public void paint(Graphics g)
{
super.paint(g);
// drawing the game-level and player
g.translate((int)cameraX, (int)cameraY);
world.paint(g);
player.paint(g);
g.translate(-(int)cameraX, -(int)cameraY);
}
public void upd()
{
player.update(left, right, this);
}
#Override
public void run()
{
// game-loop
}
#Override
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if(code == KeyEvent.VK_LEFT)
{
left = true;
}
if(code == KeyEvent.VK_RIGHT)
{
right = true;
}
}
#Override
public void keyReleased(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_LEFT)
{
left = false;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
{
right = false;
}
}
#Override
public void keyTyped(KeyEvent e)
{
}
//to set camera position
public void setCameraX(float cameraDx)
{
cameraX += cameraDx;
}
}
This is the 'Player' class. This class is where the player and camera movement takes place. The camera's x and values are then returned to 'TheGamePanel' :-
public class Player
{
private float x, y;
private float dx = 1;
private int width = 32, height = 32;
private float leftLimit, rightLimit;
public Player()
{
//player's initial x and y coordinates
x = 320;
y = 240;
//camera's limit (where the camera needs to stop following player)
leftLimit = x;
rightLimit = 960;
}
public void paint(Graphics g)
{
//for painting the player
g.setColor(Color.GREEN);
g.fillRect((int)x, (int)y, width, height);
}
//to move player and camera
public void update(boolean left, boolean right, TheGamePanel panel)
{
if(left == true)
{
x -= dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(dx);
}
}
if(right == true)
{
x += dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(-dx);
}
}
}
}
And lastly, the 'World' class. This class is used to simply paint a big map(level) in the background :-
public class World
{
private BufferedImage map;
private int tileWd = 32, tileHi = 32;
public World()
{
try
{
map = ImageIO.read(new File("map1.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void paint(Graphics g)
{
//simply paints a game-level in the background
}
}
If anything not understandable please tell. I will add more details.
Consider the case where the player is standing near the right edge of the map. One quick tap on the "right" key moves him out of the camera-follow area so the camera doesn't move. One quick tap on the "left" key moves him back into the camera-follow area. The camera will be moved "dx" units to the left. This will have the effect of the player slowly creeping closer to the right edge of the playing field, if I'm correct.
(To find bugs like this, I generally litter the code with System.out.println messages. If there's a lot of messages, I write them to a file and do text searches on keywords)
you have a location for your camera (cameraX,cameraY) but nothing for the player?
just create a location for player (playerX,playerY)
change the paint like:
public void paint(Graphics g)
{
super.paint(g);
// drawing the game-level and player
g.translate((int)cameraX, (int)cameraY);
world.paint(g);
g.translate((int)playerX, (int)playerY);
player.paint(g);
g.translate(-(int)(playerX+cameraX), -(int)(playerY+cameraY));
}
and when player come near borders don't move camera and only player.
I believe the following change fixes the problem:
Player class:
//to move player and camera
public void update(boolean left, boolean right, TheGamePanel panel)
{
if(left == true)
{
x -= dx;
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(dx);
}
}
if(right == true)
{
if(x > leftLimit && x < rightLimit)
{
panel.setCameraX(-dx);
}
x += dx; // Only change: moved this line AFTER the if block
}
}
By testing x after changing it when moving left and before changing it when moving right you compensate for the error that was otherwise accumulating every time you reached one of the boundaries.
Anyway I suggest you to change your approach to the problem in order to make your code easier to maintain and more flexible. One way to do that is to calculate the camera position based on current player's position on every frame.
Note: The line g.translate(-(int)cameraX, -(int)cameraY); in the paint() method of TheGamePanel class is unnecessary once the method translate(int, int) is not incremental.
Regards
Below is my code where I am drawing circle on the Google Map in Android. It is working fine for me.
Problem Statement:-
Currently the circle that is getting drawn on the google map is very dark. I need to make that circle little bit light with the same color that I am having currently. Is that possible to make that circle little bit light by tweaking few parameters in the paint or color? It is more darker in the center part, don't know why. I just need to make it light in all the four circles that I have currently.
class MapOverlay extends Overlay {
private GeoPoint pointToDraw;
int[] imageNames=new int[6];
private Point mScreenPoints;
private Bitmap mBitmap;
private Paint mCirclePaint;
public MapOverlay(GPSLocationListener gpsLocationListener, int currentUser) {
imageNames[0]=currentUser;
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setColor(0x30000000);
mCirclePaint.setStyle(Style.FILL_AND_STROKE);
mBitmap = BitmapFactory.decodeResource(getResources(),imageNames[0]);
mScreenPoints = new Point();
}
public void setPointToDraw(GeoPoint point) {
pointToDraw = point;
}
public GeoPoint getPointToDraw() {
return pointToDraw;
}
#Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
super.draw(canvas, mapView, shadow);
if (pointToDraw == null) {
return true;
}
mScreenPoints = mapView.getProjection().toPixels(pointToDraw, mScreenPoints);
int totalCircle=5;
int radius=40;
int centerimagesize=35;
for (int i = 1; i <= totalCircle; i ++) {
canvas.drawCircle(mScreenPoints.x,mScreenPoints.y, i*radius, mCirclePaint);
}
canvas.drawBitmap(mBitmap, (mScreenPoints.x-(centerimagesize/2)),(mScreenPoints.y-(centerimagesize/2)), null);
super.draw(canvas,mapView,shadow);
return true;
}
}
Snapshot of my Circle currently-
Any suggestion will be of great help.
Problem
The reason why it gets darker in the center, is because you are drawing four circles, one over the other. When you draw the second circle, the part that is commoun to both, is painted twice, so it becomes darker. When you draw the tird circle, it becomes even darker ...
Solution
If you want all circles with same color, you should use Style.STROKE for all the circles, except the larger one, which shoud use Style.FILL_AND_STROKE. With that you only draw the lines for the small circles and fill all area when drawing the big one.
Code
mCirclePaint.setStyle(Style.STROKE);
for (int i = 1; i <= totalCircle-1; i ++) {
canvas.drawCircle(mScreenPoints.x,mScreenPoints.y, i*radius, mCirclePaint);
}
mCirclePaint.setStyle(Style.FILL_AND_STROKE);
canvas.drawCircle(mScreenPoints.x,mScreenPoints.y, totalCircle*radius, mCirclePaint);
Regards