It's not a secret anymore!*
The moose likes Game Development and the fly likes An Enum with arrays in it, for holding area data Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Game Development
Bookmark "An Enum with arrays in it, for holding area data" Watch "An Enum with arrays in it, for holding area data" New topic
Author

An Enum with arrays in it, for holding area data

Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
I've used an enum to hold all the data for my monster types and it works quite nicely.

I thought i'd also be able to use this method to hold the data I require for my areas but can't get the arrays to work properly.

Here's what my creatures enum looks like:

And this is what I want my area enum to look like, in a very simple form (there will be a lot more data types in the end)

(Also, I don't think I need that constructor in the enum. I first wrote this a wile ago, not sure why I thought I need it anymore.)
Then, like I have done with my creatures, Iwill have a constructor in my Area Class which will receive the AreaType as the only input and instantiate the area. Methods will then allow me to get the exits and exitNames and use those values when asking the player where they want to go. The actual exit parameter is an AreaType so that the next area can be instantiated in the same way, after receiving that chosen exit AreaType as input.

I'm also not sure if I should be using {} or [] around my array contents...

I'm getting a lot of error messages off the first line of my enum: constructor cannot be applied to given types, illegal start of expression, illegal start of type...
Darryl Burke
Bartender

Joined: May 03, 2008
Posts: 4523
    
    5

Richard Henderson wrote:I'm also not sure if I should be using {} or [] around my array contents...

I'm getting a lot of error messages off the first line of my enum: constructor cannot be applied to given types, illegal start of expression, illegal start of type...


First, when seeking help with any error or exception, post the entire error text or exception stack trace. That helps to pinpoint the cause.

An array initializer is enclosed in braces {...} not brackets [...]. However, except when part of a declaration-cum-assignment statement, you need to tell the compiler whet type of array you are initializing.

edit {SECOND, TURNBACK} will also need a new Something[] ahead of it.


luck, db
There are no new questions, but there may be new answers.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
OK, so I've got:

and i'm getting these errors:
constructor AreaType in enum goblincave.AreaType cannot be applied to given types;
required: java.lang.String,java.lang.String[],java.lang.String[]
found: java.lang.goblincave.AreaType[],java.lang.String[]
reason: actual argument goblincave.AreaType[] cannot be converted to java.lang.String[] by method invocation conversion

illegal forward reference

cannot find symbol
symbol: variable LEAVE
location: class goblincave.ArreaType
Darryl Burke
Bartender

Joined: May 03, 2008
Posts: 4523
    
    5

It's time you need to post a SSCCE (<- link) so we can see what's wrong.

However, an illegal forward reference happens when you try to access a variable earlier than it has been declared. You probably need to move the declaration of LEAVE higher up in the source code.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
I wanted to use only a few locations, initially, so I could move on to checking that my game loop would run correctly.

They're all essentially place holders and i'm not sure it fits the brief for SSCCE but here it is:
By putting LEAVE in front of INTRO the "cannot find symbol" error now can't find SQUARE. It seems I may have to list each of my areas in reverse, so that each area has already been declared before something else refers to it. That might mean I have to put in some extra areas so that no references overlap in the wrong way.
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2271
    
  28

Your constructor is taking 3 parameters, a string and 2 string arrays. However, you are calling it with a string, an area type array and a string array. The arguments don't match. The compiler error message is actually tell you this. You just need to parse it out a bit.

What you are doing here doesn't seem to me to be a good use of enums. Enums are supposed to be straightforward constants and not meant to be connected to each other. You could do it the way you are doing. It's just not a good way of doing it. Yon probably should be using immutable classes instead of enum.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
Ok, I reversed the listing and it's not throwing errors now:
Shame I didn't try this a few hours ago before the day was gone.

Edit: I missed your reply. I realised I had messed around with that constructor trying to make things work, and changed it back just before posting the above code.
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2271
    
  28

Won't you need to put exits in both directions. Area1 will have an exit to area2 and area2 will have an exit to area1. Rooms in games are generally undirected graphs. You are able to build only directed graphs.

Again I strongly suggest not to use enums to represent your rooms. It's bad design.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
If I was using an immutable class (or would it be a series of classes?) how would that work, in a nutshell?

I think what I was trying to do with the two String[] in the constructor was to replace the AreaType[] in the enum so avoid that interconnectedness. I need each area to say which other areas it leads to, in order for the player to navigate. If I had those areas listed as Strings, but in ALLCAPS, would I be able to use them as input for a method that wanted a reference to an AreaType? Maybe by casting, somehow...
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
Yes, they should need to have exits in both directions. I was misleading myself with these entries because the beginning of the story is a short railroad before the options become available.

So immutable classes are the better why to do this? Is that one class per area or an instance per area?
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2271
    
  28

Well, simply put an immutable class is a Java class that encapsulates properties and has only getter methods, no setter methods. The constructor initializes all the properties. Once created the immutable never changes. Conceptually, an enum is an immutable, but enum is not the only way to create an immutable. You can create an immutable by just creating a java class with only getter methods

Generally, when you are creating a graph of immutable, you use a factory to create the graph. Basically, the factory is a method whose main responsibility is to create an initialize other objects. In your case you can have an area factory that returns an array of areas. Inside the factory method you can create the areas one by one and connect them to each other.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
I can figure out how to do that with the help of google. What I wonder is how to record the differences there will be between each area though.

Each area obviously has a different description string but also different mob types and size and various other stuff. Does all this get stored in a multi dimensional Object[][]?
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2271
    
  28

Well depends.. You will have some mobs that can change areas, while some mobs will be stationary, right? So. The question how you want to model it and how you want to use it. You can have an area hold a list of mobs. But when a mob moves, you will have to take it out of the list of one area, and put it in list of another area. Alternatively, you can have the mob have a reference to the area that it is currently in. This makes it easier to move the mob, but it makes it difficult to find all the mobs in one area.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
Having mobile mobs is too sophisticated for me at the moment, though i'd love to have it in a later version. So for now, everything stays in the place it's first put.

After sleeping on this it now makes a lot of sense. I will have a large 2D array (which could even have arrays at some indices) and all the getting methods take the area number as an argument then pull the information from the array.

Will it be a problem having a static array or will all the methods have to be static too? If the methods are static will I be able to make a non static object with them, or call them from a non static object instance?
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2271
    
  28

I don't understand what do you mean by static functions. I would put the "State" of the areas apart from the business logic of the game. The Area class should encapsulate all the information about the area and provide methods to get the information. For now your Area is immutable because nothing in the Area ever changes, however in the future you might have some parts of the Area that are not mutable(exits, fixed mobs, etc), while some are mutable(moving mobs, weather, day/night, loot, etc). SO, you need to have a sense of what you will do to add mutability, even if you don't do it right now.

I would put the business logic of the game outside. Now, you need to put some sort of data structure that allows you the business logic to access the areas. This means it could be that you have an array of Areas, or you could have a graph or a Map. The design of this holding data structure depends on what you want to do in the business logic

You might have to think about what you want to do with the Areas before you start designing the data structure. You can't build the data structure in isolation. You will have to do the app design and data structure together. It's a good idea to do it iteratively if you want to take small bites.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
For static/non static I meant how you can label a member Static, so that it is accessible without having to instantiate an instance of the class.

Having thought about it, I don't think I will have to make any instances at all.

The Areas class will consist of an Object array with all the details of each area, and a bunch of methods which return various objects from that array.

The game logic will consist of a loop which will call, first, the description thread of the new area, then check some Booleans to see if mobs or traps are present, etc. Each step of the loop will call the next appropriate method and mostly display info to the player. At the end of the loop the player can choose the next area they will move to.

I realised that wondering mobs might not be too tricky either. I'd have to instantiate the mob at some point, maybe triggered by a player action, then the mob would record it's location and have a method for (maybe) choosing a new location each time the loop runs. I could even include a bit of code that checks to see if the player and mob cross paths by going to the area the other was in, and then have an encounter in one of those areas.

I already have a pretty fair idea of what the loop, methods and areas class have to do. I'll use 3 or 4 areas with only a few parameters to start with and get the loop working.
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2271
    
  28

To begin with you will need instances of Area and an instance of a data structure that holds the Areas. Yes, you could put all your game logic in your main method.

Although, as you add different types of mobs, you will find it onerous to put all the logic in the main method. At some point, you will have to start thinking about how to modularize your game logic. A good way to do this will to put all the logic for a particular kind of mob in its own class. In this case, you will need to start thinking about holding instances of those mobs somehow.

Anyways, I'm just looking couple of steps ahead. You are fine with what you have for the very limited set of requirements that you are focusing on. Just keep in mind that as you keep enhancing your game, you might start making your code complex, and at some point you will have to change your existing code to make it simpler.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
My game logic is not all in the main method. The main method creates an instance of Player, one of GUIWindow (and sets it to visible, etc.), an instance of Areas and an instance of CaveController. The game logic is in the last one. Then it calls the playGame() method from caveController and that takes over. Is that what you meant?

I'm not making an instance of the data structure, I've included that as part of Areas. Should it be separate? An AreaData class, maybe?

I found an issue with creating monster instances though (it might be a separate topic). When the playGame loop checks the hasMob Boolean to see if there are enemies, it creates a fight instance if it returns true. That receives the player object and creature type and quantity as parameters. Then fight() creates monster instances. I can't figure out how to tell the creature constructor, which takes an enum as an argument, to take the creature enum from the argument list that was sent to the fight() method.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7492
    
  18

Richard Henderson wrote:I've used an enum to hold all the data for my monster types and it works quite nicely.
I thought i'd also be able to use this method to hold the data I require for my areas but can't get the arrays to work properly.

I'm afraid I've only given the thread a cursory glance, so forgive me if this has already been answered; but I noticed that you appear to want to change things in your areas; and that doesn't compute with the use of enums.

Enums are NOT objects in the normal sense, they are values - more specifically, constants; and furthermore, singletons - so if you start mucking about with the internals of an enum during process, you're probably asking for trouble. And I suspect that this is why they lend themselves to 'monsters' and not 'areas'.

That doesn't mean that you couldn't use them to initialize an Area object though.

HIH

Winston

Isn't it funny how there's always time and money enough to do it WRONG?
Articles by Winston can be found here
Piter Smith
Ranch Hand

Joined: Feb 25, 2009
Posts: 31
In one of your replies, you wrote that you might not ahve any instances at all.

why would you not want any instances at all? In OOP, it's objects which matter -- those are your instances.

when you write that:

"Areas class will consist of an Object array " that's a good start. Why not take it further with:

class Areas

private List<Area> someAreas = new ArrayList<>();


so that instead of dealing with an array (ugh) use List? Notice that it's not List<Object> but List<Area> because you know for a fact that it's not just some random object, but a specific type of Object, an Object which implements Area, which gets added to your list of areas. Yes, you then need an interface Area, but that will pay off later. You can't accidentally add something to your list of Areas which is of the wrong type, and whenever you pull something out of your collection, or iterate it, you can depend on knowing what sort of objects are there -- their type, or interface.

As to wandering mobs, here you might want to think about has-a (composition). What's the relationship between an Area object and a Monster object? Probably, an Area has-a Monster. Or, more likely, an Area has-a List<Monster>. An area has a collection of monster objects.

When a monster moves from one area to another your controller needs to handle that. How? by removing the monster or mob from the monster collection for one room, and then adding it to another:

Area a1 = new Area();
Orc friendlyOrc = new Orc();
a1.add(friendlyOrc);
...
..
Area a2 = new Area();
a1.remove(friendlyOrc);
a2.add(friendlyOrc);

thus, your orc wandered from a1 to a2. Of course, your areas will will probably not be a1, a2, a3, because that would get very difficult past three rooms. No, don't use an array -- use a collection! So, in your Areas object, it holds a collection of Area objects. Each Area object holds a collection of Mob's.

In your Areas class you would probably have a moveMob method.


Hope that helps.
Richard Henderson
Ranch Hand

Joined: Feb 18, 2013
Posts: 42
Piter, Winston, thank you for the replies. Sorry I haven't replied before now but my laptop has stopped working and I haven't been doing any coding for the last few weeks.

Anyway, I think I'll ditch the Enum idea for the area data table and go to a multi dimensional array.

I'll be returning to the code once I've got a working computer again and will be back in here trying to figure out what I should be doing.

Cheers.
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: An Enum with arrays in it, for holding area data
 
Similar Threads
An object to hold several arrays
Interface and using Polymorphism (I think?) -- Game I'm making and need help.
Help with an array situation
MVC for text adventure: working out how the classes interact
Enum or int