LiquidFun particles being sucked in and shot out of objects - libgdx

I'm working on a game using LiquidFun with libgdx. The problem is when I try to have an object sink into the particles the particles get sucked into the top side of the object, whichever direction its facing, and shot out the bottom side of the object, whichever direction its facing. So it's acting very much like a turbine, sucking them in one side and shooting them out of the other, and propeling the object in the direction the top is facing. If the top side is against a wall or the ground it will suck particles in from one of the corners connected to the top side. Here's a gif demonstrating
Here's the code to demonstrate, it's pretty much just a stripped down version of the LiquidFun demo file:
import com.badlogic.gdx.*;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import finnstr.libgdx.liquidfun.ParticleDebugRenderer;
import finnstr.libgdx.liquidfun.ParticleDef.ParticleType;
import finnstr.libgdx.liquidfun.ParticleGroupDef;
import finnstr.libgdx.liquidfun.ParticleSystem;
import finnstr.libgdx.liquidfun.ParticleSystemDef;
import com.badlogic.gdx.physics.box2d.*;
public class Demo extends ApplicationAdapter implements InputProcessor {
private final static float BOX_TO_WORLD = 120.0f;
private final static float WORLD_TO_BOX = 1f / BOX_TO_WORLD;
private OrthographicCamera camera;
private World mWorld;
private ParticleSystem mParticleSystem;
private ParticleDebugRenderer mParticleDebugRenderer;
private Box2DDebugRenderer mDebugRenderer;
private ParticleGroupDef mParticleGroupDef1;
Body boxBody;
#Override
public void create() {
float width = Gdx.graphics.getWidth();
float height = Gdx.graphics.getHeight();
camera = new OrthographicCamera(width, height);
camera.position.set(width / 2, height / 2, 0);
camera.update();
Gdx.input.setInputProcessor(this);
createBox2DWorld(width, height);
createParticleStuff(width, height);
mDebugRenderer = new Box2DDebugRenderer();
mParticleDebugRenderer = new ParticleDebugRenderer(new Color(0, 1, 0, 1), mParticleSystem.getParticleCount());
}
private void createBox2DWorld(float width, float height) {
mWorld = new World(new Vector2(0, -9.8f), false);
/* Bottom */
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.StaticBody;
bodyDef.position.set(width * WORLD_TO_BOX / 2f, height * (2f / 100f) * WORLD_TO_BOX / 2f);
Body ground = mWorld.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(width * WORLD_TO_BOX / 2, height * (2f / 100f) * WORLD_TO_BOX / 2f);
FixtureDef fixDef = new FixtureDef();
fixDef.friction = 0.2f;
fixDef.shape = shape;
ground.createFixture(fixDef);
shape.dispose();
/* Walls */
BodyDef bodyDef1 = new BodyDef();
bodyDef1.type = BodyType.StaticBody;
bodyDef1.position.set(width * (2f / 100f) * WORLD_TO_BOX / 2f, height * WORLD_TO_BOX / 2);
Body left = mWorld.createBody(bodyDef1);
bodyDef1.position.set(width * WORLD_TO_BOX - width * (2f / 100f) * WORLD_TO_BOX / 2f, height * WORLD_TO_BOX / 2);
Body right = mWorld.createBody(bodyDef1);
shape = new PolygonShape();
shape.setAsBox(width * (2f / 100f) * WORLD_TO_BOX / 2f, height * WORLD_TO_BOX / 2);
fixDef.shape = shape;
left.createFixture(fixDef);
right.createFixture(fixDef);
shape.dispose();
}
private void createParticleStuff(float width, float height) {
ParticleSystemDef systemDef = new ParticleSystemDef();
systemDef.radius = 10f * WORLD_TO_BOX;
systemDef.dampingStrength = 0.2f;
systemDef.density = 1.3f;
mParticleSystem = new ParticleSystem(mWorld, systemDef);
mParticleGroupDef1 = new ParticleGroupDef();
mParticleGroupDef1.color.set(1f, 0, 0, 1);
mParticleGroupDef1.flags.add(ParticleType.b2_waterParticle);
mParticleGroupDef1.position.set(width * (30f / 100f) * WORLD_TO_BOX, height * (80f / 100f) * WORLD_TO_BOX);
PolygonShape particleGroupShape = new PolygonShape();
particleGroupShape.setAsBox(width * (70f / 100f) * WORLD_TO_BOX / 2f, width * (70f / 100f) * WORLD_TO_BOX / 2f);
mParticleGroupDef1.shape = particleGroupShape;
mParticleSystem.createParticleGroup(mParticleGroupDef1);
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
mWorld.step(Gdx.graphics.getDeltaTime(), 10, 6, mParticleSystem.calculateReasonableParticleIterations(Gdx.graphics.getDeltaTime()));
Matrix4 cameraCombined = camera.combined.cpy();
cameraCombined.scale(BOX_TO_WORLD, BOX_TO_WORLD, 1);
mParticleDebugRenderer.render(mParticleSystem, BOX_TO_WORLD, cameraCombined);
mDebugRenderer.render(mWorld, cameraCombined);
}
public void createBoxBody(float x, float y){
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(x * WORLD_TO_BOX, y * WORLD_TO_BOX);
boxBody = mWorld.createBody(bodyDef);
PolygonShape shape;
shape = new PolygonShape();
shape.setAsBox(50 * MyGdxGame.WORLD_TO_BOX, 50 * MyGdxGame.WORLD_TO_BOX);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 3;
boxBody.createFixture(fixtureDef);
shape.dispose();
}
#Override
public void dispose() {
mParticleGroupDef1.shape.dispose();
mWorld.dispose();
mDebugRenderer.dispose();
}
#Override
public boolean touchDown(int p1, int p2, int pointer, int button) {
float screenY = Gdx.graphics.getHeight() - p2;
if(boxBody != null){
mWorld.destroyBody(boxBody);
}
createBoxBody(p1, screenY);
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
if(button != Input.Buttons.LEFT && button != Input.Buttons.RIGHT && button != Input.Buttons.MIDDLE) return false;
return true;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(float p1, float p2)
{
// TODO: Implement this method
return false;
}
#Override
public boolean keyDown(int keycode) {return false;}
#Override
public boolean keyUp(int keycode) {return false;}
#Override
public boolean keyTyped(char character) {return false;}
}

Related

sprite's setPosition method does not work

So i have been trying to move the sprite wherever my body moves in the world. So i was using the sprite's setPosition method but turns out it didn't help. My Image just sits at the position (0,0) and i cant understand why.
Here is the code:
package com.example.shapetest;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
class ShapeTest implements ApplicationListener {
SpriteBatch batch;
World world;
OrthographicCamera camera;
Box2DDebugRenderer debugRenderer;
Texture squareTx;
Sprite square;
Body body;
#Override
public void create() {
batch = new SpriteBatch();
world = new World(new Vector2(0,-10),false);
squareTx = new Texture(Gdx.files.internal("sq.png"));
square = new Sprite(squareTx);
debugRenderer = new Box2DDebugRenderer();
camera = new OrthographicCamera();
camera.setToOrtho(false);
BodyDef bd = new BodyDef();
bd.type = BodyType.DynamicBody;
bd.position.set(new Vector2((Gdx.graphics.getWidth() / 2) * 0.01f, Gdx.graphics.getHeight() * 0.01f));
body = world.createBody(bd);
BodyDef bd2 = new BodyDef();
bd2.type = BodyType.StaticBody;
bd2.position.set(new Vector2(Gdx.graphics.getWidth()/2 * 0.01f, 100 * 0.01f));
Body body2 = world.createBody(bd2);
square.setSize(100,100);
PolygonShape shape = new PolygonShape();
shape.setAsBox(0.5f,0.5f);
PolygonShape shape2 = new PolygonShape();
shape2.setAsBox(1.6f,0.3f);
FixtureDef fd = new FixtureDef();
fd.density = 1;
fd.restitution = 0.2f;
fd.shape = shape;
fd.friction = 0.4f;
body.createFixture(fd);
body2.createFixture(shape2, 0f);
shape.dispose();
}
#Override
public void resize(int width, int height) {
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Vector2 pos = body.getPosition();
square.setPosition(pos.x ,pos.y);
camera.update();
batch.setProjectionMatrix(camera.combined);
Matrix4 cameraCopy = camera.combined.cpy();
debugRenderer.render(world, cameraCopy.scl(100f));
world.step(1/60f,10,10);
batch.begin();
square.draw(batch);
batch.end();
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
batch.dispose();
}
}
Here is the result:
(sprite should follow the pink box position)
body.getPosition() return small value so for drawing you need to convert that value into pixel value.
According to you, sprite size is 100 pixels, and it represent dynamic physics body that is polygonShape having size 0.5f * 2 = 1; unit in physics i.e you assuming 1 unit/meter of physics is equal to 100 pixels.
Vector2 pos = body.getPosition(); // value return in physics unit
square.setPosition(pos.x*100 ,pos.y*100);

Box2dlights textures isn't drawn

I am using box2dlights in my project and there seem to be an issue. When I actually use RayHandler in the program, only the light is drawn but no textures. And so when I remove RayHandler from the render loop it all works fine. I want the light to be drawn and then textures to be drawn above it. How do I reach that?
This is the code:
public class GameScreen implements Screen {
private Core core;
private SpriteBatch batch;
private Sprite spiderSprite;
private OrthographicCamera camera;
private RayHandler rayHandler;
private Box2DDebugRenderer debugRenderer;
private World world;
private Body spider, prop;
private PointLight spiderLight;
private Stage stage;
private boolean paused, lost, check;
private int pointsCount;
private float time;
public GameScreen(Core c) {
core = c;
stage = new Stage();
batch = new SpriteBatch();
camera = new OrthographicCamera();
camera.setToOrtho(false, core.SCREEN_WIDTH, core.SCREEN_HEIGHT);
batch.setProjectionMatrix(camera.combined);
debugRenderer = new Box2DDebugRenderer();
spiderSprite = core.chars.createSprite("spider");
world = new World(new Vector2(.0f, -10.0f), true);
BodyDef spiderDef = new BodyDef();
spiderDef.type = BodyDef.BodyType.DynamicBody;
spiderDef.position.set(core.SCREEN_WIDTH / 2, core.SCREEN_HEIGHT / 2);
spider = world.createBody(spiderDef);
CircleShape shape = new CircleShape();
shape.setRadius(core.SCREEN_WIDTH / 15);
spider.createFixture(shape, .1f);
BodyDef propDef = new BodyDef();
propDef.type = BodyDef.BodyType.StaticBody;
propDef.position.set(core.SCREEN_WIDTH / 2, core.SCREEN_HEIGHT);
prop = world.createBody(propDef);
CircleShape propShape = new CircleShape();
propShape.setRadius(0.1f);
prop.createFixture(propShape, 1.0f);
RopeJointDef rope = new RopeJointDef();
rope.bodyA = spider;
rope.bodyB = prop;
rope.maxLength = core.SCREEN_HEIGHT / 2;
world.createJoint(rope);
rayHandler = new RayHandler(world);
rayHandler.setAmbientLight(.5f);
spiderLight = new PointLight(rayHandler, 100, Color.WHITE, core.SCREEN_WIDTH, 100, 100);
spiderLight.attachToBody(spider);
}
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
stage.addAction(Actions.fadeIn(0.85f));
}
#Override
public void render(float delta) {
clearScreen();
batch.setProjectionMatrix(camera.combined);
batch.begin();
if (!lost && !paused) {
updateWorld();
updateSpider();
}
drawSpider();
stage.act();
stage.draw();
batch.end();
}
private void clearScreen() {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
private void updateSpider() {
//spider.setLinearVelocity(Gdx.input.getAccelerometerX() > 0 ? 50.0f : -50.0f, 0.0f);
float angle = MathUtils.radiansToDegrees * MathUtils.atan2(core.SCREEN_HEIGHT - spider.getPosition().y, core.SCREEN_WIDTH / 2 - spider.getPosition().x) - 90;
spiderSprite.setPosition(spider.getPosition().x, spider.getPosition().y);
spiderSprite.setRotation(angle);
}
private void drawSpider() {
spiderSprite.draw(batch);
rayHandler.render();
}
private void updateWorld() {
world.step(1/60f, 6, 2);
rayHandler.setCombinedMatrix(camera);
rayHandler.update();
time += Gdx.graphics.getDeltaTime();
}
}
I also removed a redundant part of the code which is not connected with the issue.
Stage has it's own batch with it's own .begin() and .end(). You should call batch.end(); before calling stage.draw();
I found it out. RayHandler.render() must not be invoked between batch.begin() and batch.end().

Libgdx collision using box2d working for desktop but failed to collide in Android emulator

My code for collision of a dynamic body to a static body works perfectly for desktop , but when running in Android emulator it can not able to detect collision ,Dynamic body goes down without collision.
I used Libgdx version : 1.5.0 .
Code :
package com.kg.game;
import java.util.Random;
import aurelienribon.tweenengine.BaseTween;
import aurelienribon.tweenengine.Tween;
import aurelienribon.tweenengine.TweenCallback;
import aurelienribon.tweenengine.TweenManager;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
public class MyGdxGame extends ApplicationAdapter implements InputProcessor {
private static final float VIEWPORT_WIDTH = 10;
private static final float BALL_RADIUS = 0.15f;
private static final int MAX_BALLS = 200;
private World world;
private Body[] ballModels;
private Texture bottleTexture;
private Texture ballTexture;
private Sprite[] ballSprites;
private Texture whiteTexture;
private Sprite groundSprite;
private SpriteBatch batch;
private BitmapFont font;
private OrthographicCamera camera;
private final Random rand = new Random();
float w;
float h;
Box2DDebugRenderer debugRenderer;
private final TweenManager tweenManager = new TweenManager();
#Override
public void create() {
debugRenderer = new Box2DDebugRenderer();
world = new World(new Vector2(0, -10), true);
createGround();
createBalls();
batch = new SpriteBatch();
font = new BitmapFont();
font.setColor(Color.BLACK);
w = Gdx.graphics.getWidth();
h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(VIEWPORT_WIDTH, VIEWPORT_WIDTH * h / w);
camera.position.set(0, (VIEWPORT_WIDTH * h / w) / 2, 0);
camera.update();
createSprites();
Gdx.input.setInputProcessor(new InputAdapter() {
#Override
public boolean touchDown(int x, int y, int pointer, int button) {
restart();
return true;
}
});
restart();
}
private void createGround() {
BodyDef bd = new BodyDef();
bd.position.set(0, 0);
bd.type = BodyType.StaticBody;
PolygonShape shape = new PolygonShape();
shape.setAsBox(100, 4);
FixtureDef fd = new FixtureDef();
fd.density = 1;
fd.friction = 0.5f;
fd.restitution = 0.5f;
fd.shape = shape;
world.createBody(bd).createFixture(fd);
shape.dispose();
}
private void createBalls() {
BodyDef ballBodyDef = new BodyDef();
ballBodyDef.type = BodyType.DynamicBody;
CircleShape shape = new CircleShape();
shape.setRadius(BALL_RADIUS);
FixtureDef fd = new FixtureDef();
fd.density = 1;
fd.friction = 0.5f;
fd.restitution = 0.5f;
fd.shape = shape;
ballModels = new Body[MAX_BALLS];
for (int i = 0; i < MAX_BALLS; i++) {
ballModels[i] = world.createBody(ballBodyDef);
ballModels[i].createFixture(fd);
}
shape.dispose();
}
private void createSprites() {
ballTexture = new Texture(Gdx.files.internal("ball.png"));
ballTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
ballSprites = new Sprite[MAX_BALLS];
for (int i = 0; i < MAX_BALLS; i++) {
ballSprites[i] = new Sprite(ballTexture);
ballSprites[i].setSize(BALL_RADIUS * 2, BALL_RADIUS * 2);
ballSprites[i].setOrigin(BALL_RADIUS, BALL_RADIUS);
}
whiteTexture = new Texture(Gdx.files.internal("ground.png"));
groundSprite = new Sprite(whiteTexture);
groundSprite.setSize(100, 4);
groundSprite.setPosition(-VIEWPORT_WIDTH / 2, 0);
groundSprite.setColor(Color.BLACK);
}
private float elapsed = 0;
#Override
public void render() {
tweenManager.update(1 / 60f);
world.step(1 / 60f, 10, 10);
debugRenderer.render(world, camera.combined);
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
GL20 gl = Gdx.gl20;
gl.glClearColor(1, 1, 1, 1);
gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Update
for (int i = 0; i < MAX_BALLS; i++) {
Vector2 ballPos = ballModels[i].getPosition();
ballSprites[i].setPosition(ballPos.x - ballSprites[i].getWidth()
/ 2, ballPos.y - ballSprites[i].getHeight() / 2);
ballSprites[i].setRotation(ballModels[i].getAngle()
* MathUtils.radiansToDegrees);
}
// Render
batch.setProjectionMatrix(camera.combined);
batch.begin();
groundSprite.draw(batch);
for (int i = 0; i < MAX_BALLS; i++)
ballSprites[i].draw(batch);
batch.end();
// batch.getProjectionMatrix().setToOrtho2D(0, 0, w, h);
batch.begin();
font.draw(batch, "Touch the screen to restart", 5, h - 5);
batch.end();
}
#Override
public void dispose() {
bottleTexture.dispose();
ballTexture.dispose();
batch.dispose();
font.dispose();
world.dispose();
}
#Override
public boolean keyDown(int keycode) {
return false;
}
#Override
public boolean keyUp(int keycode) {
return true;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
private void restart() {
Vector2 vec = new Vector2();
for (int i = 0; i < MAX_BALLS; i++) {
float tx = rand.nextFloat() * 1.0f - 0.5f;
float ty = VIEWPORT_WIDTH * h / w;
float angle = rand.nextFloat() * MathUtils.PI * 2;
ballModels[i].setActive(false);
ballModels[i].setLinearVelocity(vec.set(0, 0));
ballModels[i].setAngularVelocity(0);
ballModels[i].setTransform(vec.set(tx, ty), angle);
}
tweenManager.killAll();
Tween.call(new TweenCallback() {
private int idx = 0;
#Override
public void onEvent(int type, BaseTween<?> source) {
if (idx < ballModels.length) {
ballModels[idx].setAwake(true);
ballModels[idx].setActive(true);
idx += 1;
}
}
}).repeat(-1, 0.1f).start(tweenManager);
}
}
Screensots :
this is an idea, looking at the proportions of your images, I think the error may be out there, I would look at these lines:
groundSprite.setSize(100, 4); //<--especially here
groundSprite.setPosition(-VIEWPORT_WIDTH / 2, 0); //<--especially here
.
private void createGround() {
BodyDef bd = new BodyDef();
bd.position.set(0, 0); //<--especially here
bd.type = BodyType.StaticBody;
PolygonShape shape = new PolygonShape();
shape.setAsBox(100, 4); //<--especially here
especially the position and size, if it is standing in the same place, with the change of screen "device".
You tried to render debug? I see out there, if so, you can see your object in the emulated device?
I hope I understand, but not if that be the error

Why does my Player follow the OrthographicCamera

My game renders a tiledmap. I let the OrthographicCamera change its position.x to the right and can see the background (the tiledmap) scroll. This is fine.
But other Objects (the player and some balls) do (visually) change their position corresponding to the camera. They should not move, because only the camera moves.
package com.me.drop;
import java.util.Iterator;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapRenderer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxNativesLoader;
import com.badlogic.gdx.utils.TimeUtils;
public class MyTestGame extends Game {
Texture dropImage;
Texture bucketImage;
Sound dropSound;
Music rainMusic;
SpriteBatch batch;
OrthographicCamera camera;
Rectangle bucket;
Array<Rectangle> raindrops;
long lastDropTime;
Animator animator = new Animator();
Body animatorBody;
private Physics physics;
public Environment environment;
// public PerspectiveCamera cam;
public Model model;
public ModelBatch modelBatch;
public ModelInstance instance;
static final int WIDTH = 1600;
static final int HEIGHT = 960;
public final static float ORTHO_SCALE=1;
public final static float WORLD_SCALE=32;
Ball balls[] = new Ball[10];
Spieler player;
#Override
public void create() {
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
glViewport = new Rectangle(0, 0, WIDTH, HEIGHT);
// load the images for the droplet and the bucket, 64x64 pixels each
dropImage = new Texture(Gdx.files.internal("droplet.png"));
bucketImage = new Texture(Gdx.files.internal("bucket.png"));
// load the drop sound effect and the rain background "music"
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
// start the playback of the background music immediately
rainMusic.setLooping(true);
rainMusic.play();
// create the camera and the SpriteBatch
camera = new OrthographicCamera();
//camera.setToOrtho(false, 400, 240);
camera.setToOrtho(false, 800/ORTHO_SCALE, 480/ORTHO_SCALE);
batch = new SpriteBatch();
ModelBuilder modelBuilder = new ModelBuilder();
model = modelBuilder.createBox(5f, 5f, 5f,
new Material(ColorAttribute.createDiffuse(Color.GREEN)),
Usage.Position | Usage.Normal);
instance = new ModelInstance(model);
// Box2d
physics = Physics.getInstance();
// floor
physics.initFloor(0f, 0f, camera.viewportWidth, 0f);
// ceiling
// physics.initFloor(0f, camera.viewportHeight, camera.viewportWidth, 10f);
// left Wall
physics.initFloor(0f, 0f, 0f, camera.viewportHeight);
// right Wall
physics.initFloor(camera.viewportWidth, 0f, 0f, camera.viewportHeight);
float x = 150;
float y = camera.viewportHeight;
for (int i = 0; i < balls.length; i++) {
if (i%10==0) {
x += 10;
y = camera.viewportHeight / 2;
}
y += x;
balls[i] = new Ball(x, y , 20f , 20f, 0.4f, 0.8f);
}
player = new Spieler(50, camera.viewportHeight, 60f, 120f);
loadBackground();
}
TiledMapRenderer tileRenderer;
public void loadBackground() {
TiledMap map = new TmxMapLoader().load("maps/mymap.tmx");
System.out.println(map.getTileSets().toString());
float unitScale = 1 / 1;
tileRenderer = new OrthogonalTiledMapRenderer(map, unitScale);
physics.createFixturesForMap(map);
}
private Rectangle glViewport;
//#Override
public void render() {
GL10 gl = Gdx.graphics.getGL10();
// Camera --------------------- /
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glViewport((int) glViewport.x, (int) glViewport.y,
(int) glViewport.width, (int) glViewport.height);
//
// tell the camera to update its matrices.
camera.update();
camera.apply(gl);
// tell the SpriteBatch to render in the
// coordinate system specified by the camera.
batch.setProjectionMatrix(camera.combined);
// background
tileRenderer.setView(camera);
tileRenderer.render();
for (Ball b : balls)
b.render();
player.render();
grabUserAction();
// Box2d
physics.step();
updateObjects();
physics.debugRenderer.render(physics.world, camera.combined);
}
private void grabUserAction() {
// process user input
if(Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
bucket.x = touchPos.x - 64 / 2;
}
Vector2 vel = this.player.getBody().getLinearVelocity();
Vector2 pos = this.player.getBody().getPosition();
// apply left impulse, but only if max velocity is not reached yet
if (Gdx.input.isKeyPressed(Keys.LEFT)) { // && vel.x > -MAX_VELOCITY) {
// this.animatorBody.localPoint2.x -= 200 *
// Gdx.graphics.getDeltaTime();
pos.x -= 2 * Gdx.graphics.getDeltaTime();
this.player.getBody().setTransform(pos, 0);
// this.animatorBody.applyLinearImpulse(0, -0.8f, pos.x, pos.y,
// true);
// this.animatorBody.applyLinearImpulse(-5000, 0, pos.x, pos.y,
// true);
}
// apply right impulse, but only if max velocity is not reached yet
if (Gdx.input.isKeyPressed(Keys.RIGHT)) { // && vel.x < MAX_VELOCITY) {
// this.animatorBody.localPoint2.x += 200 *
// Gdx.graphics.getDeltaTime();
pos.x += 2 * Gdx.graphics.getDeltaTime();
this.player.getBody().setTransform(pos, 0);
// this.animatorBody.applyLinearImpulse(5000, 0, pos.x, pos.y,
// true);
}
if (Gdx.input.isKeyPressed(Keys.UP)) {
Vector2 impuls = new Vector2(0, 500f);
this.player.getBody().applyLinearImpulse(impuls, player.getBody().getWorldCenter(),true);
// this.animatorBody.applyAngularImpulse(-5.0f, true);
//(impulse, wake);(new b2Vec2(0.0, -3.0), Body.GetWorldCenter());
}
if (Gdx.input.isKeyPressed(Keys.D)) {
this.camera.position.x += 2;
this.camera.update();
}
else if (Gdx.input.isKeyPressed(Keys.A)) {
this.camera.position.x -= 2;
this.camera.update();
}
}
private void updateObjects() {
Array<Body> array = new Array<Body>();
physics.world.getBodies(array);
Iterator<Body> bi = array.iterator();
while (bi.hasNext()){
Body b = bi.next();
// Get the body's user data - in this example, our user
// data is an instance of the Entity class
IObject e = (IObject) b.getUserData();
if (e != null) {
// Update the entities/sprites position and angle
e.setPosition((b.getPosition().x - e.getWidth()/2/WORLD_SCALE) * WORLD_SCALE
, (b.getPosition().y - e.getHeight()/2/WORLD_SCALE) * WORLD_SCALE);
// We need to convert our angle from radians to degrees
//e.setRotation(MathUtils.radiansToDegrees * b.getAngle());
}
}
}
#Override
public void dispose() {
// dispose of all the native resources
dropImage.dispose();
bucketImage.dispose();
dropSound.dispose();
rainMusic.dispose();
batch.dispose();
// modelBatch.dispose();
model.dispose();
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
//
// Vector3 oldpos = new Vector3(camera.position);
// camera.setToOrtho(false,
// width/WORLD_SCALE,
// height/WORLD_SCALE);
// camera.translate(oldpos.x-camera.position.x,oldpos.y-camera.position.y);
}
#Override
public void pause() {
super.pause();
}
#Override
public void resume() {
super.resume();
}
}

How can I move balls in random directions and how can I keep them bouncing inside the frame?

Here is the code:
public class BallGame extends JPanel implements Runnable {
JPanel panel1 = new JPanel();
private int ballX = 10, ballY = 110, ...;
Thread aThread;
int toRight=5;
int toLeft= -5;
int upWard=5;
int downWard= -5;
int widthBall, heightBall;
public BallGame(){
game=true;
aThread=new Thread(this);
aThread.start();
}
public void paintComponent(Graphics g){
setOpaque(false);
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(ballX, ballY, 7,7);
g.setColor(Color.BLUE);
g.fillOval(ballX + 15, ballY + 10, 7,7);
g.setColor(Color.GREEN);
g.fillOval(ballY - 10, ballY - 15, 7,7);
}
public void positionBall(int sx, int sy)
{
ballX = sx;
ballY = sy;
this.widthBall = this.getWidth();
this.heightBall = this.getHeight();
repaint();
}
public void run() {
boolean leftRight = false;
boolean upDown = false;
while(true){
if(game){
if (leftRight)
{
ballX += toRight;
if (ballX >= (widthBall - 5))
leftRight= false;
}
else
{
ballX += toLeft;
if ( ballX <= 0)
leftRight = true;
}
if (upDown)
{
ballY += upWard;
if (ballY >= (heightBall - 5))
upDown = false;
}
else
{
ballY += downWard;
if ( ballY <= 0)
upDown = true;
}
positionBall(ballX, ballY);
try
{
Thread.sleep(70);
}
catch(InterruptedException ex)
{
}
I don't know if the part where I drew the balls was right. The balls move in the same path. How can I move them in different directions and how can I limit them inside the frame? I need this for our case study immediately. Thank you for your time!
In order for the balls to move independently you need to treat them as 3 balls.
The reason why they always go the same direction, is that you use the same delta, just inverting the sign of delta x and delta y, thus you will always keep the same speed, and bounce at 90 degrees.
In the code below which is basically the same as you had, I keep the state of each ball in separate instances, change speed of delta x and delta y once a side is touched, and use the Swing Timer which is a better approach with respect to timing in Swing, as pointed out by Robin above.
I have updated the example, so that 4 balls start in the middle, and they move away from each other. This should give you enough information to adapt it to your requirements. The picture below is produced by only allowing 10 iterations, and setting
ballGame.setOpaque(true);
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.*;
public class BallGame extends JPanel {
private class Ball {
private int x;
private int y;
private int width;
private int height;
private Color color;
private boolean leftRight;
private boolean upDown;
private int deltaX;
private int deltaY;
Ball(Color color, int x, int y, int width, int height) {
this(color, x, y, width, height, false, false);
}
Ball(Color color, int x, int y, int width, int height, boolean leftRight, boolean upDown) {
this.color = color;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.leftRight = leftRight;
this.upDown = upDown;
updateDelta();
}
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
deltaX = minimumMovement + (int) (Math.random() * maxExtra);
}
public void positionBall() {
if (leftRight) {
x += deltaX;
if (x >= (BallGame.this.getWidth() - width / 2)) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
if (upDown) {
y += deltaY;
upDown = !(y >= (BallGame.this.getHeight() - height / 2));
if (y >= (BallGame.this.getHeight() - height / 2)) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public Color getColor() {
return color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
private ArrayList<Ball> balls = new ArrayList<>(3);
public BallGame() {
createBalls();
startGame();
}
private void startGame() {
int framesPerSecond = 30;
int timeToWait = 1000 / framesPerSecond;
Timer timer = new Timer(timeToWait, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Ball ball : balls) {
ball.positionBall();
}
repaint();
}
});
timer.start();
}
private void createBalls() {
int startX = 400;
int startY = 200;
balls.add(new Ball(Color.green, startX, startY, 10, 10));
balls.add(new Ball(Color.blue, startX, startY, 15, 15, true, true));
balls.add(new Ball(Color.red, startX, startY, 20, 20, false, true));
balls.add(new Ball(Color.orange, startX, startY, 20, 20, true, false));
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
for (Ball ball : balls) {
g2.setColor(ball.getColor());
g2.fillOval(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
g2.setColor(ball.getColor().darker());
g2.drawOval(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
}
g2.dispose();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Ball Game");
BallGame ballGame = new BallGame();
ballGame.setOpaque(false);
frame.getContentPane().add(ballGame);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(800, 450));
frame.setLocationRelativeTo(null); // Center
frame.pack();
frame.setVisible(true);
}
});
}
}