• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Tiled Based Map Game in Java

 
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello everyone

I'm trying to create a tile based map JPanel but all I get is a white screen. I'm fairly new to the Java Swing and AWT package so I've been watching tutorials on YouTube so learn as much as I can. I honestly don't know where I'm going wrong with this so I would appreciate any help or suggestions.

I've got three classes: Window.java which includes the Main method, Panel.java which is the JPanel and Tile.java to draw all the images into an array.

Window.java:


Panel.java:


Tile.java


I've checked through everything and still cannot find what I'm doing wrong. I did try different codes but I just got errors instead. Help!

Thank you very much!
 
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Cathy,

impressive code, but I have a remark and a question.

Question: where do you issue: 'startGame()'?

Remark: you are using some very nasty code here. You draw
directly to the graphics environment of your panel, while the
correct way of doing this is to override the 'paintComponent(Graphics g)' method,
in which you would do all the drawings. Then, in your 'run' method, all you need
to do is to determine the new state of your game, and then issue a 'repaint()'
command.

Can you explain why you did it this way?

Greetz,
Piet

Oops: completely forgot: welcome to the ranch!
 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Piet,

Thank you for your reply!

Ah right I need to run the startGame() method, so would I do this in the Panel constructor by typing startGame()?

Like this:

public Panel(){

setPreferredSize(dim);
setBackground(Color.black);
setFocusable(true); // Focus on JPanel to receive key events
requestFocus();

tile = new Tile();
startGame();

}

Also I had no idea this was a bad way of drawings graphics, I apologise for by naivete, I have been watching tutorials which mostly show to create a update/tick and render methods in the run method.

So you're saying I should override the paintComponent(Graphics g) method, define what I want to do then call it in the run method? And then call the repaint() method?

Thank you for your reply!
 
Bartender
Posts: 3323
86
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome to the Ranch.

May I suggest you read this tutorial on how to perform custom drawing in Swing
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Cathy,

well, issuing the startGame() command in your panel constructor might not be a good idea.
Chances are that your thread will start issuing the updates while maybe the window construction
is not yet finished. I would issue 'startGame()' in the window constructor, after 'pack()' and
'setVisible(true'). (but that would involve making that method non-private, say public).

Try it, and see what you get on your screen.

Tony gave you a link towards the tutorial on how to paint to panels in Swing. You must certainly give it
a thorough read.

Success!

Greetz,
Piet
 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you Tony, thank you Piet!

I'm working through the link now

 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi guys,

So I've done what you suggested and I must say my Panel class makes much more sense to me so thank you very much for that.

The only problem I have now is that I don't know how to draw a tile map on my Panel. I've searched for more tutorials and everyone seems to be using tick and render methods instead of paintComponent. I can't find anything where arrays or rectangles are used. I don't really know how to approach this because ideally I want the player to move from tile to another.

Here's what the code looks like now:

Window.java


Panel.java


I've also attached what the Window looks like.

Many thanks!
Tile.jpg
[Thumbnail for Tile.jpg]
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Cathy,

well, in fact you already have most of your drawing code, in your original listing.

What I think should happen now is:

1) your run() method should perform the update(). Although currently this method
does nothing, I assume you will make it change some variables, so that your drawings
will show some change

2) then this run() method should call 'repaint()'.

3) 'repaint()' will cause that 'paintComponent(Graphics g)' is invoked

4) now, paintComponent first calls 'render' (you must put this method in paintComponent).
This method creates an image, for which you obtain a Graphics g (dbGraphics).
Then you call 'draw(dbGraphics)', which will make your tiles to be drawn to this dbGraphics,
('tile.draw(dbGrapics)')
So in effect you draw your tiles to the image 'dbImage'.

Still with me?

5) So far, all drawings have been in the dbImage, so it is time to put this dbImage
to the panel! And that's being done in the paintScreen method.

6) if you look at paintScreen, you see that it gets its graphics by calling 'this.getGraphics()'.
This is fine, but this graphics is already available, since it is delivered to you by the
system, when that system called your 'paintComponent(Graphics g)', and it is to this
g that we will paint the dbImage.

Well, you may think this is all quite involved, but hey, you wrote this yourself!

So, concluding:

1) in run(): update() and 'repaint()

2) in your paintComponent(Graphics g):
- render() // which will call tile.draw(dbGraphics)
- paintScreen(g)

But I give no warranty: I may have missed one or two (or many more) issues. I hope that
you see how you could get it all to work.

You may have some other issues, like the speed of the thread issuing repaint() commands,
but that's for later.

Greetz,
Piet
 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi

I basically realised I am approaching this all wrong!! I'm trying to create a grid of tiles, for now it's 25 by 25. But these tiles don't need images on them. I want a player to move one tile to another, rather than pixel by pixel. I want it to hop from one tile to the next. And then I want to be able to get which tile the player has landed on.

For example, say I've got a 10 by 10 tile grid, the player starts off on the first tile which is in the top left hand corner. Then I move the player left by 6 and down by 4. The player should be on tile 47 now. I want to be able to get this information, that the player is on tile 47.

What's the best way to do this? I was thinking of using an array of rectangles. But I read something about using JLabels instead.

Any ideas are appreciated!

Many thanks!


 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Cathy,

there are many ways to achieve the thing you want, but to give you an idea of what's possible,
this is what I did in my chess program.

First of all: yes, I use JLabels, since a JLabel has some very pleasant properties:
- you can make them transparent, so you can let them easily "disappear" when needed
- you can easily put (or remove) an icon on them, and a border
- redrawing is automatic
- you can easily set the background color

So, I decided to use a special JLabel, like this:

You see, I added a row and a column as extra information, and I also add an
ActionListener. The idea is that whenever such a label is clicked upon,
then, in the actionlistener code, all I have to do is:

In effect, I only need just one action listener.

Panel
Then, I created a JPanel, with a GridLayout(8,8), and put all my JLabels
in with:

(the parameter 'al' is the actionlistener I talked about, and which I created
before).

So, panel is okay, labels are okay, with the actionlistener in place, add this panel
to your JFrame. You do not need to override 'paintComponent()' for your panel,
unless you want to draw other things in it.

And then it is up to you to decide how your game should go, what to do
with mouseclicks, keeping all the administrations about players, et cetera.

As I said, this is only one of the many possibilities.

Greetz,
Piet
 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi!

Thank you so much for your suggesting!! I used JLabels to create a grid layout and it works, it's exactly what I wanted.

I went away and I've gotten quite a bit done. I've got several classes, method, layouts and buttons etc.

But I have a new dilemma now! I am using a Grid Layout full of JLabels. Now the Grid Layout automatically resizes the cells to try to get all the cells to show up on screen, it tries to accommodate all cells, so no cells are dropped off. However I need a grid which is 100 cells by 100. I created a test grid of this size and it's HUGE. It takes up the entire screen. That's inconvenient. Therefore I have opted for a scroll pane. So I've got a JPanel with Grid Layout. I added this JPanel to a JScrollPane. The only problem is that the grid still resizes itself and the scroll pane is useless to me. How do I get it not to do that?

Also how can I set up a JViewport so that the JScrollPane only shows 30 rows by 30 columns at a time?

I've attaches screenshots of what a 30 by 30 looks like and what a 100 by 100 grid looks like so you can understand why I need the JScrollPane and a JViewport.

I hope I'm making sense.

Many thanks!!



30by30.jpg
[Thumbnail for 30by30.jpg]
100by100.jpg
[Thumbnail for 100by100.jpg]
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Cathy,

well, that certainly looks impressive.

To rectify the size problem of the JScrollPane, there are several things you can do.
I have a demo code below, in which I have a special label class, that sets its
minimum, preferred and maximum size to some dimension given.

Now, if you look at the code, you can see two lines that will determine the size
of your viewport.

First (see line 67) I give a preferred size to the content pane.
Then, see line 64, I give the scroll pane a preferred size.

As you see, I've commented out both lines. If you run this code,
you get a frame that does not even fit on my two screens!

Remove the comments from line 67, and run again. You see that you now get the behaviour
that you want.

You can also remove the comments from line 64. Run it, and you see you get the same behaviour.

So, these are two ways to achieve what you want. However....

I have a problem with this code, and I'm not sure what's causing it. It could
be devastating for your game.

If you click on one of the labels, and if you look at the console of your ide
(or the commandline if you run it from the command line), you see that EACH
click is reported TWICE. It looks like the label recieves twice a mouse pressed
(and released and clicked). As said, I don't yet know what's causing this.

If I have time, I'll find it out, but maybe some of the SWING guru's around know
what's happening here.

In the meantime, enjoy your game!

Greetz,
Piet
 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Omg, thank you SO much! That's exactly what I've been trying to achieve. Honestly, you've no idea how much I appreciate this, thank you!

I'm just going to add the code to my existing code and I'll let you know how I get on. Fingers crossed
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Cathy,

you're welcome, I'm very glad I could help!

About these double mouse clicks I was reporting: hmmm, I looked through the documentation
of JScrollPane, JViewport, MouseListener to see if had missed something. Nothing. Then
I googled for this error: nothing again. Then ran that same program on my wife's laptop
downstairs: no double clicks! So I start to suspect my pc's mouse... it happens that when I
click in the titlebar of a window, it then resizes to full screen, just like I had double clicked it.

Anyway: if you notice these double clicks too, could you let me know? Thanks!

Greetings,
Piet
 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Piet,

The scrollpane works, it's exactly what I was looking for thank you!

I was hoping you could help me with something else please.

So you've seen what my 100 by 100 grid of labels looks like. Let me explain how I created that. I've got a class. It's got method. I've got a method which creates and populates an array of Strings. Next method creates an array of labels and then adds the String (created from previous method) to the labels using the setText() method. Method after that takes those JLabels and adds them to a JPanel of Grid Layout. Then I've added the JPanel to a scrollpane, the scollpane gets added to another JPanel with an empty border and this final JPanel gets added to the JFrame. So that's how I've created the grid and I'm happy with that, I don't want to change it.

My only issue is that I am unable to amend the image of the JLabels from the main method. I can do this from the method which creates and populate the JLabels, I can do it from the method which creates the grid, but I cannot change the image of a JLabel from the main method. I've tried to create a new method for this and call it in the main method - nothing. I've also tried to change it from a button's ActionListener - nothing again. I know it's possible and I know I've missed something really obvious.

Please could you help with this? Below is the code, if you run it and click on the button you'll notice nothing happens. However the strangest thing is that I can change the background colour of the JLabels from almost anywhere.




Sorry about the messy unorganised code!

Thank you!
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Cathy,

indeed, the code is a bit messy, but hey, writing beautiful organized code is something that takes time
to develop.

Yes, you can change the images of your labels, even from within the main method. And that's because
you store all your labels in a static array, see line 119, where you have

Since this array is static, it is visible from anywhere in your class, so also from the main method.
If you look at your code in lines 59-65, you see that you create your labels, and put the references
in this static label-array.

Suppose you want to change the image of a label when you click on the button that you put
in the BorderLayout.North of the main panel. Now, if you look at the code of the ActionListener, in
lines 148-159, you see that you change the background color of label[1][1] to RED, and so you
see it changing to RED. So far, so good. Then, in line 153, you create a new JLabel, with
some fresh icon on it. But you do not add this new label to your tiles-panel! This adding to
the tiles-panel is only done in the method 'Grid' at line 73.

Now, changing the image of label[2][1] is actually very easy. Just use this piece of code:

that's all! Just like you changed the background color of label[1][1].

In the ActionListener code, you call 'setImage', and that changes the image of label2][2].
All that method does is creating a new label, with a reference put into label[2][2], but again,
this does not put that new label to your grid-panel! See the foregoing paragraph.

If you look at the code of 'setImage', you see that you also issue

in line 108. Any idea why you would do such a thing, since in your main-routine you
create the only ArraysGrid that you need.

Well, you see that it is easy to change the images of your labels, even from within 'main'.

Greetz,
Piet
 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks Piet!! That piece of code worked, I cannot believe I didn't see this earlier

Forgive my ignorance.

I have a question for you, not too sure if this is possible to be honest.

But one of my JLabels from the Grid will contain an image. That image is supposed to show me where the character in the program is. I use a JLabal so I can get the position. So basically when I want to move the character, I remove the image from the current JLabel and add it onto the next JLabel. I understand this is possibly the worst approach ever but I am new, all I know is Java and I've got a deadline and didn't think to learn Game Development in Java.

Anyway, since I'm using a JScrollPane, I would like the program to automatically scroll when the JLabel with the image cannot be seen anymore. Therefore as the character is moving, the JSCrollPane is scrolling, so I don't have to scroll to it. It does it for me. So like a camera watching where it's going.

Is this possible?

Thank you very much!!
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Cathy,

yes that is certainly possible, but I have no actual experience in this autoscrolling of a JScrollPane.

Look at the API documentation of the JViewport (click here: http://docs.oracle.com/javase/7/docs/api/)
And look for JScrollPane and JViewport.

In the JViewport class, you see the method 'public void scrollRectToVisible(Rectangle contentRect)'
and I think it is this one that you should invoke.

Since you know in what label your image is, and you also know the size of your label (I assume it
to be the size of your icons) and the size of the grid panel, you must calculate the coordinates of the rectangle
that you wish to be displayed, taking the size of the JViewport (700 by 700, if I recall correctly) into account.

As I said, I have never done this myself, so I have no experience to this. But I would certainly give it
a shot.

Greetz,
Piet
 
Tony Docherty
Bartender
Posts: 3323
86
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Piet Souris wrote:If I have time, I'll find it out, but maybe some of the SWING guru's around know what's happening here.


This is probably too late to be of any use but it's because you are adding the MouseListener twice to each CathyLabel

Since you know in what label your image is, and you also know the size of your label (I assume it
to be the size of your icons) and the size of the grid panel, you must calculate the coordinates of the rectangle
that you wish to be displayed, taking the size of the JViewport (700 by 700, if I recall correctly) into account.


If you know which JLabel object you want to ensure is displayed you can query the object to get it's location and size and then calculate the visible rectangle relative to those values.
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
@Tony,

pfff... you just saved me from buying a new mouse!

hi Cathy.

I had little time, so I couldn't respond earlier.
I just typed in a small demo, to see how autoscrolling could be set to work. There are probably
some smarter ways to do it, but nevertheless I tried to program as simple as I could.

Just have a look at the code. It shows some labels in a scroll pane, with a special label
colored white. Every one second a timer fires, and in the ActionListener code I randomly
put the white color to some other label. After that, I calculate the origin of a rectangle.
That rectangle is just big enough to cover the whole viewport of the scrollpanel, and
the origin of that rectangle (i.e. the left upper point) is chosen such that the white label
stays in the centre of the view as much as possible.

The automatic scrolling is jumpy, for two reasons:

- the timer fires in intervals of one second
- the unit of motion is the size of a label

Of course, you can have a much smoother scrolling, when you decide to let the
origin of the rectangle change a few pixels at a time. However, it is then not always
possible to keep the white label in the centre.

Just give the code a look. You can experiment and change as much as you like, and
fit the useable parts into your own code.

Have I just one question left:
how do you see the role of the scroll bars, with respect to this autoscrolling?
If you scroll the panel via the scroll bars, at the moment the timer fires, the panel
scrolls back again.

Greetz,
Piet

PS: click on a fixed position in the scroll panel. You will see the label coordinates
displayed and changing, as a result of the mouse listener that I added to each label.
 
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Cathy,

I've seen in some of your postings, that you say that you've been watching videos on YouTube to learn how to do some of this stuff. Could you tell me whose videos you have been watching?

Hi All,

Could you guys tell me what some of your favorite sources are to be learning Java? The problem that I am having is not so much the basic stuff, but rather knowing how to organize my program, ie, how to know which stuff to put in the Window.java, like Cathy's up above, which stuff to put in the View.java and which stuff to put in the Tile.java.

Thanks
Ed
 
Marshal
Posts: 79177
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome to the Ranch

Some videos on YouTube are good and some are really bad. You should not try to copy somebody else's class structure or anything like that. You should start by producing small GUIs and only try something larger when you have more practice.
 
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Just out of interest, what speed is the app running at - a lot of labels being used there. I'd be optimising the scrolling so only labels
you can see are actually rendered.

Regards,
Steve
 
Cathy McDuff
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi All,

I'm sorry for being absent for so long!

Piet, I can't thank you enough for your help, your code is really useful to play around with and experiment so thank you.

I also appreciate everyone for reading and commenting.

Hi Ed, below is a link to some of the Java playlists I benefited from, I hope they helps you too:

https://www.youtube.com/playlist?list=PLFE2CE09D83EE3E28 - perfect for beginners, simple and straightforward.
https://www.youtube.com/playlist?list=PL6E90696571998DC2 - this guy knows what he's talking about, I find his tutorials full of information.
https://www.youtube.com/playlist?list=PL2B0D071533E7D993 - another great playlist for beginners.

Hi Campbell, thank you and yes you're absolutely right, writing your own code is much better than using someone else's!

Hi Stevey, using a grid of labels wasn't working for me, so I've changed my approach. I'm using the paintComponent method instead to draw a grid of Rectangles and draw a BufferedImage and it's much better than using labels. Less hassle. I say that but I'm already having issues with AffineTransform lol

Thank you all
 
And then the flying monkeys attacked. My only defense was this tiny ad:
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic