LibGdx How to repeat background? - java

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()

Related

libGDX Draw viewport only partly while cutting off the rest

This problem seemed very obvious for me to solve, but whatever I try, it doesn't work. What I'm trying to do is to incorporate a mini-version of my PlayScreen in a ScrollPane as a tutorial where you can read text and try it out immediately.
Because I didn't find any better solution to add this to the Table inside the ScrollPane, I edited the draw() method of the PlayScreen to take the ScrollPane.getScrollPercentY() and offset the camera of the PlayScreen accordingly.
What I want to do now is to only render only part of the viewport that would be normally visible in the real game. Subsequently, I want to be able to control the size and position of this "window".
I also want to be able to resize and move the content, while cutting off the edges that are not visible to the camera. This is what I tried inside the PlayScreenDraw:
public void draw(final float yOffset,
final int xTiles,
final int yTiles) {
view.getCamera().position.y = yTiles / 2f - yOffset * yTiles / HEIGHT; // HEIGHT = 800
view.getCamera().position.x = xTiles / 2f;
view.setWorldSize(xTiles, yTiles); //Do i even need to change the world size?
b.setProjectionMatrix(view.getCamera().combined);
b.begin();
...
b.end();
view.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
What this gives me, in terms of the picture above, is this
How do I need to change the viewport and/or the camera? Btw., this is how i set the two up:
cam = new OrthographicCamera();
cam.setToOrtho(false, WIDTH, HEIGHT); // WIDTH = 8, HEIGHT = 16
batch.setProjectionMatrix(cam.combined);
view = new FitViewport(WIDTH, HEIGHT, cam);
The Pixmap class can help you achieve what you want since you stated that you wanted to "cut off" the parts outside of the green selection box.
You need to render what the camera sees to an FBO and then get the pixmap from the FBO itself.
Framebuffer Objects are OpenGL Objects, which allow for the creation of user-defined Framebuffers. With them, one can render to non-Default Framebuffer locations, and thus render without disturbing the main screen.
-- OpenGL wiki
// Construct an FBO and keep a reference to it. Remember to dispose of it.
FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, width, height, false);
public void render() {
//Start rendering to the fbo.
fbo.begin();
//From the camera's perspective.
batch.setProjectionMatrix(camera.combined);
batch.begin();
//Draw whatever you want to draw with the camera.
batch.end();
// Finished drawing, get pixmap.
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, width, height);
//Stop drawing to your fbo.
fbo.end();
}
After getting the pixmap you can iterate through the pixels and set the alpha of the pixels outside your green selection window to 0 making them invisible or "cutting them off"

What is the most efficient way of rendering 2D game with the possibility of changing the resolution?

I've tried:
1.Creating a separate variable called "factor" and multiplying or dividing literally everything with it: entity velocities, object sizes, fonts, resolution etc..
(the factor is always relative to the resolution so the objects are scaled properly)
public class Player extends Entity{
float size;
public Player(needed variables) {
super(needed variables);
resize();
}
public void resize() {
/*
Resize everything.
This method is supposed to be called from a separate resizing
function located in another class when the JFrame size is changed.
the function has to play with the choice between divide or multiply
variables with the factor
*/
}
public void tick() {
x += velX*factor;
y += velY*factor;
}
etc..
}
By using this factor to multiply literally everything, it makes the code really messy and hard to read sometimes.
2.Rendering to a BufferedImage and scaling the BufferedImage to fit to the JFrame.
void render() {
//Render the game to a new BufferedImage
BufferedImage renderedFrame = new BufferedImage(1920, 1080, BufferedImage.TYPE_RGB);
renderedFrame.createGraphics();
Graphics g = renderedFrame.getGraphics();
//Render the game ....
//Scale the BufferedImage to fit the current resolution and render it to the Canvas
BufferStrategy bs = getBufferStrategy();
Graphics f = bs.getDrawGraphics();
f.drawImage(renderedFrame.getScaledInstance(1280, 720, Image.SCALE_FAST), 0, 0, null);
f.dispose();
bs.show();
}
Which makes the code much more readable but then there comes 2 problems:
Mouse input problems and resizing the BufferedImage is taking too much resources which makes the game laggy.
3.I could basically try to make a separate unit system for the game.. but then there's the same problem, when it comes to rendering strings or rectangles I'd have to multiply everything with the factor and the code is horrible after that.
Is there any better ways of rendering 2D games? If no then I'll think about moving on to OpenGL.
Thanks in advance.
The way I've done this most successfully is by scaling the graphics object. You end up with something like the following:
final int gameUnitsPerScreenDim = 32;
void render(JPanel panel, Graphics2D g2) {
double pixelHeight = panel.getHeight();
double pixelsPerGameUnit = pixelHeight / gameUnitsPerScreenDim;
g2.scale(pixelsPerGameUnit, pixelsPerGameUnit);
...
}
And then for the simulation, you use game units. How big a game unit actually is is a bit arbitrary, although if you're making a tiled game there's probably some obvious value that it should be.
Instead of using scale, you can also create an AffineTransform which lets you reuse it:
if (this.tf == null || /* image size changed since the last frame */) {
...
this.tf = AffineTransform.getScaleInstance(pxPerGu, pxPerGu);
}
g2.setTransform(this.tf);
(Calling scale creates a new AffineTransform every time you call it.)
That's even a little more efficient, although probably not by much.
(If you want, you can also use a transform to invert the y-axis and translate so the origin is at the center of the image. This makes a lot of trigonometry and stuff feel more natural. Inverting the y-axis makes working with text a pain, though.)
Also, using OpenGL is probably better. Having written a couple of simple games using Swing for fun, I don't see a good reason to do it.

How to draw a sprite within the FitViewport view. libgdx

The basic question here is: how to ALWAYS keep your sprites within the Fitviewport? How to keep a reference to the view in order to have the proper coordinates as to where to draw?
I'm trying to spawn enemies into the gameplay screen. But this is handled by a FitViewport, and enemies and even the player can move outside the FitViewport on certain screen resolutions. So far the problem seems to be in the Y axis.
The FitViewport is made like this:
gameCamera = new OrthographicCamera();
gameCamera.setToOrtho(false);
gameViewport = new FitViewport(MyGame.WORLD_WIDTH,MyGame.WORLD_HEIGHT,gameCamera);
gameViewport.setScreenBounds(0,0,MyGame.WORLD_WIDTH,MyGame.WORLD_HEIGHT);
Then the camera position gets updated like this at the resize() method:
gameViewport.update(width,height); //not used when using the virtual viewport in the render method.
gameCamera.position.set(player.position.x + 200,player.position.y, 0);
Then the update() method calls the Player's own update() method which includes these lines:
//POSITION UPDATE
if (this.position.x<0) this.position.x=0;
if (this.position.x>Gdx.graphics.getWidth() - width) this.position.x= Gdx.graphics.getWidth() - width;
if (this.position.y<0) this.position.y = 0;
if (this.position.y>PlayScreen.gameViewport.getScreenHeight() - height) this.position.y = PlayScreen.gameViewport.getScreenHeight()- height;
Notice for the X axis I'm still using Gdx.graphics dimensions because I'm yet to make it work with PlayScreen.gameViewport.getScreenHeight() (gameViewport has been set to static for this purpose).
Also on enemy spawn (the problem related here is that they spawn outside of the screen Y in terms of what I see) I have this code inside the update() method of the Screen implementing all these viewports:
//Alien Spawn
if (System.currentTimeMillis() - lastZSpawn >= SpawnTimer){
count++;
lastZSpawn= System.currentTimeMillis();
for (int i=0;i<count;i++){
int x = Gdx.graphics.getWidth();
int y = random.nextInt((int)gameViewport.getScreenHeight() - Alien.height);
if (entities.size()<6){
entities.add(new Alien(new Vector2(x,y),1, alienImages,(float)((0))));
}
}
}
Also using gameViewport.getScreenHeight() here cause Gdx.graphics wasnt giving the correct result (it gave me the same issue really).
The render() method is correctly implemented in terms of the batch and applying the viewport:
MyGame.batch.setProjectionMatrix(gameCamera.combined);
gameViewport.apply();
MyGame.batch.begin();
for (int i = entities.size()-1; i>=0;i--){
entities.get(i).render();
}
You should never change the position of your player or enemies when resizing, that's why a viewport is for, remove all the code that do that first, to make your viewport work as you expected you need to create a new instance of camera passing the new viewport width and height when you resize, i prefer to make my camera static so i can acess its atribbutes from everywhere i want, you should do something like this:
public static OrthographicCamera update(int width,int height){
instance = new OrthographicCamera(width, height);
instance.setToOrtho(false);
return instance;
}
The answer to my problem is posted by myself in another question of mine which was also driven by a confusion in the implementation of FitViewports and using WorldWidth and WorldHeight properties as coordinates of reference when drawing objects into the game, and also correctly setting the camera position taking these values into consideration aswell.
The answer is here even though its text and not code and its mainly what i already wrote in this very post. FitViewport doesnt scale properly Libgdx

LibGDX problems rotating sprite

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.

Android game developing - dynamic bounds definition

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

Categories

Resources