I'm looking for a way in Java to read in raw mouse input and not just the event listeners. I'll tell you what I'm doing. Essentially, there is a game where if you move the mouse to the right, I want Java to send key signals of the 'd' key being pushed down, and when the mouse is moved to the left, the 'a' key being held down. But, when you move the mouse, the game quickly corrects the mouse position and sends it right back into the middle of the screen. So, if you use mouse listener, you get one event of the mouse being moved to the right, then another quickly following of the mouse being move back to the left. I want to know if I can get data from the mouse without those corrections in the position. Thanks!
A little code might make the situation clearer, but here's what you can do.
While there are a number of APIs (LWJGL's Mouse interface, as one example) that allow you to directly poll the mouse position, it sounds like overprogramming in your case. First, keep a private field with a reference to that last mouse position. We'll call it x here.
Use a MouseMotionListener, and have it call the same method from mouseMoved and mouseDragged. That method should look something like this.
void controlMethod(MouseEvent event) {
int newX = event.getXOnScreen();
int dx = this.x - newX;
if(dx > 0) **D Key Event**
else if(dx < 0) ***A Key Event**
x = newX;
}
That should do the job for you. The only thing you might want to look out for is the mouse straying off of the MouseMotionListener's area; but there are always ways around things like that, and it seems a bit tangential.
As a final note, if you end up with wild swings in mouse control at the beginning of your game loop, consider setting the class field x to an Optional, and use Optional.ifPresent(...) for the dx logic. This will also protect you from data nullification, such as from a focus loss, and I recommend making it a practice.
Best of luck!
Related
I'm currently trying to implement a scrollable hexmap with LibGDX. The framework has some nice map apis but they seem to be pretty useless for what I want to do :(
An example of the map view that I would want. The pink rectangle
represents the area actually visible on the screen while everything
around will get cropped
This is a basic rundown of what my map needs to be able to do:
The map needs to be an Actor on the screen that can simply be drawn
on a stage and be disposable. (Already have that)
The map needs to be scrollable. Meaning clicks and drags need to be
registered.
The individual map tiles need to be clickable. When a tile is
clicked, I would like to know what tile it was. (Edit: I can currently register clicks on the actor but I would have to manually calculate what tile was actually clicked. Is there a better way for this?)
Then, the map needs to know what tile is being displayed in the top
left or right position to determine how many tiles to request from
the QuadTree and essentially what to draw on screen.
The map data is stored in a quadtree. In the end there is a method I
will have to call with what tiles I want to draw and the Quadtree
will return the tiledata to me.
And last but not least: Tiles that reach outside the map boundries
should be cropped (less priority)
Now. This is what I currently have:
http://pastebin.com/aqjSNPy3 (THe class is 200 lines long, not gonna spam this in here :) )
I can already draw the map actor on screen. It looks ugly as hell but what the heck. Not important now.
I think the most important thing for now would be to register clicks on tiles, figure out how many tiles to display/ request and maybe do something with the camera to make it scrollable?
I'm really kinda out of answers here. Help will be highly appreciated.
Thanks alot!
Okay i am trying to help. I currently work with a normal OrthogonalTiledMapRenderer and i am sure you could get some good points at the Render class. For exmaple how you check if a tile is visible. Just take a look at the repository of libgdx.
At first. The dispose is never called in any way. You can call it yourself if you really dont need your Screen anymore. You dispose your assets in it if you use it.
So how to get a click detection. You can add Listener to every Actor for example like this:
actor.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("down");
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("up");
}
})
You can add more Listener like this. For example the ActorGestureListener() to detact pinches and so on.
Make sure that you use the cam.unprojectright so the touchevents are fired correct.
resource: libgdx/wiki/scene2d#Inputlistener
Your current method hit has an other functionality:
Hit detection
The Actor hit method receives a point and returns the deepest actor at
that point, or null if no actor was hit. Here is the default hit
method:
public Actor hit (float x, float y, boolean touchable) {
if (touchable && getTouchable() != Touchable.enabled) return null;
return x >= 0 && x < width && y >= 0 && y < height ? this : null; }
The coordinates are given in the actor's coordinate system. This
simply returns the actor if the point is inside the actor's bounds.
More sophisticated checks could be used, eg if the actor was round.
The touchable boolean parameter indicates if the actor's touchability
should be respected. This enables hit detection for purposes other
than touch on actors that are not touchable.
When hit is called on the stage, hit is called on the stage's root
group, which in turn calls hit on each child. The first non-null actor
found is returned as the actor deepest in the hierarchy that contains
the given point.
Hit detaction
You do not need to override this. Its for a stage togive a touch to the Actors if i get that right.
So how do get it scrollAble? You need to detect slide events(as shown above). If there is such event you need to move your camera around or you move your stage/tilemap (by the value of the movement maybe even while the slide is detected). Both has the same effect. At a Pinch you could change the zoom of the camera by the pinch value for example. I do move my camera in every render cycle so always centers my Character:
this.gameCam.position.x = this.character.getX()
+ this.character.sprite.getWidth() / 2;
this.gameCam.position.y = this.character.getY()
+ this.character.sprite.getHeight() / 2;
Also take a closer look to this repository! It's a working Hexmap from a game:
Hexmap refares to this game:
Mathematiles and found at Libgdx Post
I hope this helps a bit! Maybe start with an regulare Tilemap System befor you start with hexagon. It seems to be a bit harder. But there are alot of tutorials that explain the theorie and how to start creating such system. Even for libgdx.
Generally i would say you should wait with that project till they give us the Hextile API. They are working on it but it does take some time i am sure.
Regards
I am at a total loss right now. I haven't worked much with building GUIs in Java, I've been reading all about swing and JPanel, and I think what I am trying to do is possible, I just haven't figured out how.
I'm trying to build a GUI in which you can draw straight lines within a certain drawing area, I would like to be able to get the start/endpoint coordinates in order to perform some math with those points. Any help would be greatly appreciated!
I will leave the code to you so here is the algorithm:
1. Create a JFrame and add a JPanel to it.
2. Add a mouse listener for the JPanel
3. Every time the mouse is pressed, get the x and y of the click. (starting points)
4. When the mouse is dragged , record x and y continuously.
5. When mouse is released, record the x and y. (ending points)
6. You could either use the drawLine() method of Graphics class or use draw() of Graphics2D in this case you will need a Line2D.Double -- the arguments remain the same - start x, start y, end x and end y
here is an image to explain a lil bit better:
Start with Performing Custom Painting and 2D Graphics.
Basically, you going to need a mouse listener to monitor the user interaction with your panel, check out How to write mouse listeners for more infor still.
Depending on your needs, if you need to maintain all the click points of the user, you would need to store them in something like a List, or if you just need to know the start and end points, the you just need a couple of Point objects.
You would be able to use these to paint onto your surface and performing your required calculations.
Remember, in this context, the points are contextual to the container they were generated on. That is 0x0 will be the top left of the container
Updated
You could also take advantage of the Shape API, using a Line2D to represent the two points. This would make it easier to distinguish between distinct lines/points
This is harder than just "draw straight lines with (x1,y1) and (x2, y2)" approach.
You need a Line(your custom) object that is dynamically created and placed on the JPanel which is listening for MouseEvents The canvas area being the JPanel itself. You also need to separate the MODEL from the VIEW so that your custom canvas JPanel will draw itself properly with an override for paintComponent()
The question is slightly vague, so I can't provide any code.
you need to add the mouse listener on JPanel.
then:
public void mouseClicked(MouseEvent me){
if(click==1){
int x1=me.getX();
int y1=me.getY();
click=click+1;
}
else{
int x2=me.getX();
int y2=me.getY();
click=1;
}
}
drawLine(x1,y1,x2,y2)
To draw line with mouse move you can also add mouse motion listener.
I am developing a small Game in Java, and I'm rewriting the Player Movement system to not be Grid-Based. It is a 2D side-scroller, and what I'm trying to achieve is basic Player Movement, so that when the user presses, and holds, the right Key the Player moves right, and the same for the Left Key. The problem I am having is that the Paint Component in another Class draws the image of the Player on the screen, with positions X and Y stored in a Settings Class. Then a KeyListener Class gets when the user is pressing Right, and adds to the X value (And the same for Left, but minuses 1 every time). This creates a slowly moving Character on the screen, and what I want to do is have him move faster without adding more than 1px each time as it would seem like he was skipping pixels (I've already tried).
I was wondering if there was a better way to go about this, as the code I'm using is bare-minimum, and my outcome would be a smoothly moving Player.
KeyListener Snippet:
public void keyPressed(KeyEvent arg0) {
int key = arg0.getKeyCode();
if(key == 39) { // Right Key
Settings.player_pos_x++;
}else if(key == 37) { // Left Key
Settings.player_pos_x--;
}
main.Game.redo();
}
Drawing User on-screen:
g.drawImage(player_image, Settings.player_pos_x, Settings.player_pos_y, this);
Any help is appreciated, if you need any more information or code please feel free to ask.
Let's try again :)
Double buffering
Quote: http://msdn.microsoft.com/en-us/library/b367a457.aspx
Flicker is a common problem when programming graphics. Graphics operations that require
multiple complex painting operations can cause the rendered images to appear to flicker
or have an otherwise unacceptable appearance.
When double buffering is enabled, all paint operations are first rendered to a memory
buffer instead of the drawing surface on the screen. After all paint operations are
completed, the memory buffer is copied directly to the drawing surface associated with
it. Because only one graphics operation is performed on the screen, the image
flickering associated with complex painting operations is eliminated.
Quote: http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html
Suppose you had to draw an entire picture on the screen, pixel by pixel or line by
line. If you were to draw such a thing directly to the screen (using, say,
Graphics.drawLine), you would probably notice with much disappointment that it takes
a bit of time. You will probably even notice visible artifacts of how your picture is
drawn. Rather than watching things being drawn in this fashion and at this pace, most
programmers use a technique called double-buffering.
Perhaps you could write the app to iterate multiple redraws to the right, each only 1 or 2 pixels per keyboard input received. This way, you're kind of artificially setting how fast you want it to move. Otherwise, you'd be limited to how the user has their keyboard iteration speed set up.
Also, java's jPanel is not exactly the place to look for video game efficiency. Just saying; you might want to look to something like openGL for that.
At best, you could optimize it to have a transition buffer outside of the jpanel drawing logic, with the same draw functionality as a jPanel, this way you write to the buffer, then copy the whole buffer during a writeImage call... I don't know if you're already doing that, but I think it avoids flicker or something... read about it a long time ago, it's called double buffering.
While double buffering will probably help you should first address how you are calculating the distance you move each time.
Change in distance (dx) can be defined as the velocity(v) times the change in time(dt), dx = v * dt. From what I can see you are omitting dt (change in time). You should calculate the time difference from the last time the character was moved and multiply that by your velocity. This way if your distance processing code is executed 10 time or 100 times in 10 seconds the character will always move the same distance.
The code will look something like this:
int currentTime = System.nanoTime();
int deltaTime = currentTime - previousTime;
Settings.player_pos_x += velX * deltaTime;
previousTime = currentTime;
With this code you will probably need to significantly increase velX. Typically I would have a constant that I would multiply by the velocity so they are smaller numbers.
Additionally if you want better movement and physics look into JBox2D although it's probably over kill for you right now. Their documentation might also help to understand basic physics.
In order to answer your question about the speed, most games i've seen store a global int for the velocity in each plane (x and y planes), then apply the velocity to the current position rather than simply incrementing it as you have done above.
public int velX = 2;
public int velY = 2;
public void keyPressed(KeyEvent arg0) {
int key = arg0.getKeyCode();
if(key == 39) { // Right Key
Settings.player_pos_x += velX;
}else if(key == 37) { // Left Key
Settings.player_pos_x -= velX;
}
main.Game.redo();
}
Once you have that set up, try adding operations which may increase the velocity (i.e. holding the key down for a long time, or something else);
Also, try to implement a jump operation, where the players Y position goes up, and try to add a gravity field to make it come back down.
I want to have a game where the view will move around as the mouse reaches the outer edge of the window (similar to many RTS games). I have read that there is significant overhead when using the MouseMotionListener.
Is there perhaps a way of having a second transparent component within the game window (JPanel) that does not affect game-play, but will register when the mouse leaves the inner component via MouseAdapter.mouseEntered()/mouseExited()?
boolean mouseOnScreen;
boolean mouseWithinInnerComponent; //is (10 <= mouse.x <= screenWidth - 10) && (10 <= mouse.y <= screenHeight)
if(mouseOnScreen && !mouseWithinInnerComponent)
{
//do something...
}
I am at a loss for how to determine which screen boundary was crossed without having to have four of the above mentioned components overlapping at the corners to form a border around the screen which can detect if the mouse is at any edge or corner. This I imagine to be fairly expensive (having to check each component while running the game)...
boolean mouseOnScreen;
boolean mouseWithinTopComponent; //is (0 <= mouse.y <= 10)
boolean mouseWithinBottomComponent; //is (screenHeight - 10 <= mouse.y <= screenHeight)
boolean mouseWithinLeftComponent; //is (0 <= mouse.x <= 10)
boolean mouseWithinRightComponent; //is (screenWidth - 10 <= mouse.x <= screenWidth)
if(mouseOnScreen)
{
if(!mouseWithinBottomComponent)
{
//move view up
}
if(!mouseWithinTopComponent)
{
//move view down
}
if(!mouseWithinLeftComponent)
{
//move view right
}
if(!mouseWithinRightComponent)
{
//move view left
}
}
Exactly how much overhead exists with MouseMotionListener? Would this or a similar method perhaps be more efficient if the detections only need to be made along the borders of a game window?
NOTE: This will be used in windowed mode as well as possible full-screen application.
I have implemented the same thing you need using a MouseMotionListener. I'm not really sure why you think it will add overhead... If you add one and simply ask each of its methods to print to the console (which is slow) and move your mouse around, you will see it is pretty snappy from the user's point of view.
My implementation consists of 4 main pieces: a scroll pane, rectangular regions, a timer, and a MouseMotionListener.
First, I created a panel, called AutoScrollPane, that extends JScollPane. Even though it is a JScrollPane, you can hide the scrollbars. This allows me to leverage functionality for moving a viewport around on a map or similar like in an RTS game as you say.
Second, for the scroll regions, I actually have 8: n, ne, e, se, s, sw, w and nw (i.e. "north", north-east", etc.), with the diagonals allowing diagonal scrolling. I implement them simply as Rectangles. They aren't drawn on the screen or anything - I just instantiate 8 rectangles in my class sized appropriately and with coordinates that match the regions of the window. I actually allow my window to be resized, so I resize the rectangles if necessary.
Third, I have a timer that can be turned on and off. When it is turned on, every "tick" generates a Runnable. This Runnable's job is to scroll the panel's viewport in the appropriate direction a certain distance. Each Runnable is handed to the Swing event queue.
Finally, I have a MouseMotionListener. It's job is to intercept mouse enter, exit, and move events. Each time it receives an event, it checks the current mouse location and whether it intersects one of the rectangles. Based on which rectangle, it chooses a direction to scroll. It keeps track of whether the mouse was in a scroll region on the previous event or not. Based on this information it knows whether it should start scrolling, stop scrolling, or just let whatever is happening continue. I wanted my scrolling to stop if the mouse goes outside the pane, thus the use of the exit/enter events. Anyway, to start scrolling, the listener saves off the direction and distance to scroll and tells the timer to start. When it is time to stop scrolling (such as when the mouse exits a scroll region), it tells the timer to stop.
It took a while to pick the right timer granularity and scroll distance for smooth scrolling, but it does work pretty well. I hope this outline provides some help.
I think it was Martin Fowler that espoused that premature optimisation is the root of all evil in software development. Why not try the MouseMotionListener and only think about optimising if you find that it affects the performance of the game.
There is nothing wrong with a MouseMotionListener When you read about the overhead it was probably one specific exmaple
Anything you can do in any programming language can be done bad or wrong.
If you pay attention to what you do in your listener all should be fine
I'm working on a Java Bomberman clone, using a grid system, and I'm not really satisfied with the movement right now. When the player presses a movement key, the character starts to move (with 0.25 speed). The player loses the control, and the character keeps moving until it has moved a full tile. The player only regains control when the character gets to the center of the next tile.
This makes it's too "laggy". If I want to change direction now, I can't.
Maybe I could make the base of the character smaller than the size of the sprite, meaning I would have to check ahead of the corners to check if it was a valid move. Any thoughts?
Thanks!
I just played Bomberman a few minutes ago :)
You can move pretty smooth, there no grid calculations.
I haven't used Java that much. I use Flash a lot. Is the Grid for checking collisions ?
What is it for exactly ?
Would it make sense to have something like(I'll try to sketch it):
float vx,vy = 0;//velocity on x and y
Character bomberman
void keyDownHandler(KeyboardEventSomething event){
if(key is Left && ! Right ) vx -= .5;
else if(key is Right && !Left ) vx += .5;
//idem for Y axis
}
void keyUpHandler(KeyboardEventSomething event){
vx = vy = 0;
}
void updateLoop(){
bomberman.x += vx;
bomberman.y += vy;
}
I might be a bit off, because I'm not sure how much you want to clone Bomberman or not. What you're describing with the grid movement seems closer to hopmon
Don't disable user input. Ever. Constantly poll for it.
Have a Tick() or OnFrameEnter() function that does the following:
Poll the keyboard/joystick/whatever, and cache the last direction entered by the user.
Check the position of the character.
If the character is idle in the center of a grid square, set it's velocity in the proper direction and upate the movement one step, unless there's a wall/collision object in the way. Also clear out the last key press to some invalid value.
Else if the character is already moving, update the position of the character, checking for collision with a wall, or proximity to a direction changing node (intersection). If it collides with a wall, stop the character. If it's close to a direction changing node and can travel in the cached direction, change the direction and clear the cached direction. Else if the input direction is opposite the current direction (it's in a hallway and the player wants to reverse), reverse the direction and then clear the key press. This all assumes that the character should continue moving, always, until it hits a wall and stops. If you want the character to stop anywhere, a reverse direction key should simply stop it in place.
Caching the key press allows the player to preemptively change directions as the character approaches an intersection. This way the character doesn't have to wait to stop before moving on, and the player doesn't feel the game is unresponsive. Polling constantly lets the player reverse directions at any time, and makes direction changes at intersections seem faster.
You should be able to get rid of current sprite and load the new one exactly when you need it - i.e. if the character moved half way to the next tile and the player presses a key to return, cancel the sprite and load the new one starting at 0.5.
I guess it depends on how you want it to behave.
Say you are moving up, and you click right.. do you want it to stop moving up and go right?
I would store the previous grid location when you make a movement. that way if you click to move elsewhere you can hop backwards and change the movement direction..
Or if you are moving up and you click down... you could set the movement speed to be the opposite of what it is...
It is hard to answer with out knowing what you want it to behave like.
It sounds like you update the players position (start of the animation) by changing the grid cell in which its contained.
To be able to achieve the desired effect, the sprites render position should be independent of where the entity represented by that sprite is located on the grid. And allow the user to move inside that grid within a range of the cell's center without changing cells. If this range is not chosen correctly you may en up with the "doh! im in this (visually) cell but it says im in the future cell" problem, or the "my avatar is overlapping a wall".
Dont change the players cell until he is within a range (lets say 1/3 of the bounding sphere of the sprite) from the limits/borders of the cell that contains him. You would also have to modify the animation process for it to be interruptible.
This is independent of the degrees of liberty you give the player (like, it could only move up, down, left, right, and diagonals vs 360 degrees)
Another thing you should watch out for is, if the sprite is larger than the cell size. For instance, a Fat monster, or a Snake boss which spans across X cells but not necessarily in rectangular form.