Stuck with view scrolling to follow sprite - java

I'm very new to programming and am currently trying to make a simple game for android. The problem I'm having is the way the view is scrolling. By my logic, I believe the sprite should stay in the center of the screen, but it doesn't. The view does follow the sprite, but not at the same speed if that makes sense. As in the view kind of lags behind. It's not jumpy so I know it's not running slowly. What surprises me though is I'm setting my scrolling rectangle equal to player x location - display width, and then same for the y axis. So What I'm hoping you guys can help me out with is figure out why the sprite isn't staying in the center of the view. Any help will be greatly appreciated.
Thanks.
private static Rect displayRect = null; //rect we display to
private Rect scrollRect = null; //rect we scroll over our bitmap with
Display display = getWindowManager().getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
displayRect = new Rect(0, 0, displayWidth, displayHeight);
scrollRect = new Rect(0, 0, displayWidth, displayHeight);
//Setting the new upper left corner of the scrolling rectangle
newScrollRectX = ((int)player.getXLocation() - (displayWidth/2));
newScrollRectY = ((int)player.getYLocation() - (displayHeight/2));
//This is in my onDraw method, so it updates right before the player is drawn
scrollRect.set(newScrollRectX, newScrollRectY,
newScrollRectX + displayWidth, newScrollRectY + displayHeight);
//bmLargeImage is a 1440X1440 background
canvas.drawBitmap(bmLargeImage, scrollRect, displayRect, paint);
canvas.drawBitmap(player.getBitmap(),(float)player.getX(player.getSpeedX()), (float)player.getY(player.getSpeedY()), null);

My first guess would be you are using integer calculations and should use floating point calculations instead.
int test = 10 / 3; // == 3
float test2 = 10 / 3.0; // == 3.33333...
This would explain the 'jumping'.
Beware, I am not certain whether all android phones have FPUs. You might have to use fixed point calculations instead to guarantee proper performance.

Related

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

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.

How to set size, position, and color, of one RadialGradient, or set XferMode on GradientDrawable

This is my first question here on Stackoverflow, so go easy on me. I'm trying to draw a radial bloom effect around a point, and found RadialGradient, as well as GradientDrawable. However neither fully gives a solution.
Here is how I'm doing the drawing right now:
//global
PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
Paint mainP = new Paint();
Paint whiteP = new Paint();
whiteP.setColor(Color.WHITE);
RadialGradient gradient;
// in a drawing method with a canvas
gradient = new RadialGradient((int) x, (int) y, tempRadius, mainP.getColor(),
0x00000000, Shader.TileMode.CL
mainP.setShader(gradient);
mainP.setXfermode(xferMode);
canvas.drawCircle((int) x, (int) y, tempRadius, mainP);
gradient = new RadialGradient((int) x, (int) y, tempRadius/2, whiteP.getColor(),
0x00000000, Shader.TileMode.CLAMP);
whiteP.setXfermode(xferMode);
whiteP.setShader(gradient);
canvas.drawCircle((int) x, (int) y, tempRadius/2, whiteP);
This will give the expected result:
Screenshot
However the new RadialGradient builds up in memory every frame per dot. Which becomes a problem later obviously. The only public thing in that class is a constructor, so all you can do with RadialGradient is create a new one every time you need a new size, position or color. The reason I want to do it this way is because you assign the gradient to the Paint object your going to draw it with, which allows you to use it's setXferMode().
The other way, using the GradientDrawable, does allow you to just create one instance of itself, so you can change the size, position, and color, but the Paint object it uses to paint itself is private, so you can't set the XferMode on it. Which is necessary so that if you have more than one dot, they don't just paint over one another. It has a colorfilter, but it doesn't look like colorfilter worries about the destination, only a specified color and the source.
Since I am new, i can only post two links, and instead of posting just two pictures, I'll link back to the same question I wrote on reddit which has all the pictures for context. (and no answers yet, which is why I came here, ha ha)
https://www.reddit.com/r/learnandroid/comments/590uce/having_a_shader_issue_using_radialgradient_and/
So, how should this be done, I know I need one class or the other. From what I can tell, RadialGradient would be perfect if I didn't have to create a new one every time I needed a different size, position, or color. GradientDrawable would be equally great since you can just have one instance, but I need to be able to set the XferMode on the paint it uses. Is there another class, or am I missing something between the two of these?
Thanks!!
So, while I did find a solution, it still lead to more issues. The solution I found was partly here. The only thing it was missing was being able to change the color of the preallocated RadialGradient bitmap. So I came up with this:
// Global
int tempRadius;
Paint p = new Paint();
RadialGradient gradient;
Bitmap circleBitmap = Bitmap.createBitmap((int) (tempRadius * 2.0f), (int) (tempRadius * 2.0f),
Bitmap.Config.ARGB_8888);
Canvas tempCanvas = new Canvas(circleBitmap);
Rect gradBMPRect = new Rect(0,0,200,200);
Rect destRect = new Rect();
int[] hsv = {0,1,1};
PorterDuffColorFilter[] myColors = new PorterDuffColorFilter[360];
PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
// Initialize
gradient = new RadialGradient(tempRadius, tempRadius, tempRadius, Color.WHITE, 0x00000000, Shader.TileMode.CLAMP);
circleBitmap = Bitmap.createBitmap((int) (100 * 2.0f), (int) (100 * 2.0f),
Bitmap.Config.ARGB_8888);
tempCanvas = new Canvas(circleBitmap);
for(int i = 0; i < 360; i++){
hsv[0] = i;
myColors[i] = new PorterDuffColorFilter(Color.HSVtoColor(hsv), PorterDuff.Mode.MULTIPLY)
}
// update/draw
p.setDither(true);
p.setShader(gradient);
tempCanvas.drawCircle(100, 100, 100, p);
p.setXfermode(xferMode);
if(p.getColor() != mainP.getColor()) {
p.setColorFilter(myColors[hue]);
p.setColor(mainP.getColor());
destRect.set((int)x-tempRadius,(int)y-tempRadius,(int)x+tempRadius,(int)y+tempRadius);
canvas.drawBitmap(circleBitmap,gradBMPRect,destRect,p);
p.setColorFilter(null);
destRect.set((int)x-(tempRadius/2),(int)y-(tempRadius/2),(int)x+(tempRadius/2),(int)y+(tempRadius/2));
canvas.drawBitmap(circleBitmap,gradBMPRect,destRect,p);
With this the RadialGradient is used to create a greyscaled bitmap, then a pallette of 360 PorterDuffColorFilters is made using HSVtoColor. All 360 have their modes set to multiply. When drawing these the paint used to draw the bitmap is set use the ColorFilter specified by its hue. The colorfilter shades the greyscaled bitmap to whatever color the filter is. And no more memory leaks :)
This took longer to render the bitmap of a RadialGradient vs rendering a circle with a RadialGradient though. With 30 circles it took my Galaxy S5 15-20ms per frame draw, while the bitmaps took around 30-35ms. It could probably get worked out though with a little more work and adjustment.

Rotating a Bitmap around a point NOT center to bitmap

I have a bitmap that I would like to rotate about a point on a canvas. The point I want to rotate it about is not the center of the bitmap. I am using a matrix. Here is an example of what I have.
Bitmap image = ContentManager.getInstance().getImage(imageId);
Matrix matrix = new Matrix();
matrix.setTranslate(-image.getWidth()/2f, -image.getHeight()/2f);
matrix.postRotate(rotationDegrees);
matrix.postTranslate(x / scaleX, y / scaleY);
matrix.postScale(scaleX, scaleY);
paint.setAlpha(alpha);
canvas.drawBitmap(image, matrix, paint);
I want to manipulate this code slightly to not rotate around the bitmap's center point but a different point. To illustrate more clearly I have created this picture:
.
I have tried everything I can think of from setting
matrix.setTranslate(-image.getWidth()/2f, -image.getHeight()/2f);
to
matrix.setTranslate(pivotPoint.x, pivotPoint.y);
and a lot of other stuff. The result is the bitmap is always way off from where I expected it. (eg. rotate it about the center of the screen 90 degrees would put the bitmap 90 degrees from where it was and consequently would be rotated.) The bitmap always seems to rotate about its center point and then ends up in a random spot on the screen.
After much messing around and find this very difficult or buggy, not sure which, found the easiest solution to this is to find the new center of the bitmap and drop the image there instead, seem more complicated but it works where plain rotation/translation wasn't.
float angle;
float radius;
Bitmap wheelSelectBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
Matrix matrix = new Matrix();
Point pivotPoint = new Point();
pivotPoint.set(pivotPoint.x, pivotPoint.y)
Point newCenter = new Point();
newCenter.set((int)(pivotPoint.x + (radius * Math.cos(angle)), (int)(pivotPoint.y - (radius * Math.sin(angle)));
matrix.postTranslate(newCenter.x - (bitmap.getWidth()/2f), newCenter.y - (bitmap.getHeight()/2f));
matrix.postRotate(angle, newCenter.x, newCenter.y);
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), null, true);
canvas.drawBitmap(bitmap, matrix, null);
This might not be perfect but working this way solved the problem for me and stopped bitmaps flying around all over the shop. It also rotates clockwise by default unlike your diagram so just use -angle for counter-CW. Not sure what is going on here as this code definitely failed to get the desired effect for me:
matrix.postTranslate(pivotPoint.x, pivotPoint.y);
matrix.postRotate(angle);
matrix.postTranslate(radius - (bitmap.getWidth()/2f), -bitmap.getHeight()/2f);
Cant see what is wrong with logic here ? But in my case the bitmap was not visible in the view here.
When rotating an object, it will rotate around the origin (upper left corner). You'll want to first translate the bitmap so the pivot point becomes (0, 0), rotate the bitmap then translate back to it's original position.
you could try something like this:
matrix.setTranslate(-px, -py);
matrix.postRotate(rotationDegrees);
matrix.setTranslate(px, py);
// Then do other things.

Libgdx Box2D pixel to meter conversion?

When trying to program a game using Box2D, I ran into a problem with Box2D. I filled in pixel numbers for the lengths of the the textures and sprites to create a box around it. Everything was at the right place, but for some reason everything went very slowly. By looking on the internet I found out that if you didn't convert pixels to meters box2d might handle shapes as very large objects. this seemed to be a logical cause of everything moving slowly.
I found similar questions on this site, but the answers didn't really seem to help out. in most of the cases the solution was to make methods to convert the pixel numbers to meters using a scaling factor. I tried this out, but everything got misplaced and had wrong sizes. this seemed logical to me since the numbers where changed but had the same meaning.
I was wondering if there is a way to make the pixels mean less meters, so everything whould be at the same place with the same (pixel) size, but mean less meters.
If you have a different way which you think might help, I whould also like to hear it..
Here is the code i use to create the camera
width = Gdx.graphics.getWidth() / 5;
height = Gdx.graphics.getHeight() / 5;
camera = new OrthographicCamera(width, height);
camera.setToOrtho(false, 1628, 440);
camera.update();
This is the method I use to create an object:
public void Create(float X, float Y, float Width, float Height, float density, float friction, float restitution, World world){
//Method to create an item
width = Width;
height = Height;
polygonDef = new BodyDef();
polygonDef.type = BodyType.DynamicBody;
polygonDef.position.set(X + (Width / 2f), Y + (Height / 2f));
polygonBody = world.createBody(polygonDef);
polygonShape = new PolygonShape();
polygonShape.setAsBox(Width / 2f, Height / 2f);
polygonFixture = new FixtureDef();
polygonFixture.shape = polygonShape;
polygonFixture.density = density;
polygonFixture.friction = friction;
polygonFixture.restitution = restitution;
polygonBody.createFixture(polygonFixture);
}
To create an item, in this case a table, I use the following:
Table = new Item();
Table.Create(372f, 60f, 152f, 96f, 1.0f, 0.2f, 0.2f, world);
The Sprites are drawn on the item by using the following method:
public void drawSprite(Sprite sprite){
polygonBody.setUserData(sprite);
Utils.batch.begin();
if(polygonBody.getUserData() instanceof Sprite){
Sprite Sprite = (Sprite) polygonBody.getUserData();
Sprite.setPosition(polygonBody.getPosition().x - Sprite.getWidth() / 2, polygonBody.getPosition().y - Sprite.getHeight() / 2);
Sprite.setRotation(polygonBody.getAngle() * MathUtils.radiansToDegrees);
Sprite.draw(Utils.batch);
}
Utils.batch.end();
}
The sprites also have pixel sizes.
Using this methods it displays the images at the right places, but everything moves slowly.
I was wondering how or if I whould have to change this to make the objects move correctly, and / or mean less. Thanks in advance.
Box2D is an entirely independent of the graphics library that you use. It doesn't have any notion of sprites and textures. What you read online is correct, you'll have to convert pixels to metres, as Box2D works with metres(the standard unit for distance).
For example, if you drew a sprite of size 100x100 pixels, that's the size of the sprite that you want the user to see on the screen. In real world the size of the object should be in metres and not in pixels - so if you say 1px = 1m, then that'll map the sprite to a gigantic 100x100 meter object. In Box2D, large world objects will slow down calculations. So what you need to do is map the 100 pixels to a smaller number of meters, say, 1 meter - thus 100x100px sprite will be represented in Box2D world by a 1x1 meter object.
Box2D doesn't work well with very small numbers and very large numbers. So keep it in between, say between 0.5 and 100, to have good performance.
EDIT:
Ok. Now I get your question.
Don't code to pixels. Its as simple as that. I know it'll take some time to understand this(it took for me). But once you get the hang of it, its straight forward.
Instead of pixels, use a unit, say, you call it meter.
So we decide our viewport should be say 6mx5m.
So initialization is
Constants.VIEWPORT_WIDTH = 6;
Constants.VIEWPORT_HEIGHT = 5;
...
void init() {
camera = new OrthographicCamera(Constants.VIEWPORT_WIDTH, Constants.VIEWPORT_HEIGHT);
camera.position.set(Constants.VIEWPORT_WIDTH/2, Constants.VIEWPORT_HEIGHT/2, 0);
camera.update();
}
Once you know the actual width and height, you call the following function in order to maintain aspect ratio:
public void resize(int width, int height) {
camera.viewportHeight = (Constants.VIEWPORT_WIDTH / width) * height;
camera.update();
}
resize() can be called anytime you change your screen size(eg: when you screen orientation changes). resize() takes the actual width and height (320x480 etc), which is the pixel value.
Now you specify you sprite sizes, their positions etc. in this new world of size 6x5. You can forget pixels. The minimum size of the sprite that'll fill the screen will be 6x5.
You can now use the same unit with Box2D. Since the new dimensions will be smaller, it won't be a problem for Box2D. If I remember correctly Box2D doesn't have any unit. We just call it meter for convenience sake.
Now you might ask where you specify the dimensions of the window. It depends on the platform. Following code shows a 320x480 windowed desktop game:
public class Main {
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "my-game";
cfg.useGL20 = false;
cfg.width = 480;
cfg.height = 320;
new LwjglApplication(new MyGame(), cfg);
}
}
Our camera will intelligently map the 6x5 viewport to 480x320.

The View got Pixelated during Animation to Tilt

The view got pixilated during animation I just wanted to attain a little tilt while the I try to scroll. I am using the Universal-Image-Library to hanle the animation. I'd like to attain a 3D look when tilting the view.
The first picture, is what I want.
But this picture below, I what I have. The View below got pixilated.
private void rotateLeftFrag(View af) {
if (af != null) {
ObjectAnimator.ofFloat(af, "rotationY", 5, 0)
.setDuration(100).start();
}
}
ObjectAnimator com.nineoldandroids.animation.ObjectAnimator.ofFloat(Object target, String
propertyName, float... values)
Are there any resolve to this to attain smooth animation or titling of the view? Thanks
Update:
float density = getResources().getDisplayMetrics().density;
float scale = getResources().getDisplayMetrics().density;
af.setCameraDistance(density * scale);
ObjectAnimator.ofFloat(af, "rotationY", .5f, 0).setDuration(500).start();
I think this video could help you:
http://www.youtube.com/watch?v=pMcu35-tVls
At 2:10 the guy talks about adding 1 extra transparent pixel to each side of a rotating rectangle. That should help smoothing out the edges because they would be inside the rectangle, not on the border.
Link to the source code is below the video.
In case you can't see it:
http://developer.android.com/shareables/devbytes/CardFlip.zip
Class you want to see is CardView, method bitmapWithBorder:
private static final int ANTIALIAS_BORDER = 1;
/**
* Adding a 1 pixel transparent border around the bitmap can be used to
* anti-alias the image as it rotates.
*/
private BitmapDrawable bitmapWithBorder(BitmapDrawable bitmapDrawable) {
Bitmap bitmapWithBorder = Bitmap.createBitmap(bitmapDrawable.getIntrinsicWidth() +
ANTIALIAS_BORDER * 2, bitmapDrawable.getIntrinsicHeight() + ANTIALIAS_BORDER * 2,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmapWithBorder);
canvas.drawBitmap(bitmapDrawable.getBitmap(), ANTIALIAS_BORDER, ANTIALIAS_BORDER, null);
return new BitmapDrawable(getResources(), bitmapWithBorder);
}
Please try to turn off hardware rendering
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
mHeaderImage.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Categories

Resources