Alright so I have a project due for computer science, and I need help with grid world. I have the code written so I can click on a critter, but I want to click on the critter once, then click on an open spot on the grid to move the critter to. But it doesn't work. I need to get this working, and I don't know whats wrong with my code. Take a look. thanks for all your help
Actor t;
public boolean locationClicked(Location loc)
{
Grid<Actor> gr = getGrid();
t = gr.get(loc);
Actor j;
//Location second;
if (t != null)
{
setMessage("Click on " + t);
numOfClicks++;
if(t instanceof BlackCheckers || t instanceof RedCheckers)
{
if(numOfClicks==0)
{
secondClick(second);
}
}
}
else
{
setMessage("Click on nothing");
}
return true;
}
Location second;
public void secondClick(Location second)
{
this.second=second;
Grid<Actor> op=getGrid();
Actor te=op.get(second);
if(te==null)
{
t.moveTo(second);
}
}
This is beyond what I know about Gridworld, but I found something that might help.
How You Can Intercept Mouse Clicks and Keystrokes
The World class has student-friendly mechanisms for intercepting mouse clicks and keystrokes. No knowledge of AWT events is required.
When the user clicks on a grid location, the locationClicked method of the World is called. By default, that method returns false, which tells the framework to initiate the default action, namely to move the selection square and to show the constructor or method menu.
To intercept the mouse click, override the locationClicked method. Carry out any desired action and return true. The grid location on which the user clicked is passed as a parameter. Typical actions include flipping tiles, populating empty locations, and so on.
Sometimes, you need to ask the user for additional information after the mouse click. The easiest method is to use a JOptionPane.
Let’s consider a common situation. In a game, a user selects a piece. You want to ask where the user wants to move the piece. You can wait for another mouse click. That means,
your locationClicked method needs to keep track of the click state (piece selection vs. target selection). Or you can enumerate all legal targets and call JOptionPane.showOptionDialog.
When the user hits a key, the keyPressed method of the World is called. By default, that method returns false, which tells the framework to initiate the default key action. If the user hit a cursor key, the selection square is moved. If the user hit the Enter key, the constructor or method menu is shown. All other keys are ignored.
To intercept the keystroke, override the keyPressed method. The method receives the current location and the keystroke string, encoded in the same format that is used by the java.awt.KeyStroke class. Example keystroke strings are "INSERT" or "alt shift X". Your keyPressed method should check the keystroke string. If the string matches a keystroke that you want to intercept, carry out any desired action and return true. Return false for all other keystrokes. It is a good idea to return false for the cursor keys and the Enter key. Otherwise, the standard actions are disabled for your world.
Source (pg 16)
Related
I am developing a game for android with libgdx and I have a little problem, I want to make it trigger a function when the user swipes, this I achieve. The problem is that it runs the function when you finish swiping (when you lift your finger). How can I make the function run while the swipe is doing?
This is the current code for the gesture listener:
private static class DirectionGestureListener extends GestureAdapter{
DirectionListener directionListener;
public DirectionGestureListener(DirectionListener directionListener){
this.directionListener = directionListener;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
if(Math.abs(velocityX)>Math.abs(velocityY)){
if(velocityX>0){
directionListener.onRight();
}else{
directionListener.onLeft();
}
}else{
if(velocityY>0){
directionListener.onDown();
}else{
directionListener.onUp();
}
}
return super.fling(velocityX, velocityY, button);
}
}
And the game scene:
Gdx.input.setInputProcessor(new SimpleDirectionGestureDetector(new SimpleDirectionGestureDetector.DirectionListener() {
#Override
public void onUp() {
/*something*/
}
#Override
public void onRight() {
/*something*/
}
#Override
public void onLeft() {
/*something*/
}
#Override
public void onDown() {
/*something*/
}
}));
I looked into GestureDetector.java of libgdx source code itself. fling() will be executed whenever event of touchUp() happened. Thus aligned with what you experienced.
I think an option to make this work is to implement such gesture detection yourself by extending InputAdapter class or implementing InputProcessor interface class, then work on touchDown(), and touchDragged() to have an intended effect as you aimed for.
The idea is to keep track of touch id as it firstly touched on the screen inside touchDown() (its 3rd parameter is int button which is what you're looking at), then use that id to check and further operate inside touchDragged(). If id matches, then for simple approach, you can check whether user touched and moved for pre-defined distance by comparing it against original touching position.
Let's say we want a swipe gesture only when user firstly touches the screen, moves it for (at least) distance we pre-defined set, and within pre-defined duration. So if user firstly touches the screen, moves finger around but still not more than pre-defined distance, then finally moves far enough within duration we've set, this still won't be treated as swipe as our conditions set that it must be from first intention (first touch) to do such gesture. This means we calculate distance against original touching point, not moved point. Of course, you can customize the conditions to suit your need too.
From above, conditions to regard it as swipe gesture can include following (you can adapt these yourself)
distance it moved compared to original touching point
duration it took to move (might be 150ms, etc), longer duration user can be more relaxing not to act fast to make it registered as swipe gesture
only 1 swipe at a time can be taken into effect i.e. if user uses 2 fingers (2 touches) to swipe at the same time, only first one (or last one) can be used as swipe effect, etc.
Treating it separately for x, y direction is per your need. If so, you have to add handling code inside touchDragged() to check for both direction and send you corresponding event i.e. swipe-x, or swipe-y per se. Then you hook it up by calling one of your method to let your game knows.
In my JavaFX project, I have a ModifiedTreeCell class which extends TreeCell. In that class, I have two functions which listen to whether the mouse enters or exits the TreeCell. However, these methods appear to be horrendously unreliable.
Either:
A) They don't detect the mouse entering at all and no popup occurs.
B) They keep calling ENTERED and EXITED back to back forever, so the popup flashes over and over.
C) They will detect an Enter and then immediately detect an Exit even though the mouse is still well within the boundary of the Label.
How can I fix this?
If you'd like to see what I mean first hand, I compiled a runnable Jar file of my project:
Here is the repo. Once you download it, run D2BT.jar and make a new account, a new character, then add an item like Ring, click Magic from the ChoiceBox, and then click the Add Item Button. Go to the View Account Tree Tab to and then hover over one of the Label(s) in Blue.
Okay in the image below, I know my mouse cursor looks like it's on the edge of the Label but I'm telling you if you tried it yourself it doesn't really matter where your mouse is. The setOnMouseEntered/Exited commands simply don't work properly. I know it may seem like it's my ItemFrame Popup causing the problem but I assure you that it will occur even if you comment out the frame.show(); and frame.hide(); methods shown in the image.
Here is the ModifiedTreeCell class:
package application;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import logic.Item;
/**
* This TreeCell object is for the TreeCellFactory
* function in the GUI class. The TreeCellFactory
* function will convert TreeItem objects into
* ModifiedTreeCell objects which display the
* necesary information to the user, such as
* a Label displaying either the Account name,
* Character name, or Item in a readable fashion.
* #author Kevin
*
*/
public class ModifiedTreeCell extends TreeCell<TreeViewable>
{
/**
* This Label will display the neccesary text related to the item.
* The Label may have a `on Mouse Hover` listener which will display
* a ItemFrame_Animated IF the TreeViewable object claims it to be an item.
*/
private Label displayProperty;
#Override public void updateItem(TreeViewable value, boolean empty)
{
if (!empty)
{
setEditable(true);
// Create the label for this cell.
displayProperty = new Label(value.getTextProperty());
displayProperty.getStyleClass().clear();
// If Value is an Item object...
if (value instanceof Item)
{
// Item Reference.
Item ref = (Item) value;
// Create a Popup window of the item hovered over.
ItemFrame_Animated frame = new ItemFrame_Animated(ref);
displayProperty.setFont(GUI.diabloFont);
displayProperty.setTextFill(ref.getQuality().getColor());
displayProperty.setOnMouseEntered(e ->
{
System.out.println("MOUSE ENTERED THIS LABEL");
frame.show(GUI.window);
});
displayProperty.setOnMouseExited(e ->
{
System.out.println("MOUSE EXITED THIS LABEL");
frame.hide();
});
}
displayProperty.setStyle(GUI.DEBUG_PANE_BORDER);
// Display a Node for this cell.
setGraphic(displayProperty);
}
else
{
// No cell to be displayed, set to null.
setText("");
setGraphic(null);
}
}
}
I finally succeded compiling your project.
Result is no surprise -> by commenting the frame.hide() line, the popup stays on. A solution is given below at 3.
Now some points you can apply to get a super duper app that will not become a mess very quickly.
Get a nice build architecture for your Java project. You can do this by organizing it as a Maven Project. This is just a suggestion, the point is that you should be very confident by fetching your resource files for instance (in your project, you do it by at least 2 or 3 different methods, using File class and getResource(String path) method.
Think more about your architecture before start coding. I am quite sure you did'nt think about any pattern or any idioma before. Think about how you can split your app in multiples mini-API that handle a specific part of logic. Moreover, the gap between your logic and the GUI should be moremore larger to avoid spaghetti code.
Read more tutorials about JavaFX. What you are trying to achieve with a Popup already exists and is called a Tooltip, you already use it in your app and it is as customizable as any other JavaFX component.
I hope you will succeed in a very usefull App for all Diablo2 gamers! :)
So for reference, I am following Trystan's roguelike tutorial for java.
The tutorial above uses Key Listeners, which does not work for Mac OS X (and appears to be discouraged by the community), so I am trying to change the code to use Key Bindings instead.
Here's the question. In his "roguelike game", the game is divided into screens, where each screen has separate actions for a particular key. For instance, the "Start Screen" sends the player to the "Play screen" upon pressing the enter key:
public class StartScreen implements Screen {
public void displayOutput(AsciiPanel terminal) {
terminal.write("rl tutorial", 1, 1);
terminal.writeCenter("-- press [enter] to start --", 22);
}
public Screen respondToUserInput(KeyEvent key) {
return key.getKeyCode() == KeyEvent.VK_ENTER ? new PlayScreen() : this;
}
}
While the "Play Screen" sends the player to the "Win screen" upon pressing the enter key:
public class PlayScreen implements Screen {
public void displayOutput(AsciiPanel terminal) {
terminal.write("You are having fun.", 1, 1);
terminal.writeCenter("-- press [escape] to lose or [enter] to win --", 22);
}
public Screen respondToUserInput(KeyEvent key) {
switch (key.getKeyCode()){
case KeyEvent.VK_ESCAPE: return new LoseScreen();
case KeyEvent.VK_ENTER: return new WinScreen();
}
return this;
}
}
Now, from what I can see from Key Bindings examples such as this and this, all the bindings and actions seem to be "dumped" into one class. This is unsatisfactory, because:
One keystroke leads to only one action (I suppose I could have the action do a switch case, and check what screen I am in, and then execute some code specific to said screen, but perhaps there is a better way.)
It becomes more difficult to determine what action is from/for what screen.
Would there be a way to get Key Bindings to have one keystroke execute different actions depending on the "Screen"? Would I just use conditionals? Can I put Key Binding logic in other classes (Screens) and then call them in the main class, like what is happening with Key Listeners above?
Key bindings are not necessarily dumped into one class. They are associated with input maps, which in turn are associated with specific JComponents. If you register screen-specific bindings in the WHEN_ANCESTOR_OF_FOCUSED_COMPONENT input map of the JComponent representing that screen, then they will be recognized when any component in that screen has the keyboard focus (supposing a component in between has not overridden the binding with its own), but not when a component in a different screen has the focus.
Overall, the system is very flexible. You might consider reading the Java Tutorial section on this topic to bring yourself up to speed.
In my code, two comboboxes are added to actionListener( this );
In another part of my code, I call a combobox function that sets an index to a certain value. This in turn calls actionPerfoemed again and so getSource == comboBox is true. Every time I call a set function it calls actionPerformed again, creating a stack of function calls that then unwinds down to the first.
Is there a way to prevent this?
If the problem is just the initial setting, you can defer adding the listener until after both have been initialized. There's more discussion here.
From the Swing tutorial,
Combo boxes also generate item events, which are fired when any of the items' selection state changes.
These events will be generated either when a user clicks on the items with the mouse, or when your software calls setSelectedIndex().
Perhaps you don't want your actionPerformed() method in this to be called when your software calls setSelectedIndex(). You may need a Boolean eventInitiatedBySoftware. In your main (this) class, you could say
synchronized(eventInitiatedBySoftware) {
eventInitiatedBySoftware=true;
comboboxeditor.setSelectedIndex(n);
}
and then in your listener:
public void actionPerformed(ActionEvent ae) {
synchronized(eventInitiatedBySoftware) {
if (eventInitiatedBySoftware) {
eventInitiatedBySoftware=false; // clear your flag.
return; // don't want to process this event.
}
// the rest of your method goes here
}
When your software wants to adjust the value, it will set the Boolean to true. The actionPerformed method will be called, but your test will realise that this event was initiated by the software, and return before doing any of your existing code. It will clear the Boolean, so that if a user now uses the mouse to perform a selection action, your code will realise that it wasn't softwareInitiated.
BTW, It's possible that you misunderstand the event concept. For example, I suspect you are actually adding "this" as an event listener for each combobox, rather than adding comboboxes as listeners to "this". You might like to look at the Writing Event Listeners trail.
Here's the situation, I have a jFrame with a tabbed pane and within the tabs I have a couple of jTables and a jTree. I want to be able to chain the selections between the tables and the tree based on whether a user uses a ctrl/shift + click versus a regular click. (If you hold ctrl and click in the first table/tree, it adds to the overall selection, if you use a regular click it clears the selections in the other tables/tree). Currently I'm having an issue with Java's jTree component. I have added a TreeSelectionListener and a MouseListener with a class that implements both interfaces, call it MyBigListener;
i.e.
MyBigListener listener = new MyBigListener();
jTree1.addMouseListener( listener );
jTree1.addTreeSelectionListener( listener );
MyBigListener implements TreeSelectionListener, MouseListener {
private boolean chained = false;
public synchronized setChained(boolean ch){
chained = ch;
}
public synchronized boolean isChained(){
return chained
}
public void valueChanged(TreeSelectionEvent e){
if(isChained()){ blah... }
}
public void mousePressed(MouseEvent e){
setChained(e.isControlDown() || e.isShiftDown());
}
}
My plan was to set a boolean flag if the user uses a ctrl/shift + click that I could check during the valueChanged(TreeSelectionEvent e) implemented by the tree selection listener.
I want to be able to process the mouse events before the valueChanged TreeSelectionEvents, but the problem is that I receive the mouse events after the valueChanged treeSelection event. This seems weird to me that I receive the selection change before the mouse pressed event fires, when the selection change is actually initiated by the mouse pressed. (I've already synchronized the boolean flag setting, which ironically helped to highlight the mis-order of events.)
I've already tried alternatives like adding a keyListener, but this doesn't work when the focus is on a separate frame, which goofs me up when a user holds ctrl and then clicks into the jTree causing it to receive both the focus and fire any valueChanged selection events.
Any help would be appreciated, thanks!
--EDIT-- #akf
I have separate jTables and jTrees in a tabbed Pane that serve as a summary/control panel for data in a nodal-graph. I'm using these components in the tabbed Pane to do coordinated selection to a graph displayed in a separate jFrame. Individually each table works just fine for its selection as does the jTree. It's coordinating between the panes that's tricky. This works fine so far with jTable components because I fire the new selections as the result of a MouseEvent where I can tell if the shift/ctrl button was down, formulate my new selection, and pass it to the parent frame which coordinates selections between all panes and sends the final selection to the graph. However, the parent needs to know if it needs to chain a selection between panes, or squash the others. With the jTables it's fine again, because I fire selection changes as the result of a mouse click. The jTree is more of a problem because I'm doing some forced selections. If you click on a branch, it forces all leaves into the selection. I needed to implement a TreeSelectionListener to do that, but only get a valueChanged(TreeSelectionEvent) to realized changes. I added a mouseListener to listen for ctrl+clicks and shift+clicks, but apparently the events don't always happen in the same order.. at least so far I receive the valueChanged event before the mousePressed event, so checking to if a ctrl+click happened posts after the selection has already been modified.
Right now, I'm posting a pending selection change and then have the MouseListener grab that and send it up the chain, but if these events aren't guaranteed to happen in the same order, at some point it's going to fail. Implementing a delayer also rubs me the wrong way.
Thanks for the help so far.
--EDIT2-- #ykaganovich
I think overriding the fireValueChanged method is closer to the right way to go about things. Depending on my definition of what actions should cause a "chained" selection to the other components, I'd need to gather some context on what's going on before the valuedChanged method fires. This basically means calling it myself in all cases where I can define what it means by who triggers it. I.e. If a mouse event causes it and ctrl is down then set what I need to set (interpret) then fire. If it's going to change due to a keyboard event, again, set what I need to set, then fire. I don't think the TreeSelectionModel is the way to go, because I still won't know what the circumstances were when the event fired. I think this means I'll need to rewrite parts of the jTree to do this but I guess I'll see how it goes. Thanks.
Don't do it that way, override JTree.fireValueChanged instead.
Try something like this (untested):
class ChainedSelectionEvent extends TreeSelectionEvent {
ChainedSelectionEvent(TreeSelectionEvent e) {
super(e.newSource, e.paths, e.areNew, e.oldLeadSelectionPath, e.newLeadSelectionPath);
}
}
protected void fireValueChanged(TreeSelectionEvent e) {
if(chained) { // figure out separately
super.fireValueChanged(new ChainedSelectionEvent(e));
} else {
super.fireValueChanged(e);
}
}
Then check instanceof ChainedSelectionEvent in your listener
EDIT
Actually, I think the right way to do this is to implement your own TreeSelectionModel, and override fireValueChanged there instead. Assuming setSelectionPath(s) methods imply a new selection, and add/removeSelectionPath(s) imply chaining, you could distinguish between the two cleanly. I don't like listening to either keyboard or mouse events explicitly, because there's more than one way to change a selection (e.g. if someone is holding down SHIFT and hitting a down-arrow, you won't get a mouse event).
You may get the mouse event before or after the tree selection event. Best not to rely on such orders. The reason is that the tree selection event is caused in response to the mouse event. Is that mouse event listener called before or after your listener? Could be either.
This sort of thing is closely involved with the implementation of the PL&F.
the key here is to understand that a JTree is delivered with a BasicTreeUI.MouseHandler, see javax.swing.plaf.basic.BasicTreeUI.
to answer the central question, "what fires fireValueChanged", the answer is "this mouse handler"... which turns out to be the only mouse listener returned when you go tree.getMouseListeners().
So you have to replace this default mouse listener with your own version ... which is a little tricky. I use Jython, which everyone needs to discover. This code shouldn't be too difficult to translate into Java however:
from javax.swing.plaf.basic import BasicTreeUI
def makeMouseHandlerClass():
class MouseHandlerClass( BasicTreeUI.MouseHandler ):
def mousePressed( self, mouseEvent ):
genLog.info( "mouse handler MOUSE PRESSED!" )
nTFSelf.mousePressedStatus = True
BasicTreeUI.MouseHandler.mousePressed( self, mouseEvent )
nTFSelf.mousePressedStatus = False
return MouseHandlerClass
suppliedMouseHandler = nTFSelf.taskTree.mouseListeners[ 0 ]
nTFSelf.taskTree.removeMouseListener( suppliedMouseHandler )
nTFSelf.taskTree.addMouseListener( makeMouseHandlerClass()( nTFSelf.taskTree.getUI() ))
... basically the equivalent Java here would be to extend BasicTreeUI.MouseHandler as MyMouseHandler, and then in the last line replace with new MyMouseHandler( tree.getUI() )... "nTFSelf" here is merely a reference to the "this" object of the code where all this is being written...