On my class I'm implementing ApplicationListener, so on my create method this is what I do:
public void create(){
camera=new Camera();
camera.setToOrtho(false,screenW,screenH);
}
//then on the render method:
public void render(){
camera.update();
}
But then when I use Gdx.input.getY() the result is reversed, when I go up the Y coordinate is less and when I go down the it gets higher.For better understanding:
Have a look at the camera class and the unproject method. That should translate between screen coordinates and world coordinates. (Probably more efficient way to do this, but for illustration):
float x = Gdx.input.getX();
float y = Gdx.input.getY();
float z = 0.0f;
Vector3 screenCoordinates = new Vector3(x, y, z);
Vector3 worldCoordinates = camera.unproject(screenCoordinates);
Then use the worldCoordinates vector for whatever you need it for.
EDIT: Added small working example and screenshot. My screen capture didn't capture the mouse, thus the red "star". But this simple app displays y coordinates in "initial" and "unprojected" coords as you move the mouse around the screen. Try it for yourself. I think this is what you are getting at, no?
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector3;
public class SimpleInputCoords implements ApplicationListener {
private OrthographicCamera camera;
#Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
}
#Override
public void render() {
int x = Gdx.input.getX();
int y = Gdx.input.getY();
int z = 0;
System.out.println("UnmodifiedYCoord:"+y);
Vector3 screenCoordinates = new Vector3(x, y, z);
Vector3 worldCoordinates = camera.unproject(screenCoordinates);
System.out.println("UnprojectedYCoord:"+worldCoordinates.y);
}
#Override
public void dispose() {
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
In Java coordinates start in the upper left corner (0,0). On a 100 x 100, (100,0) would be upper right, and (0, 100) would be lower left. So the behavior you are seeing is expected.
http://inetjava.sourceforge.net/lectures/part2_applets/InetJava-2.1-2.2-Introduction-to-AWT-and-Applets_files/image001.gif
Related
I am making a game with a shooter such that when use click it should move left or right but it is made on canvas and onclick listeners didn't work on it so someone told me to get coordinates of canvas and use onclick listeners on it but he don't tell me how to do it
My Code
package --------;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
public class Cannon {
float x = -1; // Cannon's center (x,y)
float y = -1;
float stepX = 40;
int lowerX, lowerY, upperX, upperY;
private Paint paint;
private Context mContext;
// Constructor
public Cannon(int color, Context c) {
paint = new Paint();
paint.setColor(color);
mContext = c;
}
public void setBounds(int lx, int ly, int ux, int uy) {
lowerX = lx;
lowerY = ly;
upperX = ux;
upperY = uy;
x = ux/2;
y = uy;
}
public void moveLeft() {
if (x - 30 > 0) {
x -= stepX;
}
}
public void moveRight() {
if (x + 30 < upperX) {
x += stepX;
}
}
public float getPosition() {
return x;
}
public void draw(Canvas canvas) {
canvas.drawLine(x, y -120, x, y, paint);
canvas.drawRect(x - 90, y - 40, x + 90, y, paint);
}
}
how to use onclick listeners for this rectangle by getting its coordinates to do move left function
You already have a method getPosition, but it only returns the x position.. Create one that returns x and one that returns y, for example:
public float getCannonX(){
return x;
}
public float getCannonY(){
return y;
}
Then in your Activity you can set an onClickListener on your cannon object and access the methods above.
Or you can set an onClickListener on your canvas and use the above methods to check if the cannon coordinates was selected.
You should factor in the size of the cannon object as well
So I am just trying to make my game character, which is a texture (ball), to jump up in the air and then return back down to the position that it started at when the screen is pressed. I was just wondering if someone could give me a code example or help me to do this with my current code which is below. I have basically just drawn the background and the ball texture and positioned the ball where I want it to start the jump. The ball texture is what I want to make jump straight up.
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
Texture background;
Texture ball;
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("gamebackground.png");
ball = new Texture("ball2.png");
ball.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
}
#Override
public void render () {
batch.begin();
float scaleFactor = 2.0f;
batch.draw(background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.draw(ball, 80, 145, ball.getWidth() * scaleFactor, ball.getHeight() * scaleFactor);
batch.end();
}
#Override
public void dispose () {}
}
There are a million ways to do this.
Here's a simple (and not very flexible way). Create a Ball class that has variables for x and y position, velocity, and acceleration. Then give it an update method for applying the acceleration and velocity to the position:
public class Ball {
public static final float GRAVITY = -100; // size depends on your world scale
public static final float BOUNCE_DAMPENING = 0.6f;
public final Vector2 position = new Vector2();
public final Vector2 velocity = new Vector2();
public final Vector2 acceleration = new Vector2(0, GRAVITY);
public void update (){
float dt = Gdx.graphics.getDeltaTime();
velocity.add(acceleration.x * dt, acceleration.y * dt));
position.add(velocity.x * dt, velocity.y * dt);
if (position.y <= 0){ // hit ground, so bounce
position.y = -position.y * BOUNCE_DAMPENING;
velocity.y = -velocity.y * BOUNCE_DAMPENING;
}
}
}
This is a very rudimentary way of handling physics. It would be more sophisticated to use Box2D, but the above is fine if you're just learning.
Now, you need to create a ball instance and use it to track your ball position. Use the Ball object's position when drawing it. And you can react to taps to apply a velocity.
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
Texture background;
Texture ballTexture;
Ball ball;
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("gamebackground.png");
ballTexture = new Texture("ball2.png");
ballTexture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
ball = new Ball();
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // don't forget to clear screen
if (Gdx.input.justTouched())
ball.velocity.y += 100;
ball.update();
batch.begin();
float scaleFactor = 2.0f;
batch.draw(background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.draw(ballTexture, ball.position.x, ball.position.y, ballTexture.getWidth() * scaleFactor, ballTexture.getHeight() * scaleFactor);
batch.end();
}
#Override
public void dispose () {
batch.dispose();
background.dispose();
ballTexture.dispose();
}
}
You also need to read up on pixel units vs. world units and how to solve the scale problem with Viewports. See https://xoppa.github.io/blog/pixels/ and https://github.com/libgdx/libgdx/wiki/Viewports
I have a tiled map on which I set characters(every character is of the size of one tile). I managed to make them clickable, even when screen resizes everything works perfect. Every time I click on character I want a button to show up above it. For a button I use stage and place the button in the place I clicked with small transition and it also works.
My problem is when I try to use clicklistener on this button. If the screen does not resize, clicklistener works. Problem starts when the screen get resized - clicks on players works well, only button does not work - after a resize the clicking space and the button space are not aligned. For test purposes I made a test map that shows me grids. It seems that stage is not properly resized. Picture for a reference. I tried many solutions I came upon on the Internet and still can't find a solution to my problem. I have shortened my code down to a minimum basic example:
public class Test extends ApplicationAdapter {
public static Stage stage;
public TiledMap tiledMap;
static OrthographicCamera camera;
TiledMapRenderer tiledMapRenderer;
public static boolean showMenu;
GestureDetector gesture;
InputMultiplexer myInputMultiplexer;
public static int posx, posy;
public static Image move;
public Texture moveMenu;
#Override
public void create() {
moveMenu = new Texture(Gdx.files.internal("move.png"));
gesture = new GestureDetector(new MyGestureListener());
myInputMultiplexer = new InputMultiplexer();
float unitScale = 1 / 32f;
camera = new OrthographicCamera();
camera.setToOrtho(true, 33, 21);
stage = new Stage(new ScreenViewport());
stage.getViewport().setCamera(camera);
tiledMap = new TmxMapLoader().load("test.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, unitScale);
myInputMultiplexer.addProcessor(stage);
myInputMultiplexer.addProcessor(gesture);
Gdx.input.setInputProcessor(myInputMultiplexer);
move = new Image(moveMenu);
move.setWidth(2);
move.setHeight(2);
move.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
move(); //my action, works fine
showMenu = false;
}
});
stage.addActor(move);
}
#Override
public void render() {
super.render();
stage.act();
tiledMapRenderer.setView(camera);
camera.update();
tiledMapRenderer.render();
if (showMenu) {
mainMenuDraw();
}
}
public static void mainMenuDraw() {
move.setPosition(posx, posy-2);
stage.draw();
}
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
public static OrthographicCamera getCamera() {
return camera;
}
public static Vector3 unprojectCoords(Vector3 coords) {
camera.unproject(coords);
return coords;
} }
and part of my gesturelistener:
public boolean touchDown(float x, float y, int pointer, int button) {
Vector3 temp_coord = new Vector3(x, y, 0);
Vector3 coords = Test.unprojectCoords(temp_coord);
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
Vector3 temp_coord = new Vector3(x, y, 0);
Vector3 coords = Test.unprojectCoords(temp_coord);
Test.posx = (int) coords.x;
Test.posy = (int) coords.y;
tap = true;
Test.showMenu = true;
return false;
}
I would suggest to you read more about re-sizing and displaying pixels.
You need to recalculate pixels always when you render something.
- player, background image, buttons, events.
Actually you don't need to use resize method, just get the camera width and height.
You need to share more code, because it depends on everything.
I don't see how you are doing rendering.
tiledMapRenderer.render(), background rendering / layers?
player rendering?
menu rendering?
buttons rendering?
Example: (the same should be for event handler)
public GameButton(TextureRegion reg, float x, float y, OrthographicCamera cam) {
this.reg = reg;
this.x = x;
this.y = y;
this.cam = cam;
width = reg.getRegionWidth();
height = reg.getRegionHeight();
vec = new Vector3();
Texture tex = Game.res.getTexture("hud");
font = new TextureRegion[11];
for(int i = 0; i < 11; i++) {
font[i] = new TextureRegion(tex, 32 + i * 9, 16, 9, 9); //use height and width here)
}
}
Here is my Core project :
public class GameClass extends Game {
public static int screenWidth, screenHeight;
public static CustomScreen currentScreen;
public static PlayScreen playScreen;
#Override
public void create () {
screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight();
CustomScreen.initialize();
playScreen = new PlayScreen(this);
SetScreen(playScreen);
}
public void SetScreen(CustomScreen screen) {
currentScreen = screen;
setScreen(currentScreen);
}
}
public abstract class CustomScreen implements Screen {
GameClass game;
static BitmapFont font;
static SpriteBatch batcher;
static OrthographicCamera cam;
public CustomScreen(GameClass game) {
this.game = game;
}
public static void initialize() {
cam = new OrthographicCamera();
cam.setToOrtho(true, GameClass.screenWidth, GameClass.screenHeight);
batcher = new SpriteBatch();
batcher.setProjectionMatrix(cam.combined);
font = new BitmapFont();
font.setScale(4f, -4f);
}
public void Clear() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
#Override
public abstract void render(float delta);
}
public class PlayScreen extends CustomScreen {
public static final int speed = 300;
public ArrayList<Entity> entityList;
Random rand = new Random();
float timer = rand.nextInt(2) + rand.nextFloat();
public PlayScreen(GameClass game) {
super(game);
entityList = new ArrayList<Entity>();
}
void update(float delta) {
timer -= delta;
if (timer <= 0) {
entityList.add(new Enemy(GameClass.screenWidth, rand.nextInt(GameClass.screenHeight - Enemy.Height)));
timer += rand.nextInt(2) + rand.nextFloat() + 1/2;
}
for (int i = entityList.size(); i > 0; --i)
entityList.get(i-1).update(delta);
}
#Override
public void render(float delta) {
Clear();
update(delta);
batcher.begin();
for (int i = 0; i < entityList.size(); ++i) {
entityList.get(i).Display(batcher);
}
if (entityList.size() > 1)
System.out.println(entityList.get(1).posX - entityList.get(0).posX);
batcher.end();
}
}
public abstract class Entity {
protected Sprite sprite;
public int posX, posY, width, height;
public Entity(int posX, int posY, int width, int height) {
this.posX = posX;
this.posY = posY;
this.width = width;
this.height = height;
}
public abstract void update(float delta);
public void Display(SpriteBatch batcher) {
batcher.draw(sprite, posX, posY, width, height);
}
}
public class Enemy extends Entity {
static Sprite texture = new Sprite(new Texture(Gdx.files.internal("enemy.png")));
public static int Width = 300, Height = 200;
public Enemy(int posX, int posY) {
super(posX, posY, Width, Height);
this.sprite = Enemy.texture;
}
#Override
public void update(float delta, int i) {
posX -= delta * PlayScreen.speed;
if (posX + width < 0) {
GameClass.playScreen.entityList.remove(this);
}
}
}
In PlayScreen, enemies keep spawning randomly, and they move from the right of the screen to the left, at a constant speed (final int 300). But when they reach the left edge of the screen (when posX <= 0), they slow down, for an unknown reason. The thing is, I didn't program anything to happen when an enemy reaches the edge of the screen. (I programmed them to disappear when they are completely outside of the screen, when posX + width <= 0, but it has nothing to do with my problem, since even when I remove this, they keep slowing down when reaching the edge of the screen).
It happends with both the desktop and the android projects, so this definitely comes from the Core project.
I have no idea why this happens, this is really, really awkward.
Here is a couple picture to show you what happens.
http://i.stack.imgur.com/DrOSH.png
http://i.stack.imgur.com/Zjtju.png
We can see that the two enemies are closer to each other on the second picture than on the first one.
You can set PlayScreen.speed to 100 instead of 300, it will be even more noticeable.
And if you set it to a low enough value, like 20, enemies will not just slow down, they will basically stop moving.
I'm lost and have no idea how to fix this problem. If you have any, please feel free to share it.
I fixed it. The problem was that Enemy.posX was an int instead of a float.
I'm not quite certain but I'd guess that your calculations in the Enemy class involving delta get rounded (since PlayScreen.Speed is an integer).
Having a low enough PlayScreen.Speed or a low enough delta will result in delta * PlayScreen.Speed being 0.something which will get cut off to 0 when converting to an integer, resulting in posX never changing.
I usually use floats for all calculations involving positions (e.g. posX and posY and so on...) so that this cutting off doesn't happen until something gets drawn on the screen (since pixels are always integers). This produces more accurate results and solves a lot of problems around movement on the screen.
I'm trying to implement a camera for a 2D game that I'm making... The goal will to have the cam keep the player in the center and the sprites relative to the camera.
To get the hang of normalocity's post, I tried starting off simple by making a Camera Test project, where I'd simulate a camera by drawing a sprite to a JPanel, and moving a "camera" object (which is the JPanel) around and setting the sprite's x,y relative to that.
The Camera, as I said, is the JPanel... and I've added a "world", which is a class with an x,y of 0,0, and w=1000, h=1000. I've included the sprite's location relative to the world as well as the camera. When I move the camera up, the sprite moves down and the player stays in the middle as expected..
But if I keep pressing down, the sprite seems to keep drawing over itself.
My questions are:
Am I on the right track in implementing a camera given the code below?
Why does the sprite start to draw over itself there? It should just disappear off the viewPort/JPanel
Thanks!
Now with PaintComponent(g) added, my JPanel bg color of gray now slides off. Is this supposed to happen?
EDIT: SSCCE of my program:
Main Class:
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class MainSSCCE extends JFrame {
static MainSSCCE runMe;
public MainSSCCE() {
JFrame f = new JFrame("Camera Test");
CameraSSCCE cam = new CameraSSCCE(0, 0, 500, 500);
f.add(cam);
f.setSize(cam.getWidth(), cam.getHeight());
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
f.setLocation( (screensize.width - f.getWidth())/2,
(screensize.height - f.getHeight())/2-100 );
}
public static void main(String[] args) {
runMe = new MainSSCCE();
}
}
Camera Class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
//Camera is the JPanel that will draw all objects... each object location will be in relation to the World
public class CameraSSCCE extends JPanel implements KeyListener {
//add world to camera...
private static final long serialVersionUID = 1L;
private int camX, camY, camH, camW;
private SpriteSSCCE sprite;
private PlayerSSCCE player;
private WorldSSCCE world;
public CameraSSCCE(int x, int y, int w, int h) {
camX = x;
camY = y;
camW = w;
camH = h;
sprite = new SpriteSSCCE(this, 300, 300, 20, 20);
player = new PlayerSSCCE(this, camW/2, camH/2, 25, 40);
world = new WorldSSCCE(this, 0, 0, 1000, 1000);
addKeyListener(this);
setFocusable(true);
}
public int getWidth() {
return camW;
}
public int getHeight() {
return camH;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//cam is 500 x 500
g.setColor(Color.gray);
g.fillRect(camX, camY, camW, camH);
//draw sprite at JPanel location if in camera sight
if (((sprite.getX()-camX) >= camX) && ((sprite.getX()-camX) <= (camX+camW)) && ((sprite.getY()-camY) >= camY) && ((sprite.getY()-camY) <= (camY+camH))) {
g.setColor(Color.green);
g.fillRect(sprite.getX()-camX, sprite.getY()-camY, 20, 20);
//Cam Sprite Location
g.setColor(Color.white);
g.drawString("Camera Sprite Location: (" + (sprite.getX()-camX) + ", " + (sprite.getY()-camY) + ")", sprite.getX()-camX, sprite.getY()-camY);
}
//Player location (center of Camera... Camera follows player)
g.setColor(Color.cyan);
g.fillRect(player.getX()-player.getWidth(), player.getY()-player.getWidth(), player.getWidth(), player.getHeight());
g.setColor(Color.white);
//World Sprite Location
g.drawString("World Sprite Location: (" + sprite.getX() + ", " + sprite.getY() + ")", sprite.getX(), sprite.getY());
//Cam Player Location
g.drawString("Cam Player Location: (" + (camW/2-player.getWidth()) + ", " + (camH/2-player.getHeight()) + ")", camW/2-player.getWidth(), camH/2-player.getHeight());
}
public void keyPressed(KeyEvent e) {
//move camera right in relation to World
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
camX+=5;
}
//move camera left in relation to World
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
camX-=5;
}
//move camera up in relation to World
if (e.getKeyCode() == KeyEvent.VK_UP) {
camY-=5;
}
//move camera down in relation to World
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
camY+=5;
}
repaint();
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
World Class:
public class WorldSSCCE {
private int x, y, w, h;
private CameraSSCCE camera;
public WorldSSCCE(CameraSSCCE cam, int x, int y, int w, int h) {
camera = cam;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public int getWidth() {
return this.w;
}
public int getHeight() {
return this.h;
}
}
Player Class:
import java.awt.Dimension;
public class PlayerSSCCE {
private int x, y, w, h;
private CameraSSCCE cam;
public PlayerSSCCE(CameraSSCCE cm, int x, int y, int w, int h) {
cam = cm;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public int getWidth() {
return this.w;
}
public int getHeight() {
return this.h;
}
public void setX(int val) {
this.x += val;
}
public void setY(int val) {
this.y += val;
}
}
Sprite Class:
import java.awt.Color;
import java.awt.Graphics;
public class SpriteSSCCE {
private int xLoc, yLoc, width, height;
private CameraSSCCE world;
public SpriteSSCCE(CameraSSCCE wld, int x, int y, int w, int h) {
xLoc = x;
yLoc = y;
width = w;
height = h;
world = wld;
}
public int getX() {
return xLoc;
}
public int getY() {
return yLoc;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void paintComponent(Graphics g) {
g.setColor(Color.green);
g.fillRect(xLoc, yLoc, width, height);
}
}
1) You have not honored the paint chain by calling super.paintComponent(g) in paintComponent(..):
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//do drawing here
}
As per Java docs:
protected void paintComponent(Graphics g)
Further, if you do not invoker super's implementation you must honor
the opaque property, that is if this component is opaque, you must
completely fill in the background in a non-opaque color. If you do not
honor the opaque property you will likely see visual artifacts.
2) Also notice the #Override annotation I added and the fact that I changed public modifier to protected as thats what the access level is defined as in the implementation class which we should keep unless for a specific reason.
3) Also Swing uses Keybindings have a read on How to Use Key Bindings
4) Also have a read on Concurrency in Swing specifically on The Event Dispatch Thread which dictates all swing components be created on EDT via SwingUtillities.invokeXXX(..) block:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//create and manipulate swing components here
}
});
5) You extend the JFrame class and create an instance, this is not what you want rather remove the extends JFrame from the class declaration:
public class MainSSCCE extends JFrame { //<-- Remove extends JFrame
public MainSSCCE() {
JFrame f = new JFrame("Camera Test");//<-- instance is created here
}
}
Your world is a virtual area larger than the screen (or your jpanel for what matters). All objects' positions are relative to the world. Let's call them absolute coordinates.
Your camera is a small rectangular portion of the world (your panel). By moving it you see different world portions. If you could move the camera like in the post you link to, then at some point you would not be able to see neither the player nor the other sprite.
Since your goal is to keep the player centered on the screen what does this mean for our world? This means that the player and the camera are moving together in relation to the world.
Given the above it does not make sense to draw a camera sprite as in your first screenshot. The camera sprite should be either invisible or it should be drawn in the same position with the player sprite. Nor it makes sense to change the camera's absolute coordinates without changing the player's. Those two are moving together. (take this into account in your keyPressed() methods)
Now when you are drawing, you are drawing from the camera's point of view (or in other words in the camera's coordinate system). From that point of view, the camera always see a rectangle of (0, 0, cameraWidth, cameraHeight). That's what you should use when clearing the area with gray color. This will fix your moving background issue. Since camera and player always have the same absolute coordinates the player will always be in the same place (this is what we want). The rest of the sprites will be seen relative to camera.
For each one of them you translate them in the camera's coordinate system when you do (sprite.x - cam.x) and (sprite.y - cam.y). Since they are translated, you only need to check if they are inside the camera's rectangle (0, 0, cameraWidth, cameraHeight). If they are you go ahead and draw them. If not ignore them.
I hope that helps
Note: cameraWidth, cameraHeight are your jpanel's dimensions