I'm trying to make a 2d game using java microedition and i just want to make my control smoother but the problem is when i press the LEFT key while pressing the UP Key the condition is not working i dont know why
public void moveJet2() throws IOException{
int gameAction = getKeyStates();
if(gameAction==LEFT_PRESSED && gameAction==UP_PRESSED){
padX-=padXVel;
padY-=padYVel;
}
else if(gameAction==RIGHT_PRESSED){
padX += padXVel;
}
else if(gameAction==UP_PRESSED){
padY-=padYVel;
}
else if(gameAction==DOWN_PRESSED){
padY+=padYVel;
}
}
getKeyStates() returns the state of keys in a single int. The various keys have individual values. UP_PRESSED = 0x0002 and LEFT_PRESSED = 0x0004. So if you press UP on your d-pad while calling getKeyStates(), you'll get 2 back, and if (getKeyStates()==UP_PRESSED) will thus be true.
Likewise, if you press LEFT on your d-pad while calling getKeyStates(), you'll get 4 back.
But if you press UP and LEFT at the same time, you can't get back 2 and 4 - because that's obviously 2 ints - and getKeyStates() only returns one int.
What you do get back though, is rather simple: 2 + 4 = 6.
So, asking if (getKeyStates()==6) will be true if pressing UP and LEFT at the same time. Or if (getKeyStates()==UP_PRESSED+LEFT_PRESSED).
Typically though, you would ask using bit-operators, like this:
public void moveJet2() throws IOException{
int gameAction = getKeyStates();
if((gameAction & LEFT_PRESSED)!=0) {
padX -= padXVel;
}
if((gameAction & RIGHT_PRESSED)!=0) {
padX += padXVel;
}
if((gameAction & UP_PRESSED)!=0) {
padY-=padYVel;
}
if((gameAction & DOWN_PRESSED)!=0){
padY+=padYVel;
}
}
Because using that approach will work with any of the 8 directions you can press at the same time.
Related
I am creating a simple game of 15 puzzle (Please see here: https://en.wikipedia.org/wiki/15_puzzle). I have an array of 4 by 4 buttons and want to know the best way to handle a user clicking on a button and moving around the numbers.
I have started off by creating a JavaFX gridpane to display the buttons as well as a HashMap (suggested by multiple people) to store a mapping between the displayed number (1-15) and the button at that location.
I populate the map with class objects "Btn"
public class Btn {
private int ID;
private int x;
private int y;
public Button button;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
Btn btn = new Btn(count, j, i, new Button("" + count));
map.put(count, btn);
btn.button.setMinSize(100, 100);
btn.button.setOnAction(e -> {
if (isMoveLegal(btn) == true) {
move(btn);
}
});
count++;
grid.add(btn.button, j, i);
}
}
So far it has worked quite well. In the isMoveLegal() method I check if the empty field is above, left, right, or below the clicked button. Which gets quite complicated because of the HashMaps nature of not preserving any order. But my real problem lies in the move() method. Since there is no order, I can't just switch 2 map nodes or can I?
if (MoveDir.equals("Right")) {
map.get((btn.getYs()+1)*4 - (4-btn.getXs())).button.setText("" + map.get(btn.getID()).getID());
map.get(btn.getID()).button.setText("" + map.get((btn.getYs()+1)*4 - (4-btn.getXs())).getID());
int tempID = map.get(btn.getID()).getID();
map.get(btn.getID()).setID(16);
map.get((btn.getYs()+1)*4 - (4-btn.getXs())).setID(tempID);
// System.out.println(map.get(btn.getID()).getID());
// System.out.println(map.get((btn.getYs()+1)* 4 - (4-btn.getXs())).getID());
map.get(btn.getID()).setYs(map.get(btn.getID()).getYs()+1);
map.get((btn.getYs()+1)* 4 - (4-btn.getXs())).setYs(map.get((btn.getYs()+1)* 4 - (4-btn.getXs())).getYs()-1);
This is what I have come up with so far, which extremely complicated and tedious. To quickly sum it up, I first switch the labels of the buttons, then I change the ID variables of the 2 buttons, and then I change the cord variables (x & y) to indicate their new location in map/grid.
I'm pretty sure I have gone way too far with this and there is a simpler solution to all of this but I am just unsure what that would be. Should I ditch the HashMap entirely and just use an object array of Btns?
Thanks for the help.
The problem you're facing is that your UI and your data structure are too tightly coupled. You need to separate them, give them their own responsibilities, and use communication (method calls) between them to make things happen.
For example, the UI should only be responsible for displaying the numbers and allowing the user to click a number to perform a move. Using a gridpane of buttons seems reasonable for this. Each button only needs to know it's x,y coordinate.
The data model should be a 2-dimensional array that contains the number at that location. For example:
+-+-+-+
|4|1|8|
+-+-+-+
|2|3|7|
+-+-+-+
| |5|6|
+-+-+-+
(You can figure out how to represent the empty space. Maybe a null, or the number '0' or '-1')
The data model can be wrapped in a data object that handles questions about and manipulations to the data model. For example, one method it might contain is getTheNumberAtLocation(x,y) which the buttons will call, and will return the number at that location. The buttons will use this to determine what number they should show.
Another method it might contain is isThereASpaceNextToLocation(x,y). This would return whether or not a space exists next to the location given by the x,y. The button will call this method to determine whether or not it can be clicked.
Finally, you could have a moveLocationToEmptySpace(x,y) which will manipulate the data to put the number at the current location into the empty space. After that, all the buttons should call getTheNumberAtLocation(x,y) to update the number they are showing.
By arranging your code like this you've nicely separated the concern of the UI (show text, handle button clicks) from the concern of maintaining the game state (checking if a move is valid, performing a move, determining the state of the board). Now when you write code it will be easier to write because each method will be responsible for a small, manageable piece of logic.
To summarise:
Gridpane (4x4)
-> Button
-> label [calls GameData.getTheNumberAtLocation]
-> click [calls GameData.isThereASpaceNextToLocation, moveLocationToEmptySpace]
GameData
-> Array (4x4) (private)
-> Integer (1-15)
-> getTheNumberAtLocation(x,y)
-> isThereASpaceNextToLocation(x,y)
-> moveLocationToEmptySpace(x,y)
Disclaimer: I'm really new at this and I apologize in advance if:
1) my question has already been asked (I've tried searching and had a lot of trouble finding what I needed)
or 2) if I'm not asking the question correctly.
Basically, I'm trying to make a game where pressing the spacebar triggers a sort of "super-power" that will perform a set of actions just once. Afterwards, if they try to press it again, it'll run up some sort of dialogue box that says their one-time super-power has already been used.
What I have:
try {
Key move = canvas.getLastKey();
int space = 0;
if(move == Key.SPACE) {
if (space == 0) {
space = 1;
}
if (space == 2){
JOptionPane.showMessageDialog(null, "superpower already used");
}
}
if( space == 1 ) {
//action here
canvas.resetKey();
space = 2;
}
}
Right now, the super-hero action is on an endless loop but if I reset the key here:
if(move == Key.SPACE) {
if (space == 0) {
space = 1;
canvas.resetKey();
}
the user can just use the super-power over and over again. Any help would be appreciated!
In the third line, you have written int space=0 so your variable is constantly reset to 0...
You have to initialize it elsewhere (the beginning of your program is a good place for any global variable).
You should consider moving int space = 0, outside of the try block. I suppose your try block gets invoked repeatedly, so you should declare this variable under a global scope.
I am currently making a text adventure game in Java, but I have come across a problem:
I need the value of a String variable to change each time the value of a particular int variable changes.
I want the program to perform this task (then continue where it left off) each time the value of an int variable changes:
if (enemyposition == 1) {
enemyp = "in front of you";
}
else if (enemyposition == 2) {
enemyp = "behind you";
}
else if (enemyposition == 3) {
enemyp = "to your left";
}
else if (enemyposition == 4) {
enemyp = "to your right";
}
else {
enemyp = "WOAH";
}
Thanks! :D
You could make the code much shorter using an array.
String[] message = {"WOAH", // 0
"in front of you", // 1
"behind you", // 2
"to your left", // 3
"to your right"}; // 4
enemyp = (enemyposition > 0 && enemyposition < 5) ? message[enemyposition] :
message[0];
The question you're asking sounds like it might be answerable by creating a class to hold the enemyposition integer. Add a "setter" method to your class to set the integer. You can write your setter method so that when the integer is set, it also sets up a string. Then write a "getter" method to retrieve the string. That's one common way of making sure two variables change together.
public class EnemyPosition {
private int enemyposition;
private String enemyp;
public void setPosition(int n) {
enemyposition = n;
enemyp = [adapt your code to set this based on the position]
}
public String getEnemyp() {
return enemyp;
}
}
I'm sure there are a lot of details missing, but you get the idea. Then instead of int enemyposition in the rest of your code, use EnemyPosition enemyposition = new EnemyPosition(), and use the setPosition method instead of assigning to it.
That's not the only solution (an array or Map that maps integers to strings may be good enough), but it's one OOP way to do things.
Below is the code I'm using to add an OnKeyboardActionListener to my KeyboardView. (For the sake of brevity, I've omitted the required overridden methods that I've left empty.)
keyboardView.setOnKeyboardActionListener(new OnKeyboardActionListener() {
private void shiftOn(boolean on) {
System.out.println("Shifting " + (on ? "on" : "off"));
keyboard.setShifted(on);
shiftKey.icon = keyboard.isShifted() ? shiftLockDrawable : shiftDrawable;
}
#Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = editText.getEditableText();
int selectionStart = editText.getSelectionStart();
if (primaryCode == SHIFT) {
shiftOn(!keyboard.isShifted());
} else {
if (primaryCode == DELETE) {
if (editable != null && selectionStart > 0) {
editable.delete(selectionStart - 1, selectionStart);
}
} else {
editable.insert(selectionStart, Character.toString((char) primaryCode));
}
shiftOn(false);
}
}
});
The problem
When I press the shift key, everything goes as expected; both the key's icon and the state of "shiftedness" changes.
However, when I press any other key (which is supposed to turn shift off), the state of shiftedness changes to off, but the icon doesn't change to the unshifted version. I experience the same problem when using text instead of icons.
I've tried calling postInvalidate() on my KeyboardView but to no avail.
Here's a video that highlights my problem.
I added the following code to the end of the shiftOn method:
keyboard.invalidateKey(SHIFT);
It seems to me that the redrawing of the shift key is attached to the actual input event. Can you, instead of changing the shiftKeyIcon simulate a shift key press in code? You just generate an additional shift key press event when another key is pressed.
I hope this helps you.
I think that there is a problem in shiftOn(). I don't exactly know what shiftLockDrawable and shiftDrawable do, but maybe the following code works
private void shiftOn(boolean on) {
System.out.println("Shifting " + (on ? "on" : "off"));
shiftKey.icon = (on ? shiftLockDrawable : shiftDrawable);
keyboard.setShifted(on);
}
If this doesn't work or if this isn't what you want, could you maybe provide more information?
I am building a GWT component to behave much like the comments box here on stackoverflow, and other sites. I am trying to register listeners for KeyPress, Change and ONPASTE events that will update my status line with number of characters remaining, etc.
It works except it is always one character behind the actual number of characters in the text area. I set the max number of characters to 10. When I type the first character it still says, "10 characters remaining". It doesn't update the status line until I type the second character and then it is one off, it says 9 characters remaining when the second character is typed.
When I BACKSPACE or DELETE, it is also one off, when there are no characters it still says "9 characters remaining" until I press the BACKSPACE or DELETE a second time.
I am getting this behavior in both Firefox, Chrome and Internet Explorer on Windows. So I think I am not registering something correctly.
I know this has something to do with when the events are getting fired, but I have spend hours on trying to diagnose this behavior and have run out of ideas.
Here is where I am registering the event handlers, the complete code is BoundedTextAreaWithFeedback.
private void registerHandlers()
{
final BoundedTextAreaWithFeedback outer = this;
this.textArea.addChangeHandler(new ChangeHandler()
{
public void onChange(final ChangeEvent changeEvent)
{
outer.validate();
}
});
this.textArea.addKeyPressHandler(new KeyPressHandler()
{
public void onKeyPress(final KeyPressEvent keyPressEvent)
{
outer.validate();
}
});
this.panel.addFocusHandler(new FocusHandler()
{
public void onFocus(final FocusEvent focusEvent)
{
outer.textArea.setFocus(true);
}
});
// capture paste events
this.textArea.sinkEvents(Event.ONPASTE);
}
Here is the validate() method.
private boolean validate()
{
final boolean isValid;
final int len = this.textArea.getText().length();
if (len < this.minLength)
{
this.status.setText("Enter at least " + this.minLength + " characters.");
this.status.setStyleName("input-status-underflow");
isValid = false;
}
else if (len > this.maxLength)
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-overflow");
isValid = false;
}
else
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-ok");
isValid = true;
}
return isValid;
}
I just started adding every addXXXHandler() until one worked.
this.textArea.addKeyUpHandler(new KeyUpHandler()
{
public void onKeyUp(final KeyUpEvent event)
{
outer.validate();
}
});
Seems to have done the trick.
Here is the working code, CTRL-V and paste from context menu also work now.
Try using a DeferredCommand to execute the validation code. I believe the problem is that when the event is firing, they character is not yet added to the text area. The DeferredCommand will not execute until any pending event handlers have finished, allowing the length of the text to be calculated correctly.
See this question for an example of using a DeferredCommand.