I'm writing a chess game with gui in mvc design.
Step 1: a main menu pops and you choose a game mod.
Step 2: once you chose, the main menu closes and a new window opens with the board and pieces, then you play with the mouse.
for step 1; I use actionEvent and check the string of the button you clicked on.
for example, you have the button Standard Game, and then model sets up the dataBoard and notifies observer(=view).
for step 2; I use mouseEvent and check relative coordinates x/y, the model does what it does and decides if you can move the piece.
I want to have two update methods in view, one for step 1, the other for step 2.
currently it always goes to the first update.
// this is in the model, initializing once you chose a game mod,
// this is for the first step.
public void initializeGame(String givenString){
abstractGame = factoryGame.createGame(givenString);
abstractGame.startPlaying(boardTest);
setChanged();
notifyObservers(5);
}
// this is in the model, doing stuff, this is for the second step.
public boolean checkGivenCoordinates(int sourceRow, int sourceColumn, int destinationRow, int destinationColumn) throws IncorrectCoordinatesException, IncorrectColorException, InvalidMoveException
{
if(abstractGame.checkCorrectCoordinates(sourceRow, sourceColumn, destinationRow, destinationColumn) == true)
{
abstractGame.checkMove(sourceRow, sourceColumn, destinationRow, destinationColumn);
int [] changeView = {sourceRow, sourceColumn, destinationRow, destinationColumn};
System.out.println("Model : in the move ");
setChanged();
notifyObservers(changeView);
return true;
}
else
throw new IncorrectCoordinatesException();
}
// Called from the Model
public void update(Observable obs, Object obj) { // this is the one it always goes to now.
//who called us and what did they send?
System.out.println ("First update View : Observable is " + obs.getClass() + ", object passed is " + obj.getClass());
} //update()
// Called from the Model
/* this is for step 2, but is not invoked.
The array I send holds 4 ints, source row/column and destination row/column.
this is what I do in model just prior to notifying,
supposed to go to step 2's update method,
but as stated, it doesnt.
*/
public void update(Observable obs, int[] obj) {
//who called us and what did they send?
System.out.println ("Second update View : Observable is " + obs.getClass() + ", object passed is " + obj.getClass());
graphBoardView.setMove(obj[0], obj[1], obj[2], obj[3]);
} //update()
so,
1) can I have more than one update in a single class?
2) if so, how can I direct notifying to the correct update method?
3) if q1 isn't possible, how can I bypass this?
4) could it be that Object obj causes it to always go to the first one?
thanks in advance,
ariel.
You can indeed have more than one method of the same name, but with different parameters, in the same class.
You can see what you're seeing when the compiler cant determine which method to use if there is ambiguity - remember that that an array is an Object too.
With a simple test case it should work:
new Test().update(new Observable(), new int[]{1, 2});
new Test().update(new Observable(), new Object());
The correct methods get invoked.
How are you calling your methods?
Related
So I'm trying to use Key Bindings, and the action map's put() method takes an action and a string parameter.
/* all declartion is above
* the class extends JPanel so the keyword "this" can be used
* xlist is an ArrayList of Integers
* keyActionRight ka = new keyActionRight(x); is declared above, where x is a global int
* this is part of the keyBindingsTest class */
xlist.add(x);
im = this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "right");
am = this.getActionMap();
am.put("right", ka);
System.out.println(ka.getNextX(xlist)); //Any way for this to be called just like if I printed in the actionPerformed of the action class?
This is the keyActionRight class. It is an action as you get an action when you extend AbstractAction:
public class keyActionRight extends
AbstractAction
{
private int x;
private ArrayList<Integer> xlist;
public keyActionRight(int x)
{
this.x = x;
xlist = new ArrayList<Integer>();
xlist.add(x);
}
public int getNextX(ArrayList<Integer> x)
{
x = xlist;
return x.get(0);
}
public void actionPerformed(ActionEvent e)
{
if(x != 440)
{
x++; //this incrementing works fine
xlist.add(0, x); //this updates xlist fine
}
}
}
The goal is essentially just to update the instance variable x in the keyBindingsTest class whenever I press or hold the right arrow key. The x in the Action class is updating just fine when I do this (I printed it out and it works). It's been pointed out why it's not updating - it is only being called once in the print statement. I want to know if there is a way to make this work with a separate class for the action or if I need to take a different approach.
I could try making the Action in the keyBindingsTest class, but that was giving me strange errors last time I tried that. Any help would be appreciated.
Thanks.
You have faulty assumptions:
xlist.add(x);
im = this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "right");
am = this.getActionMap();
am.put("right", ka);
// **** the comment below is incorrect ****
//only prints out zero - should print out ascending values of x as I hold down the right arrow key
System.out.println(ka.getNextX(xlist));
The assumption you're making is that the println gets called when the Key Bindings action is called, but that is simply not so. The println is called once and only once when the key binding is created. The only code that gets called repeatedly is that which is within the Action's actionPerformed method, the code that is called in response to an event.
If you want code called multiple times and in response to an event, it must be placed within an event listener, not the listener's creation code.
I made a simple plugin on actions. I have one issue.
When player press shift and quickly close inventory, he can get item without pay. I need to fix this, what do I need to do?
Code Below:
#EventHandler public void inventoryHandler(InventoryClickEvent e) throws Exception {
for (AuctionInventory[] inventories : inventoryMap.values()){
for (AuctionInventory inventory : inventories){
if (inventory.getInventoryType().equals(AuctionInventoryType.MAIN)) {
if (e.getClickedInventory().equals(inventory.getSource())) {
e.setResult(Event.Result.DENY);
e.setCancelled(true);
if (e.getCurrentItem().getType() != Material.AIR) {
Player p = (Player) e.getWhoClicked();
for (Button button : buttonList){
if (button.getItem().equals(e.getCurrentItem())){
button.doLogic(inventory.getSource(), p);
e.setResult(Event.Result.DENY);
}
}
IProduct product = InventoryUtil.getProductByItem(getProducts().values(), e.getCurrentItem());
if ((product != null)) {
buyProduct(p, product);
}
}
}
}
}
}
}
#Override #Deprecated #SuppressWarnings("all")
public boolean buyProduct(Player p, IProduct product) throws Exception {
if (!product.getSeller().equals(p.getUniqueId())) {
if (Economy.getMoney(p.getName()) < product.getPrice()) {
return false;
}
p.getInventory().addItem(product.getItem());
removeProduct(product);
Economy.setMoney(p.getName(), Economy.getMoney(p.getName()) - product.getPrice()); Economy.setMoney(Bukkit.getOfflinePlayer(product.getSeller()).getName(), Economy.getMoney(Bukkit.getOfflinePlayer(product.getSeller()).getName()) + product.getPrice());
return true;
}
return false;
}
It is hard to say, if your logic related to checking inventory is fine I would say that you missed InventoryDragEvent. You need to implement that event too, and block any interactions related to your inventories.
Also in your ClickEvent you should block interaction if your inventory is open - including clicks inside player inventory, as there are interactions that can move items from opened inventory by clicking inside own inventory.
Also getClickedInventory() can return null.
So you should just check event.getView().getTopInventory() check if it is not a null, and if it is your inventory.
Also your for loop with buttons does not break/return, so even if player will hit a button you will still try to find item to sell, that might cause some issues too.
Also I noticed few others problems here, you should not use .setMoney function if you are using Vault API as this might break compatibility with other plugins, same with checking money by getMoney.
There is special public boolean has(OfflinePlayer player, double amount); method to check if player have enough money, as this function will work well with plugins that allows for negative amounts, or paying in different way.
Then you should take money from player by: public EconomyResponse withdrawPlayer(OfflinePlayer player, double amount); also you should then check response to ensure that it was successful.
p.getInventory().addItem(product.getItem()); what if player does not have enough space in inventory? Note that this method returns Map<Integer, ItemStack> where key is index of item from method argument (as it is varargs, in your case key can be only a 0, as you are only passing single argument) and item that didn't fit into inventory. (note that one part of stack might be added, like 12 from 43 items in stack)
I learn Java and wonder if the item in this code line:
useResult(result, item);
Will be overrwritten by the next call coming from the
doItem(item);
Here´s the eaxmple:
public void doSomeStuff() {
// List with 100 items
for (Item item : list) {
doItem(item);
}
}
private void doItem(final Item item) {
someAsyncCall(item, new SomeCallback() {
#Override
public void onSuccess(final Result result) {
useResult(result, item);
}
});
}
the SomeCallback() happens some time in the future and it´s another thread
I mean will the useResult(result, item); item be the same when callback return?
Please advice what happens here?
I mean will the useResult(result, item); item be the same when callback return?
Of course it will, what would the utility of that be otherwise?
What you are doing is creating 100 different SomeCallback classes, that will process a different Item object.
A skeleton for your someAsyncCall may look like this:
public static void someAsyncCall(Item i, Callback callback) {
CompletableFuture.runAsync( () -> { // new thread
Result result = computeResult(i);
callback.onSuccess(result, i);
});
}
The point is: Callback, at the moment of instantiation, doesn't know anything about the Item he will get as parameter. He will only know it, when Callback::onSuccess is executed in the future.
So, will Item i change (be assigned a new object) ?
No, because it is effectively final within someAsyncCall (the object value is not explicitly changed).
You can't even assign i = new Item(), as the compiler will complain about the anonymous function accessing a non-final variable.
You could of course create a new Item and pass it to the callback
Item i2 = new Item();
callback.onSuccess(result, i2);
but then it would become one hell of a nasty library...
Nobody forbids you to do i.setText("bla") though, unless your Result class is immutable (the member fields are final themselves).
EDIT
If your questions is how java handles object in method parameters, then the answer is: yes, they are a just copy of the original instances.
You could try with a simple swap method void swap(Item i1, Item 12); and you'll notice the references are effectively swapped only within function, but as soon as you return the objects will point respectively to their original instances.
But it's a copy that reflects the original instance.
Coming back to your example. Imagine your someAsyncCall waits 10000 ms before executing the callback.
in your for loop, after you call doItem, you also do: item.setText("bla");.
When you print item.getName() within useResult you will get bla. Even though the text was changed after the async function was called.
I have following problem:
I've programmed a 2D Game with a multiplayer function. Right now i store others Player Data and GameObjects in two ArrayList (The world is stored otherwise). Sometimes the Network-Thread sends Updates, which can not be applied, because the Game draws the Players/Game Objects (java.util.ConcurrentModificationException). Because this drawing process happens every Second around 60 times (because of animations) the problem apeers often (every 2 seconds). This is the code for the players ArrayList:
Draw the Players:
for (Player p : oPlayer) {
if (p != null) {
int x = (int) ((width / 2) + (p.x - getPlayerX()) * BLOCK_SIZE);
int y = (int) ((height / 2) + (p.y - getPlayerY()) * BLOCK_SIZE);
g.drawImage(onlinePlayer, x, y, BLOCK_SIZE, BLOCK_SIZE, null);
FontMetrics fm = g.getFontMetrics();
g.setColor(Color.DARK_GRAY);
g.drawString(p.getName(), x + (BLOCK_SIZE / 2) - (fm.stringWidth(p.getName()) / 2), y - 5);
}
}
Edit Information in Network-Thread:
case "ADP": //add Player
Game.oPlayer.add(new Player(message, id));
sendX();
sendY();
break;
case "SPX": // set X
for (Player p : Game.oPlayer) {
if (p.getId() == id) {
p.setX(Short.parseShort(message));
break;
}
}
break;
case "SPY": // set Y
for (Player p : Game.oPlayer) {
if (p.getId() == id) {
p.setY(Short.parseShort(message));
break;
}
}
break;
case "PDI": // remove Player
for (Player p : Game.oPlayer) {
if (p.getId() == id) {
Game.oPlayer.remove(p);
break;
}
}
break;
Thank you in advance :)
What happens here is, that 2 Threads are working on the same list.
The first one is reading the List (for (Player p : oPlayer) {) and the second one is modifying it (Game.oPlayer.add(new Player(message, id));). This brings the oPlayer list into an (sort of) "inconsistent" state. Java sees that you modified something that you are reading and throws this exception to let you know, that something is not kosher.
More information about ConcurrentModificationExceptions can be found here
To clarify, you dipped into the so called Readers-writer problem. You have an reader (Thread), that reads the Data of Game.oPlayer and a writer (Thread) that writes data to Game.oPlayer.
Solutions
Synchronized-Keyword
The synchronized keyword is explained here. You would use it like this:
private final List<Player> players = ...;
public void addPlayer(Player player) {
synchronized(players) {
players.add(player);
}
}
public void removePlayer(Player player) {
synchronized(players) {
players.remove(player);
}
}
Note that the List has to bee final. Furhter i am using a local attribute instead of your static one. Remove players with Game.oPlayer to get a suited solution.
This allows only 1 thread to access players.add() and players.remove().
Lock
Informations about how to use Locks can be found here.
Easy said, you create a block like this:
try {
lock.lock();
// work ..
} finally {
lock.unlock();
}
so that only one thread can access the work part by saying lock.lock(). If any other thread locked the work part using lock.lock() and not unlocked it, the current thread will wait until lock.unlock() is called. The try-finall block is used, to assure, that the lock is unlocked, even if your work part is throwing an throwable.
Furhter i would recommend itterating over a "copy" of the player-list like this:
List<Player> toIterate;
synchronized(players) {
toIterate = new ArrayList<>(getPlayerList());
}
for(Player player : toIterate) {
// work
}
Or synchronizing this part completly like this:
synchronized(players) {
for(Player player : players) {
// work
}
}
The first one provides you with an copy of that instance, which basically means, it contains the same Objects as the original List, but it isn't the same List. It helps you by letting more threads work on there own "list" and finish theire jobs, regardless of updates at the current time, becaus the second example will block if:
Any thread wants to read the list.
Any thread modifies the list.
So you only have to synchronize the coppy part in the first example.
Even furhter (not particually part of your question, but still something that would make it easyer) i would recommend not using static, as you stated in Game.oPlayer.[...] and taking a look at Dependency Injection.
You could modify your Game-class to provide the methods addPlayer(Player player);, removePlayer(Player player); and getPlayerList(); to realy code in an Object Oriented fashion.
With that design, you could easyly modify your code, to handle the new concurrency issue.
If a list is iterated or modified in one thread and also in another thread you will get a ConcurrentModficationException. In general user interface applications restrict modifying model data to a single thread, usually the user interface thread, such as the event dispatch thread of Swing, or the platform thread in JavaFX.
As an aside, for JavaFX there exists a game library providing out of the box techniques for game development. JavaFX in general is much better suited for graphics intensive work than AWT or Swing.
Have you tried using Vector instead? It is part of Collection and is synchronized.
The idea of listener is, that of some field(or attribute) of an object changes, all "registered" listeners will be "notified" and copy the new value to their fields.
However, is it not an unnecessary complicated and redundant design?
Here is a simple proposal to solve the problem with direct value pointing and in-boxing if need.
For example, in case of string field:
public class StringBox {
protected String value;
public String getValue() {
return value;
}
public void setValueAtomic(String value) {
this.value = value;
}
public StringBox(String value) {
this.value = value;
}
public StringBox() {
}
#Override
public String toString() {
return "StringBox{" + "value=" + value + '}';
}
}
public class StringListenerReplacer {
protected StringBox field;
public StringListenerReplacer(StringBox field) {
this.field = field;
}
public void setField(String field){
this.field.setValueAtomic(field);
}
public String getField(){
return this.field.getValue();
}
}
public class DemoMain {
public static void main(String[] args) {
StringBox field = new StringBox("DemoMain");
StringListenerReplacer s0 = new StringListenerReplacer(field);
StringListenerReplacer s1 = new StringListenerReplacer(field);
StringListenerReplacer s2 = new StringListenerReplacer(field);
StringListenerReplacer s3 = new StringListenerReplacer(field);
StringListenerReplacer s4 = new StringListenerReplacer(field);
StringListenerReplacer s5 = new StringListenerReplacer(field);
System.out.println("Now, it is quasi a listener set to the string field value, so if one object change it, it changes for all");
System.out.println("s0.getField() = " + s0.getField());
System.out.println("Now, for example s4 changes field");
s4.setField("another value");
System.out.println("s0.getField() = " + s0.getField());
System.out.println("s1.getField() = " + s1.getField());
System.out.println("s2.getField() = " + s2.getField());
System.out.println("s3.getField() = " + s3.getField());
System.out.println("s4.getField() = " + s4.getField());
System.out.println("s5.getField() = " + s5.getField());
}
}
With listener design, not talking about it would look syntactically weird,
each of this object would have a reference to another one (6*5 = 30 references), 6 copies of the string field and with each change
or the field, a firePropertyChange with 5 calls in the loop over all listeners will be called.
Now i understand, why for example Eclipse or Netbeans IDE are extremely slow on weak laptops, working from the akku.
So the question is, why do people do use listeners overall in programming?
The idea of listener is, that of some field(or attribute) of an object changes, all "registered" listeners will be "notified" and copy the new value to their fields.
I think the premise of this is wrong. I'm a fan of using listeners, the observer pattern in general, but have never used them in that way.
You might want to execute an action when a button is clicked. For instance printing some text to the console. Rather than constantly polling the button for changes, with every listener, it's much more efficient if the button calls the listeners instead.
Even if you have a reference to the variable isClicked which is true during the frame the button was clicked, you would constantly have to check if(isClicked) {...}, with every listener.
One big disadvantage I can see with your design is that it is necessary to have access to the StringListenerReplacer object in order to change a value and have it "listen" for the change.
What happens if I have dozens of different, barely-related classes or logical code blocks which may or may not affect the object in question? The listener pattern allows for a listener to be notified of a change no matter what state the program is in or what has access to it.
It's also much more useful for multithreading, wherein we might synchronize listeners across threads to wait for value changes or even remote calls. Those threads can be in completely different states or executing blocks of code and the listener will always be properly notified.
The official name of the listener design is called observer. You are correct that setting up listeners does add code and complexity. As such you would not use listeners for simple POJO's. You would use it mostly for events and queues.
A video game is a good example of where you would use the observable pattern, but there are countless. I worked on a game where there were events all over the place. One of the events was a pause event. At first I would manually notify all the objects that needed to know about the pause events, every enemy and projectile and the music etc.. I kept doing this because of the costs and complexity of adding the observable pattern to this part of the game. But after a while it became too difficult to notify all the objects manually as the list grew. So I bit the bullet and implemented the observable pattern. This had an overall affect of reducing complexity in my code. With the observable pattern, any object that needed to be notified about the pause event would take it upon itself to register itself to be notified when that event occurred.
Events and queues might be a little obvious. Let me give you a more mundane example, also involving the same video game. The game was coded in JavaFX, which already has observable patterns built into their classes. I registered listeners to be notified when objects on the screen changed. For example I recall having an object X on the screen whose placement depended on the placement of another object Y. So I setup a listener so that when the coordinates of object Y changed, I would rearrange object X on the screen. This example shows how it could be useful even for properties of a class.