I've created a World with earth gravity and I place an entity in the scene (contains a sprite and a Body) and it falls down slowly like a balloon.
Here's how I set the World:
world = new World(new Vector2(0, -GRAVITY_EARTH), true);
and here's the relevant Box2D code for the Body etc:
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(positionX, positionY);
// Create our body in the world
body = world.createBody(bodyDef);
// Grab the first idle sprite to use as initial
Sprite sprite = idleSprites.get(0);
// Create a box shape to represent our hit box
PolygonShape box = new PolygonShape();
box.setAsBox(sprite.getWidth() / 2f, sprite.getHeight() / 2f);
// Create a fixture definition to apply our shape
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = box;
fixtureDef.density = 1f; // Give it full density
fixtureDef.friction = 0f; // Give it no friction
fixtureDef.restitution = 0f; // Make it not bouncy
// Create our fixture and attach it to the body
fixture = body.createFixture(fixtureDef);
// Remember to dispose of any shapes after you're done with them!
// BodyDef and FixtureDef don't need disposing, but shapes do.
box.dispose();
and how I draw the sprite:
TextureRegion keyFrame = idleAnimation.getKeyFrame(stateTimeSeconds, true);
Vector2 position = body.getPosition();
batch.draw(keyFrame, position.x - keyFrame.getRegionWidth() / 2f, position.y - keyFrame.getRegionHeight() / 2f);
and the relevant code in the render() method:
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
final float deltaTime = Gdx.graphics.getDeltaTime();
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
spriteBatch.draw(sky, 0, 0);
tim.animate(spriteBatch, deltaTime);
spriteBatch.draw(floor, 0, 0);
spriteBatch.end();
// Render physics for debug
debugRenderer.render(world, camera.combined);
// Run physics
doPhysicsStep(deltaTime);
}
private void doPhysicsStep(float deltaTime) {
// fixed time step
// max frame time to avoid spiral of death (on slow devices)
float frameTime = Math.min(deltaTime, 0.25f);
accumulator += frameTime;
while (accumulator >= TIME_STEP) {
world.step(TIME_STEP, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
accumulator -= TIME_STEP;
}
}
I've tried changing the density of the fixture, and I've tried changing the gravity value, and I've tried changing the TIME_STEP and nothing is having an effect. The body just falls down slowly like a balloon.
It looks to me like you're using pixels as your units, box2d treats every unit as a meter and so you're hitting the internal limit of 2.0 units per time step, see http://www.iforce2d.net/b2dtut/gotchas. You can get around this by setting up your camera in world units instead of pixels, you have to scale all your sprites and positions to fit into world units instead of pixels though.
Something like this may do:
float w = (float) Gdx.graphics.getWidth();
float h = (float) Gdx.graphics.getHeight();
camera = new OrthographicCamera(30, 30 * (h / w));
the way the camera is set up here allows the height of the viewport to be variable based on the screens' aspect ratio.
Then to setup the sprite change it by a set factor
sprite.setSize(sprite.getWidth / PIX2M, sprite.getHeight / PIX2M);
where PIX2M is a static field defining how many pixels are a meter in box2d
Alternatively you can set the dimensions of the sprite explicitly to a value which makes physical sense and with the aspect ratio of the original image(my personal preference) . So an image of a person which is 100 x 500 for example could be set like this.
sprite.setSize(.4f, 2f);
meaning the person is 2 meters high and .4 meters wide. Also with this method you don't need a PIX2M conversion factor and you will always know the exact size of your body. Since you set the camera to a specific number of world units, 30 in this case, the sprite will take up the same amount of room on the screen no matter the resolution of the display.
Related
i'm using LibGDX and trying to learn box2D, but this units conversions are confusing me, what i think: i got a 256x256 pixels image and want to create a body representing this image, using the 1:32 scale, so everytime i want to pass values to the box2D scale i must divide it by 32 or mutiply by 1/32(it's the same equation), and everytime i want to get values from this world to pixel scale i must mutiply it by 32, but the problems still the same: can't get good simulations, i'll put my code here for you see how i'm doing things(i'll put the variables too so you can just ctrl+c and ctrl+v):
private SpriteBatch batch;
private ShapeRenderer srender;
private Texture img;
private World world;
private Body bad, bridge;
private OrthographicCamera cam, cam2;
private Box2DDebugRenderer render;
#Override
public void create () {
srender = new ShapeRenderer();
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
cam = new OrthographicCamera(500f, 500f);
cam.translate(250f, 250f);
cam.update();
//Used to draw the box2D world scaled to the pixels size
cam2 = new OrthographicCamera(500 * 0.03125f, 500 * 0.03125f);
cam2.translate(250f * 0.03125f, 250f * 0.03125f);
cam2.update();
render = new Box2DDebugRenderer();
world = new World(new Vector2(0f, -10f), true);
BodyDef bdef = new BodyDef();
bdef.type = BodyType.DynamicBody;
bad = world.createBody(bdef);
PolygonShape pshape = new PolygonShape();
pshape.setAsBox(img.getWidth() * 0.03125f, img.getHeight() * 0.03125f);
FixtureDef fdef = new FixtureDef();
fdef.shape = pshape;
bad.createFixture(fdef);
/*Criando a ponte*/
bdef.type = BodyType.StaticBody;
bridge = world.createBody(bdef);
pshape.setAsBox(500f * 0.03125f, 5f * 0.03125f);
bridge.createFixture(fdef);
bad.setTransform(new Vector2(250f * 0.03125f, 500f * 0.03125f) , 0);
bridge.setTransform(new Vector2(250f * 0.03125f, 0f * 0.03125f), 0);
batch.setProjectionMatrix(cam.combined);
srender.setProjectionMatrix(cam.combined);
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(img, (bad.getPosition().x - img.getWidth()/2 * 0.03125f) * 32,
(bad.getPosition().y - img.getHeight()/2 * 0.03125f) * 32);
batch.end();
render.render(world, cam2.combined);
srender.begin(ShapeRenderer.ShapeType.Filled);
srender.circle(250f, 500f, 5f);
srender.circle(250f, 0f, 5f);
srender.end();
world.step(1/60f, 6, 2);
}
if you run this code you will see that the box created still not fitting the image size, the image stop walking on the middle of the screen while it should stop only at the bottom, can anyone help me here? thanks for attention.
Ps:i have already heard about changing the viewport, but i'm still trying to learn this conversions, after that i'll go look for the viewports.
I am really confused with two examples related to viewport and orthagraphic. Although i understand that Viewport is the size of the dimensions we set to view on the screen and camera projects that. I am learning libgdx and cannot finish through orthographic camera and viewport examples which have left me completely confused. the code runs fine for both examples and with proper result on screen.
here's one example in which camera.position.set is used to position the camera.
public class AnimatedSpriteSample extends GdxSample {
private static final float WORLD_TO_SCREEN = 1.0f / 100.0f;
private static final float SCENE_WIDTH = 12.80f;
private static final float SCENE_HEIGHT = 7.20f;
private static final float FRAME_DURATION = 1.0f / 30.0f;
private OrthographicCamera camera;
private Viewport viewport;
private SpriteBatch batch;
private TextureAtlas cavemanAtlas;
private TextureAtlas dinosaurAtlas;
private Texture background;
private Animation dinosaurWalk;
private Animation cavemanWalk;
private float animationTime;
#Override
public void create() {
camera = new OrthographicCamera();
viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);
batch = new SpriteBatch();
animationTime = 0.0f;
...
...
..
camera.position.set(SCENE_WIDTH * 0.5f, SCENE_HEIGHT * 0.5f, 0.0f);
Here's another example which does not use camera.position.set and still the result is the same.
#Override
public void create() {
camera = new OrthographicCamera();
viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);
batch = new SpriteBatch();
oldColor = new Color();
cavemanTexture = new Texture(Gdx.files.internal("data/caveman.png"));
cavemanTexture.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
}
#Override
public void dispose() {
batch.dispose();
cavemanTexture.dispose();
}
#Override
public void render() {
Gdx.gl.glClearColor(BACKGROUND_COLOR.r,
BACKGROUND_COLOR.g,
BACKGROUND_COLOR.b,
BACKGROUND_COLOR.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
int width = cavemanTexture.getWidth();
int height = cavemanTexture.getHeight();
float originX = width * 0.5f;
float originY = height * 0.5f;
// flipX, flipY
// Render caveman centered on the screen
batch.draw(cavemanTexture, // Texture itselft
-originX, -originY, // pass in the world space coordinates where we to draw, Considering the camera is centered at (0,0). by default we need to position
// out cavement at -originX, -originY.
originX, originY, // coordinates in pixels of our texture that we consider to be the origin starting from the bottom-left corner.
// in our case, we want the origin to be the center of the texture. then we pass the dimensions of the texture and the scale
// and the scale along both axes (x and Y).
width, height, // width, height
WORLD_TO_SCREEN, WORLD_TO_SCREEN, // scaleX, scaleY
0.0f, // rotation
0, 0, // srcX, srcY
width, height, // srcWidth, srcHeight
false, false); // flipX, flipY
What is really confusing me is why does it not use camera.position.set on the second example to adjust the camera's view and why is it important to use this on the first example.
I really hope this question is legit and makes sense. I have searched the forum here and couldnt find any clues. Hope someone can guide in the right direction.
Many Thanks.
In the first example a 2 dimensional vector has been initialized for the position of the camera the x direction and the y direction. This for the specifically the camera.
camera = new OrthographicCamera();
So, this code creates a camera object from the OrthographicCamera class created by libgdx creators. Check out the documentation for the class here from that class you can see when that it is constructed it accepts both the viewport_height and viewport_width. (in your example you've left it blank, so these are 0 for the time being.)
viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);
This line of code defines the width, height and which camera should be used for the viewport. check out the documentation for FitViewport class here
So when camera.position.set is called, it sets for the x and y direction based on the viewport's width and height. This whole example defines the viewport dimensions for the overall viewport.
The difference between this and the second example is that the camera is set around the texture that has been loaded onto the screen. So the viewport's x and y direction has been positioned and the width, height, originX, originY of the texture/camera has been defined also:
int width = cavemanTexture.getWidth();
int height = cavemanTexture.getHeight();
float originX = width * 0.5f;
float originY = height * 0.5f;
Libgdx then allows you to draw the texture using the spritebatch class to draw both the texture and the viewport surrounding that texture.
Summary
Example one allows you to define a viewport on it's own, without any textures being drawn. This will allow you to draw multiple textures with the same viewport being set (a normal process of game creation)
But in Example two if you wanted the viewport to say, follow the main character around on the screen. you can define the viewport surrounding the texture to thus follow that texture.
Personally, i'd always pursue the first example as you can define a viewport for any game width or height and then i'd create a second viewport ontop to follow any textures i've drawn on the screen. They both work, just for different reasons.
Hope this helps you clear things up.
Happy coding,
Bradley.
I'm making a game in libgdx which includes the player being able to move vertically beyond the set screen size.
As for my question, if I have the screen size set at a certain width and height, what is required to make the actual game world larger for the camera to follow the player?
This is of course my targeted screen size in the Main game class:
public static final int WIDTH = 480, HEIGHT = 800;
Below that I currently have :
public static final int GameHeight = 3200;
GameHeight is the value I test for whether the player is going out of bounds.
Here is the problem. With this code, the player is centered on the screen, and moves horizontally, rebounding off the screen bounds (As it would without the camera, but neglecting the change in y-position)
public GameScreen(){
cam = new OrthographicCamera();
cam.setToOrtho(false, 480, 800);
}
#Override
public void render(float delta) {
// TODO Auto-generated method stub
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.position.y = player.getPosition().y;
cam.update();
batch.setProjectionMatrix(cam.combined);
player.update();
player.draw(batch);
}
If I remove:
cam.position.y = player.getPosition().y;
The camera is placed at the bottom of the virtual world and the ball starts at the top (y = 3200) and travels downward. When it reaches y = 800, it shows up as it should.
I've found a lot of examples that indicate in writing that setting the cameras position to the players y position should force the camera to follow the player, whether it's moving up or down, but it either freezes y movement or sets the camera at the bottom the virtual world.
Any help is appreciated, thanks!
I would try doing cam.position.set(player.getPosition().x, player.getPosition().y). This will make the camera follow your player and it should not cause any "freezing."
private val worldTransform = Matrix4()
private val cameraPosition = Vector3()
private val objPosition = Vector3()
private var rot = Quaternion()
private var carTranslation = Vector3(0f, 0f, 0f)
fun focus(obj: BulletObject) {
// worldTransform
obj.entity?.motionState?.getWorldTransform(worldTransform)
// objPosition
worldTransform.getTranslation(objPosition)
obj.entity?.modelInstance?.transform?.getTranslation(carTranslation)
// get rotation
worldTransform.getRotation(rot)
println("rot.angle: ${rot.getAngleAround(Vector3.Y)}")
val rad = Math.toRadians(rot.getAngleAround(Vector3.Y).toDouble())
// pointFromCar
val pointFromCar = Vector2(-3f * sin(rad.toFloat()), -3f * cos(rad.toFloat()));
cameraPosition.set(Vector3(objPosition.x + pointFromCar.x, objPosition.y + 1f, objPosition.z + pointFromCar.y))
// camera set position
camera.position.set(cameraPosition)
camera.lookAt(objPosition)
camera.up.set(Vector3.Y)
camera.update()
}
I'm trying to make a 2D car side scrolling game. I'm using wheel joints to move the car.
Here is the screenshot when car is not moving.
Screenshot of car when not moving
And when the car is moving. You can see sprites are not in correct position.
Screenshot when the car is moving
Here is the constructor of car object.
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(x, y);
//Chassis
PolygonShape chassisShape = new PolygonShape();
chassisShape.setAsBox(width, height);
chassisFixtureDef.shape = chassisShape;
chassis = world.createBody(bodyDef);
// Car Body Sprite
Sprite body = new Sprite(new Texture(Gdx.files.internal("data/body.png")));
body.setSize(5f, 2f);
body.setPosition(0f, 0);
body.setOrigin(body.getWidth() / 2, body.getHeight() / 2);
chassis.setUserData(body);
chassis.createFixture(chassisFixtureDef);
//Left Wheel
CircleShape wheelShape = new CircleShape();
wheelShape.setRadius(height / 1.5f);
wheelFixtureDef.shape = wheelShape;
leftWheel = world.createBody(bodyDef);
//Sprite Test
wheel = new Sprite(new Texture(Gdx.files.internal("data/wheel.png")));
wheel.setSize(1f, 1f);
wheel.setOrigin(wheel.getWidth() / 2, wheel.getHeight() / 2);
leftWheel.setUserData(wheel);
leftWheel.createFixture(wheelFixtureDef);
//Right Wheel
rightWheel = world.createBody(bodyDef);
rightWheel.setUserData(wheel);
rightWheel.createFixture(wheelFixtureDef);
//Left Axis
WheelJointDef def = new WheelJointDef();
def.bodyA = chassis;
def.bodyB = leftWheel;
def.frequencyHz = chassisFixtureDef.density;
def.localAnchorA.set(-width / 2 * 1.7f + wheelShape.getRadius(), -height / 2 * 2.5f);
def.localAxisA.set(Vector2.Y);
def.maxMotorTorque = chassisFixtureDef.density * 30;
leftAxis = (WheelJoint) world.createJoint(def);
def.bodyB = rightWheel;
def.localAnchorA.x *= -1;
rightAxis = (WheelJoint) world.createJoint(def);
And Here is the code to draw sprites relevant to bodies on screen.
for (Body body : bodies)
if (body.getUserData() != null && body.getUserData() instanceof Sprite){
Sprite sprite = (Sprite)body.getUserData();
sprite.setPosition(body.getPosition().x - sprite.getWidth()/2, body.getPosition().y - sprite.getHeight()/2);
sprite.setRotation(body.getAngle() * MathUtils.radiansToDegrees);
sprite.draw(batch);
}
Sorry if couldn't make my question very specific or clear. I'm new to Stackoverflow.
Edit [Solved]
Just placed in render method [Correct]
renderer.render(world, camera.combined);
after gl.clear
I was doing it after drawing everything on screen. [Wrong]
seems like you update your physic after rendering it, because your physic-debugged polygon moved already further than the sprite shows up. You could try to first update your physics and then draw your sprites.
There shouldn't be something wrong with the code / calculations itself.
If you're already doing so it's probably because the updates of your physic simulation updates more frequently than your rendering-loop.
I'd like to apply a pixelate filter to a bitmap. Is there a way to do it without using pixel bender?
You should be able to achieve this with the BitmapData class and its getPixel()/setPixel methods. As for your effect specifically, you could calculate an average color for a given group of pixels, and apply the same color to all of them.
More on pixel manipulation : http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7d64.html
A very simple way to do this is by redrawing a bitmap twice. This code assumes that blockSize is chosen so that your intermediate BitmapData (smaller) aligns with the pixel grid. For example, if your source was 100x100 pixels, a blockSize of 2 will make the intermediate BitmapData 50x50 pixels. Anything more complicated probably requires Math.round() and some fudging.
// Assumes that source.width / blockSize has no remainder
// Same with source.height / blockSize
public function getMosaic( source:BitmapData, blockSize:int ):BitmapData
{
var bitmap:Bitmap = new Bitmap( source );
bitmap.smoothing = true; // blends pixels values
var smaller:BitmapData = new BitmapData( source.width / blockSize,
source.height / blockSize );
var matrix:Matrix = new Matrix();
matrix.scale( 1 / blockSize, 1 / blockSize );
smaller.draw( bitmap, matrix );
bitmap = new Bitmap( smaller );
// Avoid "bitmap.smoothing = true" here to keep it blocky
var blocky:BitmapData = new BitmapData( source.width, source.height );
matrix.invert(); // gives the opposite effect from before
blocky.draw( bitmap, matrix );
smaller.dispose(); // always dispose BitmapData no longer needed
return blocky;
}