How to extend the background in LibGdx for top down game? - java

What is the proper way to extend the background in top down game? I used LibGdx framework. Any idea or tutorial for top down game.My background is in PNG format and screen of 720x1280 portrait.I had a problem in extending the background.I want the camera follow the character and the background will extend. How could I do that? Here is the Screen shot of
https://i.stack.imgur.com/jl03R.png
Here is my code
To display background I used this
//background
Background = new Texture(Gdx.files.internal("floor.png")); //File from assets folder
Background.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
bgsprite = new Sprite(Background);
In render
spriteBatch.draw(Background,0,100,0, srcy, Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
srcy +=3;
The background is scrolling but the camera don't follow the player(cat)
Source code for GameScreen
http://pastebin.com/Dxfx9f65
Thank's and Advance any help or suggestion are much appreciated. :)

Use two identical texture background. Each the size of the screen It can be the same file. It is important that are docked vertically. Move of at the same time. Alternately changing with each other.
Sample code:
declaration:
Texture background1, background2;
SpriteBatch batch;
float yMax, yCoordBg1, yCoordBg2;
final int BACKGROUND_MOVE_SPEED = 100; // pixels per second. Put your value here.
creation:
Background1 = new Texture(Gdx.files.internal("floor.png"));
Background2 = new Texture(Gdx.files.internal("floor.png")); // identical
yMax = 1280;
yCoordBg1 = yMax*(-1); yCoordBg2 = 0;
in method render:
yCoordBg1 += BACKGROUND_MOVE_SPEED * Gdx.graphics.getDeltaTime();
yCoordBg2 = yCoordbg1 + yMax; // We move the background, not the camera
if (yCoordBg1 >= 0) {
yCoordBg1 = yMax*(-1); yCoordBg2 = 0;
}
batch.begin();
batch.draw(background1, 0, yCoordBg1);
batch.draw(background2, 0, yCoordBg2);
batch.end();
The background can be made in the format jpg - will spend less memory.

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"

How can I draw on a video while recording it in android, and save the video and the drawing?

I am trying to develop an app that allows me to draw on a video while recording it, and to then save both the recording and the video in one mp4 file for later use. Also, I want to use the camera2 library, especially that I need my app to run for devices higher than API 21, and I am always avoiding deprecated libraries.
I tried many ways to do it, including FFmpeg in which I placed an overlay of the TextureView.getBitmap() (from the camera) and a bitmap taken from the canvas. It worked but since it is a slow function, the video couldn't catch enough frames (not even 25 fps), and it ran so fast. I want audio to be included as well.
I thought about the MediaProjection library, but I am not sure if it can capture the layout containg the camera and the drawing only inside its VirtualDisplay, because the app user may add text as well on the video, and I don't want the keyboard to appear.
Please help, it's been a week of research and I found nothing that worked fine for me.
P.S: I don't have a problem if a little bit of processing time is included after that the user presses the "Stop Recording"button.
EDITED:
Now after Eddy's Answer, I am using the shadercam app to draw on the camera surface since the app does the video rendering, and the workaround to do is about rendering my canvas into a bitmap then into a GL texture, however I am not being able to do it successfully. I need your help guys, I need to finish the app :S
I am using the shadercam library (https://github.com/googlecreativelab/shadercam), and I replaced the "ExampleRenderer" file with the following code:
public class WriteDrawRenderer extends CameraRenderer
{
private float offsetR = 1f;
private float offsetG = 1f;
private float offsetB = 1f;
private float touchX = 1000000000;
private float touchY = 1000000000;
private Bitmap textBitmap;
private int textureId;
private boolean isFirstTime = true;
//creates a new canvas that will draw into a bitmap instead of rendering into the screen
private Canvas bitmapCanvas;
/**
* By not modifying anything, our default shaders will be used in the assets folder of shadercam.
*
* Base all shaders off those, since there are some default uniforms/textures that will
* be passed every time for the camera coordinates and texture coordinates
*/
public WriteDrawRenderer(Context context, SurfaceTexture previewSurface, int width, int height)
{
super(context, previewSurface, width, height, "touchcolor.frag.glsl", "touchcolor.vert.glsl");
//other setup if need be done here
}
/**
* we override {#link #setUniformsAndAttribs()} and make sure to call the super so we can add
* our own uniforms to our shaders here. CameraRenderer handles the rest for us automatically
*/
#Override
protected void setUniformsAndAttribs()
{
super.setUniformsAndAttribs();
int offsetRLoc = GLES20.glGetUniformLocation(mCameraShaderProgram, "offsetR");
int offsetGLoc = GLES20.glGetUniformLocation(mCameraShaderProgram, "offsetG");
int offsetBLoc = GLES20.glGetUniformLocation(mCameraShaderProgram, "offsetB");
GLES20.glUniform1f(offsetRLoc, offsetR);
GLES20.glUniform1f(offsetGLoc, offsetG);
GLES20.glUniform1f(offsetBLoc, offsetB);
if (touchX < 1000000000 && touchY < 1000000000)
{
//creates a Paint object
Paint yellowPaint = new Paint();
//makes it yellow
yellowPaint.setColor(Color.YELLOW);
//sets the anti-aliasing for texts
yellowPaint.setAntiAlias(true);
yellowPaint.setTextSize(70);
if (isFirstTime)
{
textBitmap = Bitmap.createBitmap(mSurfaceWidth, mSurfaceHeight, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(textBitmap);
}
bitmapCanvas.drawText("Test Text", touchX, touchY, yellowPaint);
if (isFirstTime)
{
textureId = addTexture(textBitmap, "textBitmap");
isFirstTime = false;
}
else
{
updateTexture(textureId, textBitmap);
}
touchX = 1000000000;
touchY = 1000000000;
}
}
/**
* take touch points on that textureview and turn them into multipliers for the color channels
* of our shader, simple, yet effective way to illustrate how easy it is to integrate app
* interaction into our glsl shaders
* #param rawX raw x on screen
* #param rawY raw y on screen
*/
public void setTouchPoint(float rawX, float rawY)
{
this.touchX = rawX;
this.touchY = rawY;
}
}
Please help guys, it's been a month and I am still stuck with the same app :( and have no idea about opengl. Two weeks and I'm trying to use this project for my app, and nothing is being rendered on the video.
Thanks in advance!
Here's a rough outline that should work, but it's quite a bit of work:
Set up a android.media.MediaRecorder for recording the video and audio
Get a Surface from MediaRecorder and set up an EGLImage from it (https://developer.android.com/reference/android/opengl/EGL14.html#eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int) ); you'll need a whole OpenGL context and setup for this. Then you'll need to set that EGLImage as your render target.
Create a SurfaceTexture within that GL context.
Configure camera to send data to that SurfaceTexture
Start the MediaRecorder
On each frame received from camera, convert the drawing done by the user to a GL texture, and composite the camera texture and the user drawing.
Finally, call glSwapBuffers to send the composited frame to the video recorder

Creating an Eraser for an Android Drawing App

I'm working on a drawing application and am pretty close to release but I'm having issues with the eraser part of the app. I have 2 main screens (fragments) one is just a blank white canvas that the user can draw on with some options and so on. The other is a note taking fragment. This note taking fragment looks like notebook paper. So for erasing on the drawing fragment, I can simply use the background of the canvas and the user wont know the difference. On the note fragment though I cannot do this beacuse I need to keep the background in tact. I have looked into PorterDuffer modes and have tried the clear version and tried to draw onto a separate bitmap but nothing has worked. If there was a way to control what gets draw ontop of what then that would be useful. I'm open to any suggestions, I can't seem to get anything to work.
Ive also played with enabling a drawing cache before erasing and that doesn't work. In addition I tried hardware enabling and that made my custom view behave oddly. Below is the relavent code. My on draw methods goes through a lot of paths because I am querying them in order to allow for some other functionallity.
#Override
protected void onDraw(Canvas canvas) {
//draw the backgroumd type
if(mDrawBackground) {
//draw the background
//if the bitmap is not null draw it as the background, otherwise we are in a note view
if(mBackgroundBitmap != null) {
canvas.drawBitmap(mBackgroundBitmap, 0, 0, backPaint);
} else {
drawBackgroundType(mBackgroundType, canvas);
}
}
for (int i = 0; i < paths.size(); i++ ) {
//Log.i("DRAW", "On draw: " + i);
//draw each previous path.
mDrawPaint.setStrokeWidth(strokeSizes.get(i));
mDrawPaint.setColor(colors.get(i));
canvas.drawPath(paths.get(i), mDrawPaint);
}
//set paint attributes to the current value
mDrawPaint.setStrokeWidth(strokeSize);
mDrawPaint.setColor(mDrawColor);
canvas.drawPath(mPath, mDrawPaint);
}
and my draw background method
/**
* Method that actually draws the notebook paper background
* #param canvas the {#code Canvas} to draw on.
*/
private void drawNoteBookPaperBackground(Canvas canvas) {
//create bitmap for the background and a temporary canvas.
mBackgroundBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBackgroundBitmap);
//set the color to white.
mBackgroundBitmap.eraseColor(Color.WHITE);
//get the height and width of the view minus padding.
int height = getHeight() - getPaddingTop() - getPaddingBottom();
int width = getWidth() - getPaddingLeft() - getPaddingRight();
//figure out how many lines we can draw given a certain line width.
int lineWidth = 50;
int numOfLines = Math.round(height / lineWidth);
Log.i("DRAWVIEW", "" + numOfLines);
//iterate through the number of lines and draw them.
for(int i = 0; i < numOfLines * lineWidth; i+=lineWidth) {
mCanvas.drawLine(0+getPaddingLeft(), i+getPaddingTop(), width, i+getPaddingTop(), mNoteBookPaperLinePaint);
}
//now we need to draw the vertical lines on the left side of the view.
float startPoint = 30;
//set the color to be red.
mNoteBookPaperLinePaint.setColor(getResources().getColor(R.color.notebook_paper_vertical_line_color));
//draw first line
mCanvas.drawLine(startPoint, 0, startPoint, getHeight(), mNoteBookPaperLinePaint);
//space the second line next to the first one.
startPoint+=20;
//draw the second line
mCanvas.drawLine(startPoint, 0, startPoint, getHeight(), mNoteBookPaperLinePaint);
//reset the paint color.
mNoteBookPaperLinePaint.setColor(getResources().getColor(R.color.notebook_paper_horizontal_line_color));
canvas.drawBitmap(mBackgroundBitmap, 0, 0, backPaint);
}
To all who see this question I thought I would add how I solved the problem. What I'm doing is creating a background bitmap in my custom view and then passing that to my hosting fragment. The fragment then sets that bitmap as its background for the containing view group so that when I use the PorterDuff.CLEAR Xfermode, the drawn paths are cleared but the background in the fragment parent remains untouched.

LibGdx How to repeat background?

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

AndEngine GLES 2 - black screen, no errors

I am writing a game for Android using AndEngine GLES 2. Everything was working properly - I had a background image, there were sprites moving around and even some music - until recently I tried something new (I wanted to be able to switch between two different scenes) when the display turned black.
I could still execute the game and there were no error shown. All log entries I made during the game were shown, even the music was playing so I knew the game was running "properly", but I couldn't see any image. Nothing. All black.
So I thought, changing everything back to before this "error" appeared, would do the trick. But still the screen is black.
I even tried commenting everything out but the background image - nothing.
Now if it is not too much to ask, could anyone please look over this short piece of code and tell me what is wrong there?
This are the variables I use:
private SmoothCamera camera;
private BitmapTextureAtlas bitmapTextureAtlas;
private Scene scene;
private Sprite background;
The EngineOptions I never changed, so they should be alright.
#Override
public EngineOptions onCreateEngineOptions() {
float positionX = 80f; // horizontal (x) position of the camera
float positionY = 280f; // vertical (y) position of the camera
float velocityX = 200f; // velocity of the horizontal camera movement
float velocityY = 200f; // velocity of the vertical camera movement
float zoomFactor = 1f; // the camera's zoom Factor (standard := 1)
this.camera = new SmoothCamera(positionX, positionY, this.getWindowManager().getDefaultDisplay().getWidth(), this.getWindowManager().getDefaultDisplay().getHeight(), velocityX, velocityY, zoomFactor);
EngineOptions options = new EngineOptions(true, ScreenOrientation.LANDSCAPE_SENSOR, new RatioResolutionPolicy(this.camera.getWidth(), this.camera.getHeight()), this.camera);
return options;
}
Here I create the TextureAtlas and load a background image.
#Override
protected void onCreateResources() {
// create the TextureAtlas
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
this.bitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 1024, 1600, TextureOptions.NEAREST);
// background
this.background = new Sprite(0, 0, BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.bitmapTextureAtlas, this, "background.png", 0, 0, 1, 1), this.getVertexBufferObjectManager());
this.mEngine.getTextureManager().loadTexture(this.bitmapTextureAtlas);
}
And finally the Scene is instantiated and the background gets attached.
#Override
protected Scene onCreateScene() {
this.scene = new Scene();
this.scene.attachChild(this.background);
return this.scene;
}
Now why would this small Activity not show? I forgot: its a SimpleBaseGameActivity.
Well, since AndEngine GLES2 is not running on the emulator, I have to use my phone (Samsung Galaxy GIO) and can't test the app on another machine.
Did anyone stumble upon a similar problem?
Any help is really much appreciated and thank you for your time !
Christoph
I think the problem is here:
this.bitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 1024, 1600, TextureOptions.NEAREST);
The dimensions of the Atlas are supposed to be powers of 2.

Categories

Resources