UPDATE
I have a hint. That is because the center of the screen in JBox2D is (0, 0). This is so weird because x and y are not from -1 to 1, it depends of the screen size.
This means the Util class I copied from the internet (everybody shared this code) is not up to date. I still need help because I can't find any 'algorithm' to have aspect ratio + screen size dependency.
BASE QUESTION
Since I have added the "slick2D to jbox2D position" and vice versa (it's like position in screen = position in screen / 100 for JBox), I don't get a good result. Screenshots below
I'm explaining with code:
public class Util {
private static final float SCALE = 0.01f; // 1/100 pixels
public static float toPosX(float posX) { return (posX * SCALE); }
public static float toPosY(float posY) { return (-posY * SCALE); }
public static float toScreenX(float posX) { return (posX / SCALE); }
public static float toScreenY(float posY) { return (-posY / SCALE); }
}
Square.java :
public class Square {
private Body body;
private Rectangle rectangle;
Square(World world, BodyType type, Vec2 pos, Vec2 size) {
float x = Util.toPosX(pos.x);
float y = Util.toPosY(pos.y);
float sx = Util.toPosX(size.x);
float sy = Util.toPosY(size.y);
//body definition
BodyDef bd = new BodyDef();
bd.position.set(x, y);
bd.type = type;
//define shape of the body.
PolygonShape cs = new PolygonShape();
cs.setAsBox(sx, sy);
//define fixture of the body.
FixtureDef fd = new FixtureDef();
fd.shape = cs;
fd.density = 1f;
fd.friction = 0.3f;
fd.restitution = 1.0f;
//create the body and add fixture to it
body = world.createBody(bd);
body.createFixture(fd);
rectangle = new Rectangle(0, 0, size.x, size.y);
rectangle.setLocation(pos.x, pos.y);
}
public Body getBody() { return this.body; }
public Rectangle getRectangle() { return this.rectangle; }
}
And finally my display class:
public class DisplayManager extends BasicGame {
private GameManager gameManager;
private Body b1, b2;
private Rectangle r1, r2;
private World world;
public DisplayManager(GameManager game) {
super("Title");
this.gameManager = game;
}
#Override
public void init(GameContainer container) throws SlickException {
this.gameManager.initPlayersSprites();
world = new World(new Vec2(0, -10));
Square s1, s2;
s1 = new Square(world, BodyType.STATIC, new Vec2(10, 800), new Vec2(1900, 30));
b1 = s1.getBody();
r1 = s1.getRectangle();
s2 = new Square(world, BodyType.DYNAMIC, new Vec2(945, 200), new Vec2(30, 30));
b2 = s2.getBody();
r2 = s2.getRectangle();
}
public void render(GameContainer container, Graphics g) throws SlickException {
float step = 1.0f / 600.0f;
world.step(step, 6, 2);
r1.setLocation(Util.toScreenX(b1.getPosition().x), Util.toScreenY(b1.getPosition().y));
r2.setLocation(Util.toScreenX(b2.getPosition().x), Util.toScreenY(b2.getPosition().y));
g.draw(r1);
g.draw(r2);
}
}
Here is the result :
first frame :
http://i.stack.imgur.com/WgQPK.png
some frames later :
http://i.stack.imgur.com/a1XyL.png
(the ground didn't move, it's just another screenshot took from my hand)
In other words, the cube falls down like for ever. I debugged the position of the cube and it doesn't stop to go down.
With Slick2D DebugDraw it doesn't help because the cube goes through the ground anyway.
Please note that in JBox2D, it worked with pixels measurements (that was not accurate at all but collisions worked well)
That was because of the negative size. (toPoxY reverse the y pos)
Related
Hi guys so i was trying to make this simple game in libgdx and everything was fine until i noticed that i need to apply a big force just to make the player move a little is there any way to make it need less force?
This is my PlayScreen where I render the player.
`
private Logang game;
//basic playscreen variables
private OrthographicCamera gamecam;
private Viewport gamePort;
//Box2d variables
private World world;
private Box2DDebugRenderer b2dr;
boolean drawn = true;
private Player p;
private int pX = 100, pY = 300;
public GameScreen(Logang game) {
this.game = game;
//create cam used to follow mario through cam world
gamecam = new OrthographicCamera();
gamecam.update();
Box2D.init();
//create our Box2D world, setting no gravity in X, -10 gravity in Y, and allow bodies to sleep
world = new World(new Vector2(0, Logang.GRAVITY), true);
//allows for debug lines of our box2d world.
b2dr = new Box2DDebugRenderer();
//create a FitViewport to maintain virtual aspect ratio despite screen size
gamePort = new ScalingViewport(Scaling.fill, Logang.GWIDTH, Logang.GHEIGHT, gamecam);
p = new Player(new Sprite(new Texture("hud_p3.png")), world, pX, pY, 1);
//initially set our gamcam to be centered correctly at the start of of map
gamecam.position.set(gamePort.getWorldWidth() / 2 , gamePort.getWorldHeight() / 2, 0);
line();
}
#Override
public void show() {
}
public void update(float dt) {
//handle user input first
p.update(dt);
//update our gamecam with correct coordinates after changes
}
#Override
public void render(float delta) {
//separate our update logic from render
update(delta);
//Clear the game screen with Black
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1f / 60f, 6, 2);
gamecam.position.set(p.getSprite().getX(),Logang.GHEIGHT / 2, 0); // x and y could be changed by Keyboard input for example
gamecam.update();
game.getBatch().setProjectionMatrix(gamecam.combined);
//renderer our Box2DDebugLines
b2dr.render(world, gamecam.combined);
System.out.println("Player x: " + p.getSprite().getX() + " Camera X: " + gamecam.position.x + " Body X: " + p.getBody().getPosition().x);
//System.out.println("Player y: " + p.getSprite().getY() + " Camera Y: " + gamecam.position.y + " Body Y: " + p.getBody().getPosition().y);
game.getBatch().begin();
if (p.getBody() != null)
p.render(game.getBatch());
EntityManager.renderTerra(game.getBatch(), delta);
game.getBatch().end();
}
public void line() {
Texture tmp = new Texture("hud_p3.png");
tmp.setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
for (int i = 0; i < 50; i++) {
EntityManager.add(new Ground(new Sprite(tmp), world, (int)(i * Logang.TILE), 1, 2));
}
// EntityManager.changeSize(((Logang.TILE) * 5),Logang.TILE);
}
#Override
public void resize(int width, int height) {
//updated our game viewport
gamePort.update(width, height);
}
public World getWorld() {
return world;
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
world.dispose();
b2dr.dispose();
}`
And this is my Entity class which is extended by the player
private World world;
private Sprite sprite;
private Body body;
private int tipo;
public Entity(Sprite sprite, World world, int x, int y, int tipo){
this.sprite = sprite;
this.world = world;
getSprite().setPosition(x, y);
getSprite().setSize(Logang.TILE , Logang.TILE);
define(tipo);
this.tipo = tipo;
}
public void update(float dt){
if(Gdx.input.isKeyPressed(Input.Keys.LEFT)){
getBody().applyLinearImpulse(new Vector2(-Logang.PPM,0f), getBody().getWorldCenter(), true);
}
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)){
getBody().applyLinearImpulse(new Vector2(Logang.PPM,0f), getBody().getWorldCenter(), true);
}
if(Gdx.input.isKeyPressed(Input.Keys.SPACE)){
getBody().applyLinearImpulse(0f,-Logang.GRAVITY * Logang.PPM, getBody().getPosition().x, getBody().getPosition().y, true);
}
}
}
public void define(int tipo){
BodyDef bdef = new BodyDef();
bdef.position.set((getSprite().getX() + getSprite().getWidth() / 2), (getSprite().getY() + getSprite().getHeight() / 2));
switch(tipo){
case 1: {
bdef.type = BodyDef.BodyType.DynamicBody;
break;
}
case 2:{
bdef.type = BodyDef.BodyType.StaticBody;
break;
}
case 3:{
bdef.type = BodyDef.BodyType.DynamicBody;
break;
}
}
body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox(getSprite().getWidth() / 2, getSprite().getHeight() / 2);
fdef.shape = shape;
body.createFixture(fdef);
body.setUserData(this);
shape.dispose();
}
public void render(SpriteBatch batch){
if(tipo != 2) {
float posX = getBody().getPosition().x;
float posY = getBody().getPosition().y;
getSprite().setPosition(posX - getSprite().getWidth() / 2, posY - getSprite().getHeight() / 2);
}
getSprite().draw(batch);
}
public Sprite getSprite() {
return sprite;
}
public void setSprite(Sprite sprite) {
this.sprite = sprite;
}
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}
}
Thank everybody for any answer
Box2D is a physics engine so tries to imitate real life physics in game. So if your object is large and heavy it will require a large amount of force to move it.
To make it so your objects can move with less force you can either make them smaller or change the density of them to make them lighter which will allow them to be moved with less force.
To change the density you set it in the fixtureDefinition
FixtureDef fdef = new FixtureDef();
fdef.density=0.1f; // (weight: range 0.01 to 1 is good)
fdef.friction = 0.7f; // (how slippery it is: 0=like ice 1 = like rubber)
fdef.restitution = 0.3f; //(how bouncy is it 0= not bouncy 1 = 100% bouncy)
Another thing I noticed is you are using what seems to be a PixelPerMeter ratio for your forces in this line:
getBody().applyLinearImpulse(new Vector2(-Logang.PPM,0f), getBody().getWorldCenter(), true);
You shouldn't use this value for your forces as this is for converting box2d world to render coordinates and you can use the following code to apply the force to the center.
getBody().applyLinearImpulse(new Vector2((10f*getBody().getMass()),0f), getBody().getWorldCenter(), true);
As a side note the impulse is used to create a single application of force whereas body.applyForceToCenter(force,wake); is used to apply a constant force over time. Try with the apply force method and see if this helps.
Hi guys i'm quite new to libgdx I tried to make the camera follow the player.
Trying to do so i read online that i had to add this line of code.
game.getBatch().setProjectionMatrix(gamecam.combined);
By doing so i noticed that my game was really zoomed i tried to dezoom it but i was not able to make it work. Do you guys have any suggestion?
This is my GameScreen where i render the player.
`public class GameScreen implements Screen {
private Logang game;
//basic playscreen variables
private OrthographicCamera gamecam;
private Viewport gamePort;
//Box2d variables
private World world;
private Box2DDebugRenderer b2dr;
boolean drawn = true;
private Player p;
private int pX = 100, pY = 300;
public GameScreen(Logang game) {
this.game = game;
//create cam used to follow mario through cam world
gamecam = new OrthographicCamera(Logang.GWIDTH, Logang.GHEIGHT);
gamecam.update();
//create our Box2D world, setting no gravity in X, -10 gravity in Y, and allow bodies to sleep
world = new World(new Vector2(0, Logang.GRAVITY), true);
//allows for debug lines of our box2d world.
b2dr = new Box2DDebugRenderer();
//create a FitViewport to maintain virtual aspect ratio despite screen size
gamePort = new ScalingViewport(Scaling.fill, Logang.GWIDTH / Logang.PPM, Logang.GHEIGHT / Logang.PPM, gamecam);
p = new Player(new Sprite(new Texture("badlogic.jpg")), world, pX, pY, 1);
//initially set our gamcam to be centered correctly at the start of of map
//gamecam.position.set(gamePort.getWorldWidth() / 2, gamePort.getWorldHeight() / 2, 0);
line();
}
#Override
public void show() {
}
public void update(float dt) {
//handle user input first
p.update(dt);
//update our gamecam with correct coordinates after changes
/*gamecam.position.set(p.getSprite().getX(),0,0);
gamecam.update();*/
}
#Override
public void render(float delta) {
//separate our update logic from render
update(delta);
//Clear the game screen with Black
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1f / 60f, 6, 2);
gamecam.position.set(p.getSprite().getX(), p.getSprite().getY(), 0); // x and y could be changed by Keyboard input for example
//gamecam.position.set(p.getSprite().getX(), p.getSprite().getY(), 0);
gamecam.update();
game.getBatch().setProjectionMatrix(gamecam.combined);
//renderer our Box2DDebugLines
b2dr.render(world, gamecam.combined);
System.out.println("Player x: " + p.getSprite().getX() + " Camera X: " + gamecam.position.x + " Body X: " + p.getBody().getPosition().x);
//System.out.println("Player y: " + p.getSprite().getY() + " Camera Y: " + gamecam.position.y + " Body Y: " + p.getBody().getPosition().y);
game.getBatch().begin();
if (p.getBody() != null)
p.render(game.getBatch());
EntityManager.renderTerra(game.getBatch(), delta);
game.getBatch().end();
}
public void line() {
Texture tmp = new Texture("dirt.png");
tmp.setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
for (int i = 0; i < 10; i++) {
EntityManager.add(new Ground(new Sprite(tmp), world, i * Logang.TILE, 0, 2));
}
//EntityManager.changeSize(Logang.TILE * 5,Logang.TILE);
}
#Override
public void resize(int width, int height) {
//updated our game viewport
gamePort.update(width, height);
}
public World getWorld() {
return world;
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
world.dispose();
b2dr.dispose();
}`
And this is my Entity class which is extended by the Player which i empty for now`
public abstract class Entity {
private World world;
private Sprite sprite;
private Body body;
private int tipo;
public Entity(Sprite sprite, World world, int x, int y, int tipo){
this.sprite = sprite;
this.world = world;
getSprite().setPosition(x, y);
getSprite().setSize(Logang.TILE, Logang.TILE);
define(tipo);
this.tipo = tipo;
}
public abstract void update(float dt);
public void define(int tipo){
BodyDef bdef = new BodyDef();
bdef.position.set((getSprite().getX() + getSprite().getWidth() / 2) / Logang.PPM, (getSprite().getY() + getSprite().getHeight() / 2) / Logang.PPM);
switch(tipo){
case 1: {
bdef.type = BodyDef.BodyType.DynamicBody;
break;
}
case 2:{
bdef.type = BodyDef.BodyType.StaticBody;
break;
}
case 3:{
bdef.type = BodyDef.BodyType.DynamicBody;
break;
}
}
body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox(getSprite().getWidth() / Logang.PPM / 2, getSprite().getHeight() / Logang.PPM / 2);
fdef.shape = shape;
body.createFixture(fdef);
body.setUserData(this);
shape.dispose();
}
public void render(SpriteBatch batch){
if(tipo != 2) {
float posX = getBody().getPosition().x * Logang.PPM;
float posY = getBody().getPosition().y * Logang.PPM;
getSprite().setPosition(posX - getSprite().getWidth() / 2, posY - getSprite().getHeight() / 2);
}
getSprite().draw(batch);
}
public Sprite getSprite() {
return sprite;
}
public void setSprite(Sprite sprite) {
this.sprite = sprite;
}
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}`
If I remove that line at the start the game sizes are good but my camera doesn't follow my player.
Thanks for the answer and sorry if the question was not well asked.
1) If your viewport dimensions divided by Logang.PPM then all Textures size should be also divided by Logang.PPM.
Logang.TILE should be float and divided by Logang.PPM
Player sprite also should be resized**.
2) To follow player try dividing gamecam resolution by Logang.PPM.
Initialize it like this:
gamecam = new OrthographicCamera(Logang.GWIDTH / Logang.PPM, Logang.GHEIGHT / Logang.PPM);
UPD: I found issue, it was in player render method:
float posX = getBody().getPosition().x; // delete * Logang.PPM
float posY = getBody().getPosition().y; // delete * Logang.PPM
The camera takes in two variables: the width and height of the world. That's an important keyword here, as it defines the rendered size of the world. If the width and height of the camera is 300x300, that means there's 300x300 units visible on the screen, even if the screen is 1920x1080.
When you do:
gamecam = new OrthographicCamera(Logang.GWIDTH, Logang.GHEIGHT);
You set the width and height of the camera to a given value.
The second you apply it:
game.getBatch().setProjectionMatrix(gamecam.combined);
the batch you use to render uses the projection matrix of the camera, meaning it converts screen coordinates to world coordinates based on the width and height of what's visible at once. For an instance 300x300.
If you think the world is too small (meaning what you render shows up as too big) you can of course zoom out by adding a scale factor, but you can also increase the width and height of the camera. I have no clue what you set the width and height to, but if you increase the width and height it'll probably work.
And as I already mentioned, the world coordinates can be different from the screen coordinates.
Im trying to learn about the Box2D physics engine.
Im using it in LibGX, and im facing a problem.
When i convert from Pixels to Meters, only large objects are drawn..
say this:
public class GameScreen implements Screen{
static int PPM = 100;
Box2DDebugRenderer debugRenderer;
World w = new World(new Vector2(0,-0.981f),true);
OrthographicCamera cam;
public static Body createDynamicBody(World world, int x, int y, int w,
int h, int density, int scale) {
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.DynamicBody;
def.position.set(x/scale,y/scale);
Body b = world.createBody(def);
FixtureDef fdef =new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox((w/2)/scale,(h/2)/scale);
fdef.shape = shape;
b.createFixture(fdef);
return b;
}
// initialized when Screen is loaded
#Override
public void show() {
cam = new OrthographicCamera();
font = new BitmapFont();
debugRenderer = new Box2DDebugRenderer();
cam.setToOrtho(false,800,480);
debugRenderer = new Box2DDebugRenderer();
// this body is not drawn
Body b = createDynamicBody(w,200,200,150,150,5, PPM);
// this body is drawn
Body b2 = createDynamicBody(w,200,200,200,200,5, PPM);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.2f,0.1f,0.7f,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
debugRenderer.render(w,camera.combined.cpy().scale(PPM,PPM,0));
w.step(1/60f,6,2);
}
}
In your createDynamicBody you are using an int for scale. This is causing you to loose precision when you divide. Simple replace your int scale with float scale and it should work.
public static Body createDynamicBody(World world, int x, int y, int w,
int h, int density, float scale)
Visit for video (http://www.monstermedia.net/portfolio.php#126)
I want to make the behavior of component like this, if I drag any component and drop anywhere on the screen then it should be return to the center of the screen smoothly like the video. I can set any component at any of specific position on the screen but unable to return them again at center.
The code is
public class Physics extends AbstractScene
{
private float timeStep = 1.0f / 60.0f;
private int constraintIterations = 10;
private int windowWidth=MT4jSettings.getInstance().windowWidth;
private int windowHeight= MT4jSettings.getInstance().windowHeight;
/** THE CANVAS SCALE **/
private float scale = 20;
private AbstractMTApplication app;
public World world;
private MTComponent physicsContainer;
PhysicsRectangle physRect;
PhysicsRectangle borderLeft, borderRight, borderTop, borderBottom;
Vector3D pos;
Vec2 gravity1;
AABB worldAABB;
public Physics(AbstractMTApplication mtApplication, String name)
{
super(mtApplication, name);
this.app = mtApplication;
float worldOffset = 600;
worldAABB = new AABB(new Vec2(-worldOffset, -worldOffset), new Vec2((app.width)/scale + worldOffset, (app.height)/scale + worldOffset));
gravity1 = new Vec2(0, 30);
boolean sleep = false;
//Create the pyhsics world
this.world = new World(worldAABB, gravity1, sleep);
this.registerGlobalInputProcessor(new CursorTracer(app, this));
this.registerPreDrawAction(new UpdatePhysicsAction(world, timeStep, constraintIterations, scale));
physicsContainer = new MTComponent(app);
physicsContainer.scale(scale, scale, 1, Vector3D.ZERO_VECTOR);
this.getCanvas().addChild(physicsContainer);
//Create borders around the screen
this.createScreenBorders(physicsContainer);
//Createa Rectangles
for (int i = 0; i < 5; i++)
{
pos = new Vector3D(windowWidth/2f, windowHeight/2f);
physRect = new PhysicsRectangle(pos, 100, 100, app, world, 1f, 0.4f, 0.4f, scale);
MTColor col = new MTColor(ToolsMath.getRandom(60, 255),ToolsMath.getRandom(60, 255),ToolsMath.getRandom(60, 255));
physRect.setFillColor(col);
physRect.setStrokeColor(col);
PhysicsHelper.addDragJoint(world, physRect, physRect.getBody().isDynamic(), scale);
physicsContainer.addChild(physRect);
}
}
private void createScreenBorders(MTComponent parent)
{
//Left border
float borderWidth = 50f;
float borderHeight = app.height;
Vector3D pos = new Vector3D(-(borderWidth/2f) , app.height/2f);
borderLeft = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
borderLeft.setName("borderLeft");
parent.addChild(borderLeft);
//Right border
pos = new Vector3D(app.width + (borderWidth/2), app.height/2);
borderRight = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
borderRight.setName("borderRight");
parent.addChild(borderRight);
//Top border
borderWidth = app.width;
borderHeight = 50f;
pos = new Vector3D(app.width/2, -(borderHeight/2));
borderTop = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
borderTop.setName("borderTop");
parent.addChild(borderTop);
//Bottom border
pos = new Vector3D(app.width/2 , app.height + (borderHeight/2));
borderBottom = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
borderBottom.setName("borderBottom");
parent.addChild(borderBottom);
}
public void onEnter() {
}
public void onLeave() {
}
}
To run the program use this class, RightClick-> Run as java application
public class staertWaterApp extends MTApplication
{
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
initialize();
}
#Override
public void startUp()
{
addScene(new Physics(this, "Physics Example Scene"));
}
}
What I also tried?
1. I was trying to apply thread but we can not use thread in MT4J (I found this from a website) and the replacement of thread is an interface IPreDrawAction. I applied this but there is another problem that we can not apply this interface on Physics Component, so I used MTComponent, but there is one another problem that we can not apply gravity on MTComponent.
I am trying to make a game engine and I want a camera controlled by the player and also effected by other jBullet entities in Java. I got suggested to use Kinematic Objects so I looked up about them. I couldn't find any documentation which I could understand.
Can someone explain how to set up and use kinematic objects or at least show me where I can start?
The documentation for KinematicCharacterController, found here isn't too entirely helpful, but the source in the CharacterDemo can be. Two main properties are defined in the demo.
public KinematicCharacterController character;
public PairCachingGhostObject ghostObject;
The ghost can be used for dynamic collision detection, as it does not automatically react to those events. The character can be moved by changing the Transform.
//from the source src\com\bulletphysics\demos\character\CharacterDemo.java
Transform startTransform = new Transform();
startTransform.setIdentity();
startTransform.origin.set(0.0f, 4.0f, 0.0f);
Vector3f worldMin = new Vector3f(-1000f,-1000f,-1000f);
Vector3f worldMax = new Vector3f(1000f,1000f,1000f);
AxisSweep3 sweepBP = new AxisSweep3(worldMin, worldMax);
ghostObject = new PairCachingGhostObject();
ghostObject.setWorldTransform(startTransform);
sweepBP.getOverlappingPairCache().setInternalGhostPairCallback(new GhostPairCallback());
float characterHeight = 1.75f * characterScale;
float characterWidth = 1.75f * characterScale;
ConvexShape capsule = new CapsuleShape(characterWidth, characterHeight);
ghostObject.setCollisionShape(capsule);
ghostObject.setCollisionFlags(CollisionFlags.CHARACTER_OBJECT);
float stepHeight = 0.35f * characterScale;
character = new KinematicCharacterController(ghostObject, capsule, stepHeight);
dynamicsWorld.addCollisionObject(ghostObject, CollisionFilterGroups.CHARACTER_FILTER, (short)(CollisionFilterGroups.STATIC_FILTER | CollisionFilterGroups.DEFAULT_FILTER));
dynamicsWorld.addAction(character);
It would also be wise to extend the MotionState class to hold the transform
public class MyMotionState extends MotionState {
private Transform worldTransform;
public MyMotionState()
{
worldTransform = new Transform();
worldTransform.setIdentity();
}
#Override
public Transform getWorldTransform(Transform worldTrans)
{
worldTrans.set(worldTransform);
return worldTrans;
}
#Override
public void setWorldTransform(Transform worldTrans)
{
worldTransform.set(worldTrans);
}
}
and linking the Kinematic to a RigidBody for applying the physics to the character, and getting info on rendering.
rigidBody.setCollisionFlags(rigidBody.getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT);
rigidBody.setActivationState(CollisionObject.DISABLE_DEACTIVATION);
Don't forget to update the physics engine once every iteration of the game loop.
Transform transform = new Transform();
transform.setIdentity();
transform.origin.set(input.getX(), input.getY(), input.getZ());
myMotionState.setWorldTransform(transform);
rigidBody.setCenterOfMassTransform(myMotionState.getWorldTransform());
If you prefer, you could put these in your MainCharacter class or whatever you call it (I like it for the object oriented feel and ease to understand)
public class MainCharacter implements KeyListener, MouseListener
{
private DynamicsWorld world;
private MyMotionState myMotionState;
private RigidBody rigidBody;
private KinematicCharacterController character;
private ConvexShape shape;
private Texture texture;
private GhostObject ghost;
private Vector3f pos;
public MainCharacter(DynamicsWorld world, Vector3f initialPosition, ConvexShape shape, Texture texture)
{
this.world = world;
RigidBodyConstructionInfo constructInfo = new RigidBodyConstructionInfo(...);
this.myMotionState = myMotionState;
rigidBody = new RigidBody(constructInfo);
ghost = new GhostObject();
character = new KinematicCharacterController(ghost,shape,1);
}
public void render()
{
glBegin(GL_QUADS);
glVertex3f(...
...
glEnd();
}
public void mouseMoved(MouseEvent e)
{
//pseudocode
this.yaw = e.getDX();
this.pitch = e.getDY();
}
public void keyPressed(KeyEvent e)
{
Vector3f dPos = null;
if(e.getKeyChar() == 'W')
{
dPos.x = 10;
}
else if(e.getKeyChar() == 'S')
{
dPos.x = -10;
}
etc...
move(dPos.x,dPos.y,dPos.z);
}
public void move(float dx, float dy, float dz) {
pos.z += dx * (float) Math.cos(Math.toRadians(yaw - 90)) + dz * Math.cos(Math.toRadians(yaw));
pos.x -= dx * (float) Math.sin(Math.toRadians(yaw - 90)) + dz * Math.sin(Math.toRadians(yaw));
pos.y += dy * (float) Math.sin(Math.toRadians(pitch - 90)) + dz * Math.sin(Math.toRadians(pitch));
//pseudocode
rigidBody.update(pos);
world.update(pos);
}
}
I hope I have helped you.