So I am trying to make a 2d game using SurfaceView (It draws and moves the objects). The game is almost done but I am facing a major problem which is that my moving objects on the screen lag or get stuck (probably skipping frames). Maybe the canvas.drawBitmap() method is not drawing it fast enough. I have tried many things like accelerating hardware in manifests and using low quality images (which I'm converting to bitmap). And I DO NOT create bitmaps on each frame. I think the problem might be in the draw or update method. here are these methods:
UPDATE:
private void update() {
background1.x -= backGroundSpeed * screenRatioX;
background2.x -= backGroundSpeed * screenRatioX;
if (background1.x + background1.background.getWidth() < 0){
background1.x = screenX;
}
if (background2.x + background2.background.getWidth() < 0){
background2.x = screenX;
}
if (flight.isGoingUp){
flight.y -= flightSpeed * screenRatioY;
}else{
flight.y += flightSpeed * screenRatioY;
}
if (flight.y < 0){
flight.y = 0;
}
if (flight.y >= (screenY - flight.height)){
flight.y = screenY - flight.height;
}
for (Pig pig: pigs){
pig.x -= pig.speed;
if (pig.x + pig.normal_width < 0) {
int bound = (int) (13 * screenRatioX);
pig.speed = random.nextInt(bound);
if (pig.speed < (backGroundSpeed * screenRatioX)+1) {
pig.speed = (int) (backGroundSpeed * screenRatioX)+1;
}
pig.x = screenX*2;
pig.y = random.nextInt(screenY - pig.normal_height);
}
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
if (Rect.intersects(pig.getCollisionShape(), flight.getCollisionShape())){
score++;
pig.x = -500;
if (!prefs.getBoolean("isMute", false)){
soundPool.play(point_sound, 1, 1, 0, 0, 1);
}
}
}
}, 500);
}
redPig.x -= redPig.redSpeed;
if (redPig.x + redPig.red_width < 0) {
int bound = (int) (25 * screenRatioX);
redPig.redSpeed = random.nextInt(bound);
if (redPig.redSpeed < (12 * screenRatioX)) {
redPig.redSpeed = (int) (12 * screenRatioX);
}
redPigDistance = random.nextInt(6);
if (redPigDistance < 2){
redPigDistance = 2;
}
redPig.x = screenX*redPigDistance;
redPig.y = random.nextInt(screenY - redPig.red_height);
}
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
if (Rect.intersects(redPig.getRedCollisionShape(), flight.getCollisionShape())){
isGameOver = true;
if (!prefs.getBoolean("isMute", false)){
soundPool.play(dead_sound, 1, 1, 0, 0, 1);
}
}
}
}, 500);
}
DRAW:
private void draw() {
if (getHolder().getSurface().isValid()){
Canvas canvas = getHolder().lockCanvas();
canvas.drawBitmap(background1.background, background1.x, background1.y, paint);
canvas.drawBitmap(background2.background, background2.x, background2.y, paint);
if (isGameOver){
isPlaying = false;
canvas.drawBitmap(flight.getDead(), flight.x, flight.y, paint);
getHolder().unlockCanvasAndPost(canvas);
saveIfHighScore();
waitBeforeExiting();
return;
}
for (Pig pig : pigs) {
canvas.drawBitmap(pig.getPig(), pig.x, pig.y, paint);
}
canvas.drawBitmap(redPig.getRedPig(), redPig.x, redPig.y, paint);
canvas.drawText("" + score, screenX/2f, (70*screenRatioY), paint);
canvas.drawBitmap(flight.getFlight(), flight.x, flight.y, paint);
getHolder().unlockCanvasAndPost(canvas);
}
}
Related
So this is the class where I create the circles which works fine.
public class CircleAnimations {
private ArrayList<Circle> circles; // the circles to animate
private int size; // canvas width and height (will be square)
private Random rng; // use to make random numbers
/** create a drawing pane of a particular size */
public CircleAnimations(int s) {
circles = new ArrayList<>();
size = s;
rng = new Random();
//don't mess with this
StdDraw.setCanvasSize(size, size); // set up drawing canvas
StdDraw.setXscale(0, size); // <0, 0> is bottom left. <size-1, size-1> is top right
StdDraw.setYscale(0, size);
}
public void drawCircle() {
for (int i = 0; i < circles.size(); i++) {
circles.get(i).draw();
}
}
public void addCircle() {
circles.add(new Circle(rng.nextInt(size - 1), rng.nextInt(size - 1), rng.nextInt(75),
new Color(rng.nextInt(255), rng.nextInt(255), rng.nextInt(255))));
circles.add(new Circle(rng.nextInt(size - 1), rng.nextInt(size - 1), rng.nextInt(75),
new Color(rng.nextInt(255), rng.nextInt(255), rng.nextInt(255))));
circles.add(new Circle(rng.nextInt(size - 1), rng.nextInt(size - 1), rng.nextInt(75),
new Color(rng.nextInt(255), rng.nextInt(255), rng.nextInt(255))));
drawCircle();
}
public void removeClicked() {
addCircle();
while (circles.size() > 0) {
for (int i = circles.size() - 1; i > 0; i--) {
double mouseXPos = StdDraw.mouseX();
double mouseYPos = StdDraw.mouseY();
if (StdDraw.isMousePressed()) {
if (mouseXPos < circles.get(i).getX() + circles.get(i).getRadius()
|| mouseXPos > circles.get(i).getX() - circles.get(i).getRadius()) {
if (mouseYPos < circles.get(i).getY() + circles.get(i).getRadius()
|| mouseYPos > circles.get(i).getX() - circles.get(i).getRadius()) {
circles.remove(i);
drawCircle();
}
}
}
}
}
}
}
The method for deleting the circle which was clicked on isn't working for some reason.
i'm trying to create a game using Kinect where you have to use your hand movements to wipe away an image to make it disappear revealing another image beneath it within 30 seconds. Now I have already done the code for the loosing condition where if you do not wipe away the image under 30 seconds, the loosing screen will pop up.
However, I am not sure how to code the part to detect when the entire PNG image has been "wiped away". Does this involve using get()? I am not sure how to approach this.
Imagine there are 2 Pimages moondirt.png and moonsurface.png
The Kinect controls the wiping and making Pimage moondirt.png transparent to reveal moonsurface.png
void kinect() {
//----------draw kinect------------
// Draw moon surface
image(moonSurface, 0, 0, width, height);
// Draw the moon dirt
image(moonDirt, 0, 0, width, height);
// Threshold the depth image
int[] rawDepth = kinect.getRawDepth();
for (int i=0; i < rawDepth.length; i++) {
if (rawDepth[i] >= minDepth && rawDepth[i] <= maxDepth) {
depthImg.pixels[i] = color(255);
maskingImg.pixels[i] = color(255);
} else {
depthImg.pixels[i] = color(0);
}
}
//moonDirt.resize(640, 480); //(640, 480);
moonDirt.loadPixels();
for (int i=0; i < rawDepth.length; i++) {
if ( maskingImg.pixels[i] == color(255) ) {
moonDirt.pixels[i] = color( 0, 0, 0, 0 );
}
}
moonDirt.updatePixels();
image(moonDirt, 0, 0, width, height);
color c = moonDirt.get(width, height);
updatePixels();
//--------timer-----
if (countDownTimer.complete() == true){
if (timeLeft > 1 ) {
timeLeft--;
countDownTimer.start();
} else {
state = 4;
redraw();
}
}
//show countDown TIMER
String s = "Time Left: " + timeLeft;
textAlign(CENTER);
textSize(30);
fill(255,0,0);
text(s, 380, 320);
}
//timer
class Timer {
int startTime;
int interval;
Timer(int timeInterval) {
interval = timeInterval;
}
void start() {
startTime = millis();
}
boolean complete() {
int elapsedTime = millis() - startTime;
if (elapsedTime > interval) {
return true;
}else {
return false;
}
}
}
I see the confusion in this section:
moonDirt.loadPixels();
for (int i=0; i < rawDepth.length; i++) {
if ( maskingImg.pixels[i] == color(255) ) {
moonDirt.pixels[i] = color( 0, 0, 0, 0 );
}
}
moonDirt.updatePixels();
image(moonDirt, 0, 0, width, height);
color c = moonDirt.get(width, height);
You are already using pixels[] which is more efficient than get() which is great.
Don't forget to call updatePixels() when you're done. You already do that for moonDirt, but not for maskingImg
If you want to find out if an image has been cleared (where clear means transparent black (color(0,0,0,0)) in this case).
It looks like you're already familiar with functions that take parameters and return values. The count function will need to:
take 2 arguments: the image to process and the colour to check and count
return the total count
iterate through all pixels: if any pixels match the 2nd argument, the total count increments
Something like this:
/**
* countPixels - counts pixels of of a certain colour within an image
* #param image - the PImage to loop through
* #param colorToCount - the colour to count pixels present in the image
* return int - the number of found pixels (between 0 and image.pixels.length)
*/
int countPixels(PImage image,color colorToCount){
// initial transparent black pixel count
int count = 0;
// make pixels[] available
image.loadPixels();
// for each pixel
for(int i = 0 ; i < image.pixels.length; i++){
// check if it's transparent black
if(image.pixels[i] == colorToCount){
// if so, increment the counter
count++;
}
}
// finally return the count
return count;
}
Within your code you could use it like so:
...
// Threshold the depth image
int[] rawDepth = kinect.getRawDepth();
for (int i=0; i < rawDepth.length; i++) {
if (rawDepth[i] >= minDepth && rawDepth[i] <= maxDepth) {
depthImg.pixels[i] = color(255);
maskingImg.pixels[i] = color(255);
} else {
depthImg.pixels[i] = color(0);
}
}
maskingImg.updatePixels();
//moonDirt.resize(640, 480); //(640, 480);
moonDirt.loadPixels();
for (int i=0; i < rawDepth.length; i++) {
if ( maskingImg.pixels[i] == color(255) ) {
moonDirt.pixels[i] = color( 0, 0, 0, 0 );
}
}
moonDirt.updatePixels();
image(moonDirt, 0, 0, width, height);
int leftToReveal = moonDirt.pixels.length;
int revealedPixels = countPixels(moonDirt,color(0,0,0,0));
int percentageClear = round(((float)revealedPixels / leftToReveal) * 100);
println("revealed " + revealedPixels + " of " + leftToReveal + " pixels -> ~" + percentageClear + "% cleared");
...
You have the option to set the condition for all pixels to be cleared or a ratio/percentage (e.g. if more 90% is clear, that's good enough) to then change the game state accordingly.
public class MovingBagView extends View {
private Bitmap bag[] = new Bitmap[2];
private int bagX;
private int bagY = 1000;
private int bagSpeed;
private Boolean touch = false;
private int canvasWidth, canvasHeight;
private Bitmap backgroundImage;
private Paint scorePaint = new Paint();
private Bitmap life[] = new Bitmap[2];
public MovingBagView(Context context) {
super(context);
bag[0] = BitmapFactory.decodeResource(getResources(), R.drawable.bag1);
bag[1] = BitmapFactory.decodeResource(getResources(), R.drawable.bag2);
backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.background);
scorePaint.setColor(Color.BLACK);
scorePaint.setTextSize(40);
scorePaint.setTypeface(Typeface.DEFAULT_BOLD);
scorePaint.setAntiAlias(true);
life[0] = BitmapFactory.decodeResource(getResources(), R.drawable.heart);
life[1] = BitmapFactory.decodeResource(getResources(), R.drawable.heart_grey);
bagX = 10;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
canvas.drawBitmap(backgroundImage, 0, 0, null);
int minBagX = bag[0].getWidth();
int maxBagX = canvasWidth - bag[0].getWidth() * 3;
bagX = bagX + bagSpeed;
if (bagX < minBagX) {
bagX = minBagX;
}
if (bagX < maxBagX) {
bagX = maxBagX;
}
bagSpeed = bagSpeed + 2;
if (touch) {
canvas.drawBitmap(bag[1], bagX, bagY, null);
}
else {
canvas.drawBitmap(bag[0], bagX, bagY, null);
}
canvas.drawText("Score : ", 20, 60, scorePaint);
canvas.drawBitmap(life[0], 500, 10, null);
canvas.drawBitmap(life[0], 570, 10, null);
canvas.drawBitmap(life[0], 640, 10, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
touch = true;
bagSpeed = -12;
}
return true;
}
}
I can tap on the screen to move the object to the left, and the more I tap on it, the further it should move to the left. However, the problem is that the object moves too much to the right, and goes off the screen. I want it to stop at the edge, so its still visible on the screen. Furthermore, the object is positioned in the center bottom of the screen, how do I position it to the bottom left corner? You can see how it works by looking at the GIF below.
This condition is never applied on the code you've provided. It continues to exceed the max value.
if (bagX < maxBagX) {
bagX = maxBagX;
}
It should look like this:
if (bagX >= maxBagX) {
bagX = maxBagX;
}
And the maxBagX value should be canvasWidth - bag[0].getWidth() in order to achieve the right edge of the bag itself. (Unless you're using the multiply 3 times for a different reason, this should be the solution.)
Create object of the layout which ever you are using linear,relative or constraint then fetch width of the screen using that object using
object.getWidth();
I did it like this //the maintainoffscreen function will maintain the path to donot move off screen, and return true ,, else if path does not collide to any side this will return false, and you can move the path by setting offset.
private boolean maintainOffScreen(Path path, float px, float py){
boolean done = true;
RectF rectF = new RectF();
path.computeBounds(rectF,true);
float l = getPathWidth(path) - rectF.right;
float r = getPathWidth(path) + rectF.left;
float t = getPathHeight(path) - rectF.bottom;
float b = getPathHeight(path)+ rectF.top;
if(l < (-1) && r < getWidth() && b < getHeight() && t< (-1)){
//if path does not collide to any side//you can move your path here as well
//by setting Path.offset(px,py)
done = false;
offScreen = OffScreen.NOOFF; //im using these as enum according to my need,
//as this is saving which side of screen collides
}
else if(l >= (-1)){
path.offset(px+(l),py);
offScreen = OffScreen.LEFT;
offscrenn_xl = 1;
done = true;
}
else if(r >= getWidth()){
float s = getWidth() - r;
path.offset(px+(s),py);
offScreen = OffScreen.RIGHT;
offscrenn_xr = s;
done = true;
}
else if(b >= getHeight()){
float s = getHeight() - b;
path.offset(px,py+s);
offScreen = OffScreen.BOTTOM;
offscrenn_yb = s;
done = true;
}
else if(t >= (-1)){
path.offset(px,py+(t));
offScreen = OffScreen.TOP;
offscrenn_yt = t;
done = true;
}
return done;
}
confuse about px,py ? this is the movement of you finger with respect to path
`
final float px = event.getX() - this.startX;
final float py = event.getY() - this.startY;
if(!maintainOffScreen(path,px,py)){path.offset(px,py); }` //you should call
//this function here ,this will move your path to finger if there is no collision.
//and donot forgot to set the startx,and starty yo new positon like this
this.startX = event.getX();
this.startY = event.getY();
I am working on a small Java Applet that has 3 balls bounce around on screen. When they collide with the walls they make one sound and when they collide with eachother they make another sound.
My issue is that the balls flicker for some reason and I am not sure why. If someone can explain why they are flickering and how I can go about fixing the issue that would be greatly appreciated.
Here is my code:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class ass3 extends Applet implements Runnable {
int[] positionX = {0, 0, 0};
int[] positionY = {0, 0, 0};
int[] incrementX = {3, 7, 4};
int[] incrementY = {8, 4, 5};
Thread t;
AudioClip sound;
AudioClip collide;
public void init(){
sound = getAudioClip(getDocumentBase(), "Audio1.au");
collide = getAudioClip(getDocumentBase(), "Audio2.au");
}
public void start() {
t = new Thread(this);
t.start();
}
public void paint(Graphics g) {
g.fillOval(getWidth()-50-positionX[0], getHeight()-50-positionY[0], 50, 50);
g.fillOval(getWidth()-450-positionX[1], getHeight()-450-positionY[1], 50, 50);
g.fillOval(getWidth()-450-positionX[2], getHeight()-50-positionY[2], 50, 50);
}
public void run() {
while (true) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {}
for (int i=0; i < 3; i++) {
positionX[i] += incrementX[i];
positionY[i] += incrementY[i];
}
// ball 1
if (positionX[0] > 500 || positionX[0] < 0) {
incrementX[0] = -incrementX[0];
sound.play();
}
repaint();
if (positionY[0] > 500 || positionY[0] < 0) {
incrementY[0] = -incrementY[0];
sound.play();
}
repaint();
// ball 2
if (positionX[1] > 100 || positionX[1] < -400) {
incrementX[1] = -incrementX[1];
sound.play();
}
repaint();
if (positionY[1] > 100 || positionY[1] < -400) {
incrementY[1] = -incrementY[1];
sound.play();
}
repaint();
// ball 3
if (positionX[2] > 100 || positionX[2] < -400) {
incrementX[2] = -incrementX[2];
sound.play();
}
repaint();
if (positionY[2] > 500 || positionY[2] < 0) {
incrementY[2] = -incrementY[2];
sound.play();
}
repaint();
// collision
if (Math.sqrt(((getWidth()-50-positionX[0])-(getWidth()-450-positionX[1]))*((getWidth()-50-positionX[0])-(getWidth()-450-positionX[1])) + ((getHeight()-50-positionY[0])-(getHeight()-450-positionY[1]))*((getHeight()-50-positionY[0])-(getHeight()-450-positionY[1]))) <= 50) {
incrementX[0] = -incrementX[0];
incrementY[0] = -incrementY[0];
incrementX[1] = -incrementX[1];
incrementY[1] = -incrementY[1];
collide.play();
}
repaint();
if (Math.sqrt(((getWidth()-50-positionX[0])-(getWidth()-450-positionX[2]))*((getWidth()-50-positionX[0])-(getWidth()-450-positionX[2])) + ((getHeight()-50-positionY[0])-(getHeight()-50-positionY[2]))*((getHeight()-50-positionY[0])-(getHeight()-50-positionY[2]))) <= 50) {
incrementX[0] = -incrementX[0];
incrementY[0] = -incrementY[0];
incrementX[2] = -incrementX[2];
incrementY[2] = -incrementY[2];
collide.play();
}
repaint();
if (Math.sqrt(((getWidth()-450-positionX[2])-(getWidth()-450-positionX[1]))*((getWidth()-450-positionX[2])-(getWidth()-450-positionX[1])) + ((getHeight()-50-positionY[2])-(getHeight()-450-positionY[1]))*((getHeight()-50-positionY[2])-(getHeight()-450-positionY[1]))) <= 50) {
incrementX[2] = -incrementX[2];
incrementY[2] = -incrementY[2];
incrementX[1] = -incrementX[1];
incrementY[1] = -incrementY[1];
collide.play();
}
repaint();
}
}
}
Simple, stop calling repaint multiple times. (You're calling it multiple times in your while loop).
I try to create a little game in java but I'm in trouble.
When I draw a map, I'm not able to display the characters without overwrite the titlesets of the squares.
My goal is to be able to display many pictures on the same square (like the titleset of the grass, the character and a tree), so I have to deal with the transparency of my pictures (this is not the problem) and the layer (it is the problem).
So how can I display an image on another image?
How can I explain to java that I need to display this image on or under another image?
This is my source code. I don't know is that can help you. Your help can be really helpfull for me if you give me a clue or a function who is able to manage the layers. That is useless to rewrite all the code for me x)
This program is not complete, I use it only for test my program right now. I know that he refresh two times the map so he overwrite the square of the character (and he have many others littles glitchs), but that is not the purpose of my question. I try to done my game by step!
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class Window extends Thread
{
private static JFrame window = new JFrame("game");
public void run()
{
Map map = new Map();
Characters characters = new Characters();
window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
window.setSize(Settings.sizeX, Settings.sizeY);
window.setLocationRelativeTo(null);
window.setResizable(false);
window.setVisible(true);
map.start();
characters.start();
}
private static void reload() throws Exception
{
SwingUtilities.updateComponentTreeUI(window);
}
private static class Map extends Thread
{
private int numberSquareX = Settings.sizeX / 20 + 1;
private int numberSquareY = Settings.sizeY / 20 + 1;
private JLabel square[][] = new JLabel[numberSquareX][numberSquareY];
public void run()
{
for (int x = 0, y = 0; y < numberSquareY; x++)
{
square[x][y] = new JLabel(new ImageIcon("grass_1.png"));
square[x][y].setBounds(x * 20, y * 20, 20, 20);
window.add(square[x][y]);
if (x == numberSquareX - 1)
{
y++;
x = -1;
}
}
square[numberSquareX - 1][numberSquareY - 1] = new JLabel(new ImageIcon("grass_1.png"));
square[numberSquareX - 1][numberSquareY - 1].setBounds(numberSquareX * 20, numberSquareY * 20, 20, 20);
window.add(square[numberSquareX - 1][numberSquareY - 1]);
try
{
reload();
}
catch (Exception e)
{
}
return;
}
}
private class Characters extends Thread
{
private JLabel square[][] = new JLabel[1][1];
public void run()
{
square[0][0] = new JLabel(new ImageIcon("character_1.png"));
square[0][0].setBounds(Test.posX, Test.posX, 20, 20);
window.add(square[0][0]);
try
{
reload();
}
catch (Exception e)
{
}
return;
}
}
}
I have already find this subjects: How to use JLayered Pane to display an image on top of another image? and this one Best practice for creating a composite image output for Java Swing but they haven't really help me...
I continue to search the answer. If I find it, I will come back for post it here.
Solved.
Thanks to MadProgrammer for his comments.
Render the title map to a BufferedImage, either in it's entirety or based on the available viewable area, which ever is more efficient. Paint this to the screen, then paint your character on top it – MadProgrammer
In 15+ years of professional Java/Swing development, I've never found a need to use SwingUtilities.updateComponentTreeUI(window);, instead, simply call repaint on the component which is responsible for renderer the output, I'm pretty sure, you'll find this more efficient. – MadProgrammer
Swing is also a single threaded environment AND is not thread safe, you should NOT be update the UI from outside of the context of the Event Dispatching Thread, as this will setup a race condition and could result in unwanted and difficult to resolve graphical issues. – MadProgrammer
Hint. JLabel is a descendent of Container, which means it can contain other components ;) – MadProgrammer
Thanks a lot MadProgrammer! So I have replace SwingUtilities.updateComponentTreeUI(window) by window.repaint(). You had right for the Thread safe, my map had some bugs but I wasn't able to find where they was from. And what about the BufferedImage? If I create two BufferedImage, the last one can be automatically on the top of the first one? Or I just want to render the title map to a BufferedImage (so I am limited by 2 layers)? – Celine
It will depend on what it is you want to achieve. Using BufferedImages gives you complete control over the placement of the images and yes, one can be rendered over the other, painting is like a artists canvas, as you add things to it, they are added on top of what is already there, BUT, you might find it easier to add a JLabel to another JLabel - just remember, JLabel doesn't have a layout manager by default – MadProgrammer
Code example:
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
public class Window extends Thread
{
private static JFrame window = new JFrame("game");
private int numberSquareX = Settings.sizeX / 20 + 1;
private int numberSquareY = Settings.sizeY / 20 + 1;
private JLabel titlesetLayer1[][] = new JLabel[numberSquareX][numberSquareY];
private JLabel titlesetLayer2[] = new JLabel[1];
private JLabel titlesetLayer3[] = new JLabel[1];
private JLabel titlesetLayer4[] = new JLabel[0];
private JLabel titlesetLayer5[] = new JLabel[0];
private JLabel characters[] = new JLabel[2];
public void run()
{
window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
window.setSize(Settings.sizeX, Settings.sizeY);
window.setLocationRelativeTo(null);
window.setResizable(false);
// draw layer5 (on the layer4)
// draw layer4 (on the layer3)
// draw layer3 (on the characters)
titlesetLayer3[0] = new JLabel(new ImageIcon("tree_1.png"));
titlesetLayer3[0].setBounds(130, 120, 126, 160);
window.add(titlesetLayer3[0]);
// draw the charaters
characters[1] = new JLabel(new ImageIcon("character_1.png"));
characters[1].setBounds(600, 500, 100, 100);
window.add(characters[1]);
characters[0] = new JLabel(new ImageIcon("character_1.png"));
characters[0].setBounds(100, 100, 100, 100);
window.add(characters[0]);
// draw layer2 (under the characters)
titlesetLayer2[0] = new JLabel(new ImageIcon("tree_1.png"));
titlesetLayer2[0].setBounds(570, 400, 126, 160);
window.add(titlesetLayer2[0]);
// draw layer1 (under the layer2)
for (int x = 0, y = 0; y < numberSquareY; x++)
{
titlesetLayer1[x][y] = new JLabel(new ImageIcon("grass_1.png"));
titlesetLayer1[x][y].setBounds(x * 20, y * 20, 20, 20);
window.add(titlesetLayer1[x][y]);
if (x == numberSquareX - 1)
{
y++;
x = -1;
}
}
titlesetLayer1[numberSquareX - 1][numberSquareY - 1] = new JLabel(new ImageIcon("grass_1.png"));
titlesetLayer1[numberSquareX - 1][numberSquareY - 1].setBounds(numberSquareX * 20, numberSquareY * 20, 20, 20);
window.add(titlesetLayer1[numberSquareX - 1][numberSquareY - 1]);
window.setVisible(true);
// window.repaint();
}
}
Screen capture:
1
Another solution is to use JLayeredPane!
JLayeredPane layers = new JLayeredPane();
layers.add(tilesetsUnderCharacter, 0); // Layer 0
layers.add(character, 1); // Layer 1
layers.add(tilesetsOnCharacter, 2); // Layer 2
frame.setContentPane(layers);
Code example:
private void init()
{
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
frame.setSize(Settings.getX(), Settings.getY());
frame.setResizable(false);
frame.setLocationRelativeTo(null);
for (int i = 0; i < y ; i++)
{
for (int j = 0; j < x; j++)
{
for (int k = 0; k < tilesetsOnCharactersSize; k++)
{
tilesetsOnCharacters[i][j][k] = new javax.swing.JLabel(new javax.swing.ImageIcon(Resources.getTileset(Maps.getMapTileset(mapNumber, 1, k, i, j))));
tilesetsOnCharacters[i][j][k].setBounds(j * tilesetX, i * tilesetY, tilesetX, tilesetY);
map.add(tilesetsOnCharacters[i][j][k], 4);
}
for (int k = 0; k < tilesetsUnderCharactersSize; k++)
{
tilesetsUnderCharacters[i][j][k] = new javax.swing.JLabel(new javax.swing.ImageIcon(Resources.getTileset(Maps.getMapTileset(mapNumber, 0, k, i, j))));
tilesetsUnderCharacters[i][j][k].setBounds(j * tilesetX, i * tilesetY, tilesetX, tilesetY);
map.add(tilesetsUnderCharacters[i][j][k], 0);
}
for (int k = 0; k < mapAttributeSize; k++)
{
if (Maps.getMapTileset(mapNumber, 2, k, i, j) == 1)
{
blocked[i][j] = true;
}
}
}
}
for (int i = 0; i < charactersNumber; i++)
{
characters[i] = new Character(0, 0, 64, 64, 0, 0, 0, 0, 5);
tilesetsCharacters[i] = new javax.swing.JLabel(new javax.swing.ImageIcon(Characters.getCharacter(characters[i].getCharacterSkin(), characters[i].getDirection())));
tilesetsCharacters[i].setBounds(characters[i].getX(), characters[i].getY(), characters[i].getSizeX(), characters[i].getSizeY());
map.add(tilesetsCharacters[i], 1);
charactersRender[i] = false;
}
frame.addKeyListener(new java.awt.event.KeyAdapter()
{
#Override
public void keyTyped(java.awt.event.KeyEvent keyEvent)
{
}
#Override
public void keyPressed(java.awt.event.KeyEvent keyEvent)
{
if((keyEventInt = keyEvent.getKeyCode()) == java.awt.event.KeyEvent.VK_F)
{
right = true;
}
else if(keyEventInt == java.awt.event.KeyEvent.VK_S)
{
left = true;
}
else if(keyEventInt == java.awt.event.KeyEvent.VK_E)
{
up = true;
}
else if(keyEventInt == java.awt.event.KeyEvent.VK_D)
{
down = true;
}
}
#Override
public void keyReleased(java.awt.event.KeyEvent keyEvent)
{
if((keyEventInt = keyEvent.getKeyCode()) == java.awt.event.KeyEvent.VK_F)
{
right = false;
}
else if(keyEventInt == java.awt.event.KeyEvent.VK_S)
{
left = false;
}
else if(keyEventInt == java.awt.event.KeyEvent.VK_E)
{
up = false;
}
else if(keyEventInt == java.awt.event.KeyEvent.VK_D)
{
down = false;
}
}
});
frame.setContentPane(map);
frame.setVisible(true);
}
private void update()
{
if (exit && characters[0].getX() < x * tilesetX - characters[0].getSizeX() - characters[0].getMovementSpeed() && characters[0].getX() > 0 && characters[0].getY() > 0 && characters[0].getY() < y * tilesetY - characters[0].getSizeY() - characters[0].getMovementSpeed())
{
exit = false;
}
if (right && (exit || (characters[0].getX() < x * tilesetX - characters[0].getSizeX() - characters[0].getMovementSpeed() && !blocked[characters[0].getY() / tilesetY][(characters[0].getX() + characters[0].getSizeX() + characters[0].getMovementSpeed()) / tilesetX] && !blocked[(characters[0].getY() + characters[0].getSizeY()) / tilesetY][(characters[0].getX() + characters[0].getSizeX() + characters[0].getMovementSpeed()) / tilesetX])))
{
characters[0].right();
characters[0].setScaleX(5);
if (allowExitRight && characters[0].getX() > x * tilesetX - characters[0].getSizeX() - characters[0].getMovementSpeed() - 1)
exit = true;
charactersRender[0] = true;
}
if (left && (exit || (characters[0].getX() > 0 && !blocked[characters[0].getY() / tilesetY][(characters[0].getX() - characters[0].getMovementSpeed()) / tilesetX] && !blocked[(characters[0].getY() + characters[0].getSizeY()) / tilesetY][(characters[0].getX() - characters[0].getMovementSpeed()) / tilesetX])))
{
characters[0].left();
characters[0].setScaleX(-3);
if (allowExitLeft && characters[0].getX() <= 0)
exit = true;
charactersRender[0] = true;
}
if (jumped || up && (exit || (characters[0].getY() > 0 && !blocked[(characters[0].getY() - characters[0].getMovementSpeed()) / tilesetY][characters[0].getX() / tilesetX] && !blocked[(characters[0].getY() - characters[0].getMovementSpeed()) / tilesetY][(characters[0].getX() + characters[0].getSizeX()) / tilesetX])))
{
if (!jump)
{
characters[0].up();
characters[0].setScaleY(-3);
if (allowExitUp && characters[0].getY() <= 0)
exit = true;
charactersRender[0] = true;
}
else if (!jumped && !falling)
{
jumpCurrentDuration = jumpDuration;
jumped = true;
}
else if (--jumpCurrentDuration > 0)
{
if (exit || (characters[0].getY() > 0 && !blocked[(characters[0].getY() - characters[0].getMovementSpeed()) / tilesetY][characters[0].getX() / tilesetX] && !blocked[(characters[0].getY() - characters[0].getMovementSpeed()) / tilesetY][(characters[0].getX() + characters[0].getSizeX()) / tilesetX]))
{
characters[0].up();
characters[0].setScaleY(-3);
if (allowExitUp && characters[0].getY() <= 0)
exit = true;
charactersRender[0] = true;
}
}
else
{
jumped = false;
}
}
if (((down && !jumped) || (gravity && !jumped)) && (exit || (characters[0].getY() < y * tilesetY - characters[0].getSizeY() - characters[0].getMovementSpeed() && !blocked[(characters[0].getY() + characters[0].getSizeY() + characters[0].getMovementSpeed()) / tilesetX][characters[0].getX() / tilesetX] && !blocked[(characters[0].getY() + characters[0].getSizeY() + characters[0].getMovementSpeed()) / tilesetY][(characters[0].getX() + characters[0].getSizeX()) / tilesetX])))
{
characters[0].down();
characters[0].setScaleY(5);
if (allowExitDown && characters[0].getY() > y * tilesetY - characters[0].getSizeY() - characters[0].getMovementSpeed())
exit = true;
if (jump)
falling = true;
charactersRender[0] = true;
}
else if (jump)
falling = false;
}
private void render()
{
for (int i = 0; i < charactersNumber; i++)
{
if (charactersRender[i])
{
tilesetsCharacters[i].setIcon(new javax.swing.ImageIcon(Characters.getCharacter(characters[i].getCharacterSkin(), characters[i].getDirection())));
tilesetsCharacters[i].setBounds(characters[i].getX() + characters[i].getScaleX(), characters[i].getY() + characters[i].getScaleY(), characters[i].getSizeX(), characters[i].getSizeY());
charactersRender[i] = false;
}
}
}
Screen Capture:
Edit: I also found a library called Slick2D who work with TiledMapEditor:
http://slick.ninjacave.com/
http://www.mapeditor.org/
How to setup Slick2D: How to install Slick2d?
How to use Slick2D and TiledMapEditor: Slick2D + Tiled cant load map
Where started: https://thejavablog.wordpress.com/2008/06/08/using-slick-2d-to-write-a-game/