Selecting Objects from an ArrayList using Keyboard Input - java

thanks for coming by. I have been working on a game inventory system, its been working awesome when I pick items from the world and then they get added into the list and displayed inside an inventory box when I hit "I", but now I want to be able to interact with them using the arrow keys and the ENTER key, every item has a method called "use" in which it executes an action, (Ex: HP potion, increases player health) now I want to be able to select items from the list and when I hit enter that the selected item's method "use" is actually used, I've got the input handling covered, I only wish to know how to access the objects inside the arraylist depending on the selected choice.
So far I got:
private int currentChoice=0;//the value is the index position within the
//array, so 0 would mean I selected an object
//at index 0.
private ArrayList<Item> playerItems;//This is the array in which I store
//the player's items.
private boolean inventoryDisplayed;//This is used when I click "I" then the
//the arrow keys stop moving the player
//and should now be used to interact with
//the items inside the inventory.
If you guys could help me that would brighten my week, seriously, this project is very important to me, any help is very appreciated, thanks for taking your time to help a fellow member from stackOverflow, may good fortune shine on your life, have a big choco cookie just for reading up 'till here. :)

Basically you can get the element at a specific position in a list by using
list.get(index);
or in your case
playerItems.get(currentChoice);

First thing, define playerItems as private List<Item> playerItems; and then instantiate it as playerItems = new ArrayList<Item>();. This is one of the core principles of well designed code, particularly if you need to change playerItems to a LinkedList later on.
You'll need to add a KeyListener or KeyAdapter to the appropriate component when the 'i' character is typed. Then, implement the keyTyped (or maybe the keyPressed) method as follows:
#Override
public void keyTyped(KeyEvent e)
{
switch(e.getKeyChar())
{
case KeyEvent.VK_LEFT:
if(--currentChoice < 0)
currentChoice = playerItems.size() - 1;
break;
case KeyEvent.VK_RIGHT:
if(++currentChoice >= playerItems.size())
currentChoice = 0;
break;
}
}
Then you can retrieve the appropriate item with: playerItems.get(currentChoice);

Related

ActionListener and dynamic(?) GUI

I've read through a dozen or so actionlistener/loop related questions here, but I'm not sure I've found my answer. I started on my first large Java project, a text RPG that's spiraled into around 5K lines of logic and game features which was functioning as intended using just the console - when I decided I'd try to build a Java swing GUI for it instead. Here's my problem:
I use a Room object which handles the description of where the player is at and also has an array of options for the player to choose next which it creates dynamically based on what cell the room's id is in on a csv file and what is beside it. I stopped outputting this to the console and instead started creating JButtons based on the options array like so:
public void showNarrate(){
add(dd,gridConstraints);
optionCopy.clear();
int i = 0;
for(JButton j : optionButtons){
//adding and formatting buttons to gridBagConstraint I also set actionCommand for each button to the triggerValue (ID of the next room which the button should take the player to)
}
//I tried using a copy of my JButton array here so I could have something to iterate over in actionListener after clearing out the original
//(Since it needs to be cleared so the next Room's buttons can be built after the player chooses an option)
for(JButton j : optionButtons){
optionCopy.add(j);
}
optionButtons.clear();
//dd is a seperate drawingComponent I used for outputting room descriptions which may be totally unnecessary at this point :/
dd.repaint();
setVisible(true);
}
Over in actionlistener (Same class) this is how I tried to swing it:
for(JButton j : optionCopy){
if(e.getActionCommand().equals(j.getActionCommand())){
Main.saveRoom = Main.currentRoom;
Main.currentRoom = j.getActionCommand();
System.out.println(Main.currentRoom);
}
}}
Then in my main class I call:
narrator.narrate(currentRoom, saveRoom); which takes care of some other logic concerning locked doors, encounters, etc.
Also in Main loop are some other methods related to autosave and tracking which rooms the player has visited. I know from other q/a i'v read on here that this is all pretty bad design, and I'm sttarting to understand that now, but my issue is this:
The first room of the game loads up fine, when I click a button it outputs to console(Just for testing) the correct trigger value of the room the button should be calling, so I'm getting that far, but how can I call the same method over again now?
-If I call narrate from actionListener it will wind up calling itself again and complain about ConcurrentModification.
-If I try to keep a loop going in my Main class it will keep looping and won't allow for the player to actually choose a button.
I've never used threads before, which I wonder might be the answer,and the closest thing to a related answer I've found is this:
Java: Method wait for ActionListener in another class
but I don't think moving actionListener to Main class would resolve my problem which is actionListener winding up calling itself recursively. And as for the observer-observable pattern... I just can't understand it :(
I appreciate any and all help, I've learned a LOT trying to make this thing work without seeking help as much as possible but this has stumped me.
Your loop in actionPerformed only checks whether a JButton exists in your optionList with the given actionCommand. However this can be done before actually doing something:
boolean contained = false;
for (JButton j : optionButtons)
if (j.getActionCommand().equals(e.getActionCommand()))
contained = true;
if (contained) {
// change room
}
now you can call narrate because you have finished iterating over the collection beforehand and will not get a ConcurrentModificationException

how do i randomly perform button's action

I'm really new to JAVA and I'm making tic tac toe game i finished player vs player and now i want to do player vs cpu what i want to do is when player click on a button for X to appear then cpu will select their button randomly for O to appear but i don't know the code to randomly perform action
I was searching on internet for hour and still no result
here's my code
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
//my code here to set text and background etc
if(jButton3.getActionCommand().equals("X") && jButton1.getActionCommand().equals("") && jButton2.getActionCommand().equals("")){
//this where i wanna random between 2 button action
}
I want the CPU to choose between
jButton1ActionPerformed(evt);
jButton2ActionPerformed(evt);
but i really have no idea how to do it
My Understanding
I am interpreting your question as How do I write a function which randomly marks one of the remaining squares with the letter 'O', after the user has performed a move. Correct me with a comment if I am mistaken.
Problem Approach
Because I do not know the exact nature of the code representing your cpu player I will provide a high level solution that you can implement.
1. Firstly, after a player marks a square with the letter 'X' you must check which squares still remain unmarked. You can do this by initializing an ArrayList of Integers, 1 through 9, at the start of the game which represent the squares (buttons) which are still unmarked.
Figure: Numbered Tic-Tac-Toe Board
2. Second, each time one of the squares is marked, either by the player or the cpu, remove the corresponding Integer from the list.
3. Watch for button action events in the way you currently are and add the following code. (our ArrayList of Integers is named unmarked_boxes).
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
//my code here to set text and background etc
if(jButton3.getActionCommand().equals("X") && jButton1.getActionCommand().equals("") && jButton2.getActionCommand().equals("")){
Random rand_gen = new Random();
int index_selected = rand_gen.nextInt(unmarked_boxes.size());
box_selected = unmarked_boxes.remove(index_selected);
/*
here you select and mark the button which corresponds to the box
selected. i.e. if the box_selected = 3, then find and mark button3 (not sure
how you access your buttons).
*/
}
In the code I inserted we instantiate and Object of type Random and call its member function nextInt(int bound). This function will generate a number between 0 and the int 'bound'.
In this case we want to select a square from the entire list of unmarked squares.
Hence we generated a number between 0 and the number of remaining squares.
Then we grab (and simultaneously remove) the number which is at 'index_selected' in our list of unmarked_boxes and mark the corresponding button with an 'O'.
After this point, you need to implement your code to mark the chosen button.
Note: If you are dead set on selecting between only 2 squares, then forget about the ArrayList approach I have described. Just call rand_gen.nextBoolean() and insert an if statement which picks one button if true and the other if false.
This should be enough to get you started implementing your solution,
Good Luck

How to move/iterate forward to next value in Array (java/android)

Spent the last 1-2 hours looking for the answer and haven't quite got it, I'm hoping it's something simple.
I have created an array of a custom class with just a small number of values like so (where Person is a Class):
Person person[] = new Person[2];
(Note I'll be replacing the 2 with a variable like numberOfPeople)
I need to create a method that I can call when needed (on a button press for example) that will move from the current person to the next in the array (going back to the start when it reaches the end).
In other words: On button press - move from player0 to player1.
I've been looking at how to use For, ForEach, If etc to do this but can't work it out.
SOLVED VIA Vincent Ugenti's ANSWER.
In case other noobs come across this to solve their problem, had a few subsequent noob issues where I was trying to define the number of values in the array with a variable which wasn't given a value until after the array was made (causing instant crashing) and then I forgot doing nothing more with the code than this won't run each objects Constructor which needs to be done separately.
Create a variable such as "currentPerson"
In your event handler (whenever you want to advance to the next person), currentPerson = (currentPerson + 1) % numberOfPeople
The current person is then always person[currentPerson]
Keeping track of the current index and hooking a button event is what you want to do.
On button press check your variable, increment it by 1 and check if that value is not greater than the length of the array.
If its not greater than the array length you can grab the element, else reset the count to 0 and do what you need to do.
If youre only doing this on button press (event handler) you shouldnt need to use any loops.

BlackBerry - How to improve this search feature over a VerticalFieldManager that holds custom managers

I have a screen with a VerticalFieldManager
for holding a list of custom managers.
The screen also contains a EditField that
behaves as a search field, so when the user
enters some text, my app loops over an array
of custom managers and compares the entered text with the text from
every manager in the array.
If the text from a manager matches
the entered string, I append that custom manager to the
VerticalFieldManager.
These are the relevant parts of my code :
EditField _editField;
TempBeanPlaces [] _placesList;
VerticalFieldManager _vfmCellPlaces;
....
This is the constructor of TemBeanPlaces :
public TempBeanPlaces(String pPlaceName,
CellPlaceManager pCellPlaceManager) {
placeName = pPlaceName;
cellPlaceManager = pCellPlaceManager;
}
...
And this codes handles the search :
_editField.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
String text = _editField.getText().toLowerCase();
_vfmCellPlaces.deleteAll();
for (int i = 0; i < _placesList.length; i++) {
TempBeanPlaces tempBeanPlaces = _placesList[i];
if(tempBeanPlaces.getPlaceName().toLowerCase().indexOf(text) != -1) {
_vfmCellPlaces.add(tempBeanPlaces.getCellPlaceManager());
}
}
updateLayout();
}
});
This works ok when the array _placesList is not too large (length of 50, for example),
otherwise the app becomes too slow.
How could I optimize my code for large amounts of custom managers?. For example, in case the
array contains 600 elements.
I really need to improve this feature. I just have read about the ListField in BlackBerry,
but since I have this code done, maybe I don't need to rewrite everything with ListFields.
Thanks in advance!
Answered a similar question on BB forums here:
How-to-improve-this-search-feature-over-a-VerticalFieldManager
There are three workable options that I would consider:
use addAll() to add all the Managers at once thus significantly
reducing the layout time
using 'paging' so you only add the first 15, and add later
selections if the user wishes you too
Use ListField
The first 2 options would enable you to retain the current Manager code.
Try these options, in the order given, and let us know which works for you.
Update
Given that options 1 has not worked for you, and you are not allowed to do option 2, then perhaps I can suggest option 1.5. Add only the first 25 or so, but add some scroll control that detects when you are getting near the end of your VFM and when you are within 1 screen, it adds some more. This will cause a scrolling glitch at that point but the list will look continuous without the huge hit at the start.
I don't think anyone is going to scroll through 600 entries. If your search displays the number found, that will give your users an indication, and they will probably try a different search if the number is too large. And because you have not added every single item, you have speeded up the process significantly.
A variation on this is to not add al the entries until the user moves focus off the EditField onto the list.
The other thing you could look at doing it having this 'search' process done in a Thread, asynchronously, and cancel it if the user updates the edit Field with some new input.
Alternatively if option 1 has NOT worked for you, can I suggest you try just adding 10 at most, and see if the glitch is still present. If so, then I suspect there is an issue in the processing of your Fields, such as some paint loop or layout loop. Compare this with the time taken to add 10 LabelFields. Perhaps we can optimise the processing in your custom Managers that will overcome this.
Further edit
I had a random thought that perhaps restricting the height of a VFM might restrict the painting done. Not true, I've tested and the only Fields painted are those that are visible. So the performance hit is with the layout not the paint.
Change your code that handles search as follows:
_editField.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
String text = _editField.getText().toLowerCase();
// Delete the vertical field manager
delete(_vfmCellPlaces);
_vfmCellPlaces.deleteAll();
for (int i = 0; i < _placesList.length; i++) {
TempBeanPlaces tempBeanPlaces = _placesList[i];
if(tempBeanPlaces.getPlaceName().toLowerCase().indexOf(text) != -1) {
_vfmCellPlaces.add(tempBeanPlaces.getCellPlaceManager());
}
}
// Add the vertical field manager
add(_vfmCellPlaces);
}
});
Explanation:
Every add() and delete() method, when called on a manager that is currently displayed results in a call to update layout. So if you are adding 50 managers one by one, you will end up calling their sublayout() method 1+2+3+...+50 times which is 50x49/2 which is 1225 times.
If you add 600 managers one by one, you end up calling the sublayout() 179700 times which will probably make your phone crawl.
Moreover, there is no need to call the updateLayout() explicitly in this case. It only needs to be used when the contents of a field change without the knowledge of its manager.

Java Swing - make two JLists "siblings" - i.e. only one item in either can be selected

I have a JPanel which contains two JLists - both can have an item in them selected - as expected.
What I'd love to be able to do is have it so that only one item in either to be selected
Can anyone help me with either
a) "marrying" them so this can be the case
b) giving me some tips for the best practice to write listeners which can preside over them both and unselect all the elements of one when the other is selected - I'd rather avoid this if possible as I can see it getting ugly!!
Thanks :)
I think the best solution, also for the user, is putting a radio button next with a category label to each list, so you clearly disable the other each time you select one.
I can imagine the user clicking values on the first list, then clicking on the next one and seeing all the values he clicked are gone, with logical frustration...
Then when you are taking the values from the form, just take the enabled ones
The listener is not that difficult nor ugly to write. I would
make sure the lists only support single selection
add the same selection listener to both lists' selection model
This listener can be implemented as
public void valueChanged(ListSelectionEvent e){
if ( e.isAdjusting()) return;
ListSelectionModel sourceSelectionModel = (ListSelectionModel) e.getSource();
if ( !sourceSelectionModel.isSelectionEmpty() ){
//still need to implement the findOtherSelectionModel method
ListSelectionModel other = findOtherSelectionModel( sourceSelectionModel );
other.clearSelection();
}
}
Note that clearing the selection will trigger the listener again, but due to the isSelectionEmpty check you will not end up with a loop. Another approach would be to disable the listener (e.g. with a boolean flag) right before you call clearSelection on the other list.

Categories