I am developing a 2D 8 pool game using LibGDX,I am a newbie so I don't know how to solve this , I used ShapeRenderer of type line to draw a line between the white ball and the mouse pointer if mouse is pressed,but for some reason it doesn't work.
In Render()
if(cueball.CheckBallMovement()) {//if cueball stopped moving
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
Vector3 vv=new Vector3(Gdx.input.getX(),Gdx.input.getY(),0);//translate mouse coordinates world coordinates
camera.unproject(vv);
sr.setProjectionMatrix(camera.combined);
sr.begin(ShapeType.Line);
sr.setColor(1, 0, 0, 1);
sr.line(cueball.Ball.getWorldCenter().x, cueball.Ball.getWorldCenter().y,
vv.x,vv.y);
sr.end();
System.out.println("ss");`
It prints out the "ss" but doesn't render the line.I don't know if this helps, but here are my camera ratios In create()
world = new World(new Vector2(0,0),true); // x= 0 and y =0 means no gravity
debugRenderer = new Box2DDebugRenderer();
camera =new OrthographicCamera(VirtualWidth/20,VirtualHeight/20);
Related
The past few days I've been trying to figure out a display bug I don't understand. I've been working on a simple 2d platformer with box2d and orthogonal Tiled maps. So far so good, the physics work and using the b2d debug renderer I can assert proper player fixture and camera movement through the level.
Now next step I've tried to load textures to display sprites instead of debug shapes. This is where I stumble. I can load animations for my player body/fixture, but when I use the setCenter() method to center the texture on the fixture it is always out of center.
I've tried approaches via halving texture witdths and heights hoping to center the texture on the player fixture but I get the exact same off position rendering. I've played aorund with world/camera/screen unit coordinates but the misalignement persists.
I'm creating the player in my Player class with the following code.
First I define the player in box2d:
//define player's physical behaviour
public void definePlayer() {
//definitions to later use in a body
BodyDef bdef = new BodyDef();
bdef.position.set(120 / Constants.PPM, 60 / Constants.PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
b2body = world.createBody(bdef);
//Define needed components of the player's main fixture
FixtureDef fdef = new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox(8 / Constants.PPM, 16 / Constants.PPM); //size of the player hitbox
//set the player's category bit
fdef.filter.categoryBits = Constants.PLAYER_BIT;
//set which category bits the player should collide with. If not mentioned here, no collision occurrs
fdef.filter.maskBits = Constants.GROUND_BIT |
Constants.GEM_BIT |
Constants.BRICK_BIT |
Constants.OBJECT_BIT |
Constants.ENEMY_BIT |
Constants.TREASURE_CHEST_BIT |
Constants.ENEMY_HEAD_BIT |
Constants.ITEM_BIT;
fdef.shape = shape;
b2body.createFixture(fdef).setUserData(this);
}
Then I call the texture Region to be drawn in the Player class constructor:
//define in box2d
definePlayer();
//set initial values for the player's location, width and height, initial animation.
setBounds(0, 0, 64 / Constants.PPM, 64 / Constants.PPM);
setRegion(playerStand.getKeyFrame(stateTimer, true));
And finally, I update() my player:
public void update(float delta) {
//center position of the sprite on its body
// setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2);
setCenter(b2body.getPosition().x, b2body.getPosition().y);
setRegion(getFrame(delta));
//set all the boolean flags during update cycles approprietly. DO NOT manipulate b2bodies
//while the simulation happens! therefore, only set flags there, and call the appropriate
//methods outside the simulation step during update
checkForPitfall();
checkIfAttacking();
}
And my result is
this, facing right
and this, facing left
Update:
I've been trying to just run
setCenter(b2body.getPosition().x, b2body.getPosition().y);
as suggested, and I got the following result:
facing right and facing left.
The sprite texture flip code is as follows:
if((b2body.getLinearVelocity().x < 0 || !runningRight) && !region.isFlipX()) {
region.flip(true, false);
runningRight = false;
} else if ((b2body.getLinearVelocity().x > 0 || runningRight) && region.isFlipX()) {
region.flip(true, false);
runningRight = true;
}
I'm testing if either the boolean flag for facing right is set or the x-axis velocity of my player b2body has a positive/negative value and if my texture region is already flipped or not and then use libGDX's flip() accordingly. I should not be messing with fixture coords anywhere here, hence my confusion.
The coordinates of box2d fixtures are offsets from the position, the position isn't necessarily the center (although it could be depending on your shape definition offsets). So in your case i think the position is actually the lower left point of the box2d polygon shape.
In which case you don't need to adjust for width and height because sprites are also drawn from bottom left position. So all you need is ;
setPosition(b2body.getPosition().x , b2body.getPosition().y );
I'm guessing you flip the box2d body when the player looks left the position of the shape is now bottom right so the sprite offset of width/2 and height/2 is from the bottom right instead. So specifically when you are looking left you need an offset of
setPosition(b2body.getPosition().x - getWidth() , b2body.getPosition().y );
I think looking right will be fixed from this, but i don't know for sure how you handle looking left in terms of what you do to the body, but something is done because the offset changes entirely as shown in your capture. If you aren't doing some flipping you could add how you handle looking right to the question.
EDIT
It seems the answer was that the sprite wasn't centered in the sprite sheet and this additional space around the sprite caused the visual impression of being in the wrong place (see comments).
I have this code
textureAtlas = TextureAtlas("atlas.atlas")
val box = textureAtlas.findRegion("box")
I want to create a texture with "box". Is it possible? box.texture return the original texture, not the regioned. Oh and I don't want to use Sprite and SpriteBatch. I need this in 3D, not 2D.
Thanks
TextureAtlas actually not separating pieces. When you get region from atlas its just saying that this is the area you gonna use (u,v,u2,v2) and this is original reference to whole texture.
This is why batch.draw(Texture) and batch.draw(TextureRegion) are not same in use.
However taking part of picture as texture is possible.
You can use pixmap to do it.
First generate pixmap from atlas texture. Then create new empty pixmap in size of "box" area you want. Then assign pixel arrays and generate texture from your new pixmap.
It may be quite expensive due to your Textureatlas size.
You can use framebuffer.
Create FBbuilder and build new frame buffer.Draw texture region to this buffer and get texture from it.
Problem here is the sizes of texture will be same as viewport/screen sizes.I guess you can create new camera to change it to sizes you want.
GLFrameBuffer.FrameBufferBuilder frameBufferBuilder = new GLFrameBuffer.FrameBufferBuilder(widthofBox, heightofBox);
frameBufferBuilder.addColorTextureAttachment(GL30.GL_RGBA8, GL30.GL_RGBA, GL30.GL_UNSIGNED_BYTE);
frameBuffer = frameBufferBuilder.build();
OrthographicCamera c = new OrthographicCamera(widthofBox, heightofBox);
c.up.set(0, 1, 0);
c.direction.set(0, 0, -1);
c.position.set(widthofBox / 2, heightofBox / 2, 0f);
c.update();
batch.setProjectionMatrix(c.combined);
frameBuffer.begin();
batch.begin();
batch.draw(boxregion...)
batch.end();
frameBuffer.end();
Texture texturefbo = frameBuffer.getColorBufferTexture();
Texturefbo will be y flipped. You can fix this with texture draw method by setting scaleY to -1 or You can scale scaleY to -1 while drawing on framebuffer or can change camera like this
up.set(0, -1, 0);
direction.set(0, 0, 1);
to flip to camera on y axis.
Last thing came to my mind is mipmapping this texture.Its also not so hard.
texturefbo.bind();
Gdx.gl.glGenerateMipmap(GL20.GL_TEXTURE_2D);
texturefbo.setFilter(Texture.TextureFilter.MipMapLinearLinear,
Texture.TextureFilter.MipMapLinearLinear);
You can do this:
Texture boxTexture = new TextureRegion(textureAtlas.findRegion("box")).getTexture();
Actually I draw a part of my tiled map using camera zoom (with OrthogonalTiledMapRenderer on my main camera). Camera is centered on player position (who is always at center of the screen) in a box2d world.
// Set camera postion center on player (box2d body) on every update
camera.position.set(player.getBody().getWorldCenter(), 0);
I would like to create a minimap with a second camera. A simple filled rectangle with a point who represent player position on map.
So I created a new camera :
minimapCamera = new OrthographicCamera(1280, 720); // as my main camera
minimapCamera.zoom = 6; // larger zoom
minimapCamera.position.set(-1280 * 2, 720 * 3, 0); // align bottom right corner
And I try to draw shapes :
ShapeRenderer sr = new ShapeRenderer();
sr.setAutoShapeType(true);
sr.setProjectionMatrix(minimapCamera.combined);
sr.begin(ShapeType.Filled);
sr.setColor(0.5f, 0.5f, 0.5f, 0.3f);
// minimap rectangle background
sr.rect(0, 0, minimapCamera.viewportWidth, minimapCamera.viewportHeight);
sr.setColor(1f, 0f, 0f, 0.4f);
// player circle point
sr.circle(playerPos.x, playerPos.y, 20);
sr.end();
But how can I calculate the player position playerPos in the whole tiled map ? And how to draw only a part of zoomed map ? (I don't want to draw all map but a more larger section than my main camera).
EDIT :
If I want to reuse my tiled map in my minimap, how can I draw only player visible section in the minimap (at the moment, all the map is rendered even if I specify a small camera size) ?
Assuming your tile map makes use of rows and columns and each cell has a set width and height, you can get the player's position in the tile map array like this (hope you don't mind JavaScript):
var player={x:200,y:200};/* Or whatever position. */
var tile_width=tile_height=32;/* Or whatever dimension you're using. */
player.tile_x=Math.floor(player.x/tile_width);
player.tile_y=Math.floor(player.y/tile_height);
This gives you the exact x and y tile the player occupies in the world.
I'm trying to draw an arbitrary polygon with a transformed texture with Graphics API .
Here's what I'm trying to do in 3 steps:
First, I have a texture (as a BitmapData)
Second, Transform the texture - Tile it and rotate it around x, y or z axis. (y-axis for now).
Third, Draw a polygon using the transformed texture.
I could rotate it around z-axis with the code below:
var gr:Graphics = sp.graphics;
gr.clear();
var mat:Matrix = new Matrix();
mat.scale( 0.5, 0.5 );
mat.rotate( angle );
gr.beginBitmapFill( bd, mat, true, true );
gr.moveTo( points[0].x, points[0].y );
for ( var lp1:int = 1; lp1 < points.length; lp1++ )
gr.lineTo( points[lp1].x, points[lp1].y );
gr.lineTo( points[0].x, points[0].y );
gr.endFill();
But I couldn't rotate the texture around x or y axis as it requires some sort of projection I guess.
I thought about drawing a rotated Bitmap object onto a BitmapData and using it as a texture:
var bmp:Bitmap = new Bitmap( bd );
bmp.rotationY = angle;
var transformedBd:BitmapData = new BitmapData( 256, 256, true, 0 );
transformedBd.draw( bmp );
… and call gr.beginBitmapFill() with the transformedBd …
But with this code, the texture won't be tiled.
I also looked at drawTriangles() method but AFIK, it only let me draw a rotated polygon, not a polygon with rotated texture.
If anyone has insights on this issue, please share.
Any help will be greatly appreciated!
Perhaps you can:
put your 2D Texture inside a Sprite or other container
3D transform that container, for example by using
myContainer.rotationX = 20;
myContainer.rotationY = 200;
3 - then you create a new BitmapData()
4 - and you DRAW the entire myContainer into the bitmapdata.
myBitmapData.draw(myContainer, myMatrix, myColorTransform, blendMode, myRectangle, smooth);
5 - and finally you delete the original 2D texture and myContainer.
Voila, you now have a 3d transformed texture inside a single bitmapdata.
I'm trying to make a game where you build a spaceship from parts, and fly it around and such.
I would like to create the ship from a series of components (from a TextureAtlas for instance). I'd like to draw the ship from it's component textures, and then save the drawn ship as one large Texture. (So i don't have to draw 50 component textures, just one ship texture. What would be the best way to go about this?
I've been trying to do so using a FrameBuffer. I've been able to draw the components to a Texture, and draw the texture to the screen, but no matter what I try the Texture ends up with a solid background the size of the frame buffer. It's like the clear command can't clear with transparency. Here's the drawing code I have at the moment. The ship is just a Sprite which i save the FrameBuffer texture to.
public void render(){
if (ship == null){
int screenwidth = Gdx.graphics.getWidth();
int screenheight = Gdx.graphics.getHeight();
SpriteBatch fb = new SpriteBatch();
FrameBuffer fbo = new FrameBuffer(Format.RGB888, screenwidth, screenheight, false);
fbo.begin();
fb.enableBlending();
Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClearColor(1, 0, 1, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
fb.begin();
atlas.createSprite("0").draw(fb);
fb.end();
fbo.end();
ship = new Sprite(fbo.getColorBufferTexture());
ship.setPosition(0, -screenheight);
}
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.enableBlending();
batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ZERO);
ship.draw(batch);
batch.end();
}
The problem here lies in this line:
FrameBuffer fbo = new FrameBuffer(Format.RGB888, screenwidth, screenheight, false);
specifically with Format.RGB888. This line is saying that your FrameBuffer should be Red (8 bits) followed by Green (8 bits) followed by Blue (8 bits). Notice however, that this format doesn't have any bits for Alpha (transparency). In order to get transparency out of your frame buffer, you probably instead want to use the Format.RGBA8888, which includes an additional 8 bits for Alpha.
Hope this helps.